Pandas 기초 활용 - 2

haejun-kim·2020년 12월 31일
1

데이터 그룹 만들기

pandas의 group by를 알아보자.

group by의 실습을 위해 임의의 데이터프레임을 생성한다.

student_list = [
	{'name' : 'John', 'major' : 'Computer Science', 'sex' : 'male'},
	{'name' : 'Nate', 'major' : 'Computer Science', 'sex' : 'male'},
	{'name' : 'Abraham', 'major' : 'Physics', 'sex' : 'male'},
	{'name' : 'Brian', 'major' : 'Psychology', 'sex' : 'male'},
	{'name' : 'Jenny', 'major' : 'Economics', 'sex' : 'female'},
	{'name' : 'Yuna', 'major' : 'Economics', 'sex' : 'female'},
	{'name' : 'Jeniffer', 'major' : 'Computer Science', 'sex' : 'female'},
	{'name' : 'Edward', 'major' : 'Computer Science', 'sex' : 'male'},
	{'name' : 'Zara', 'major' : 'Psychology', 'sex' : 'female'},
	{'name' : 'Wendy', 'major' : 'Economics', 'sex' : 'female'},
	{'name' : 'Sera', 'major' : 'Psychology', 'sex' : 'female'},
]

df = pd.DataFrame(student_list, columns = ['name', 'major', 'sex'])

몇가지 상황을 가정하여 그룹을 지어 실습을 진행해보자.

  • 각 학과별로 몇명의 인원이 있는지 알고싶다면?
groupby_major = df.groupby('major')

위와 같이 학과를 기준으로 그룹을 만들어준다. 그룹을 만들어주었으면 내용을 확인해본다.

groupby_major.groups

각 학과별로 몇개의 데이터가 있는지 List에 담겨져서 확인이 된다. 하지만 무언가 한눈에 확 들어오는 형태는 아니다. 조금 더 시각화를 해보자.

for name, group in groupby_major:
	print(name + ' : ' + str(len(group))
	print(group)
	print()

실행 해 보면 훨씬 한눈에 잘 들어오는 형태의 출력을 확인할 수 있다. 이런식으로 데이터를 핸들링할 수 있다.

  • 이제 이 정보를 학과별로 몇 명 있는지 데이터프레임으로 만들고싶다면?
df_major_cnt = pd.DataFrame({'count' : groupby_major.size()})

상단에서 groupby 지어 준 groupby_major의 size를 구해서 데이터프레임으로 만들어주었다.

근데 위와 같이 출력하니 무언가 column이 안이쁘게 출력된다. count column을 major의 수평에 놓고 싶다.

df_major_cnt = pd.DataFrame({'count' : groupby_major.size()}).reset_index()

reset_index()를 사용함으로써 column을 제 위치에 갖다놓을 수 있다.

  • 이번에는 전공이 아닌 성별로 그룹화를 진행 해 보자.
groupby_sex = df.groupby('sex')

for name, group in groupby_sex:
	print(name + ' : ' + str(len(group)))
	print(group)
	print()

중복 데이터 삭제하기

이번에는 중복 된 행을 제거할 수 있는지를 알아보자.

student_list = [
	{'name' : 'John', 'major' : 'Computer Science', 'sex' : 'male'},
	{'name' : 'Nate', 'major' : 'Computer Science', 'sex' : 'male'},
	{'name' : 'Edward', 'major' : 'Computer Science', 'sex' : 'male'},
	{'name' : 'Zara', 'major' : 'Psycology', 'sex' : 'female'},
	{'name' : 'John', 'major' : 'Computer Science', 'sex' : 'male'},
]

df = pd.DataFrame(student_list, columns = ['name', 'major', 'sex'])

실습을 위해 임의로 데이터프레임을 생성하였다. 위의 데이터프레임은 0번과 4번의 인덱스를 가진 row가 같은 데이터를 가지고 있다는 것을 알 수 있다. 이를 제거 할 수 있는 방법을 알아보자.

위와 같이 소량의 데이터라면 눈으로 중복되는 데이터가 있는지 확인 할 수 있지만, 데이터가 무수히 많은 경우에는 눈으로 하나하나 중복이 있는지 확인하는것은 굉장히 힘들며 비효율적이다. 다행히도 판다스에서는 중복된 데이터가 있는지 체크 해 주는 함수가 있다.

df.duplicated()

위의 duplicated()함수를 사용 할 경우 Boolean 값이 리턴된다. False : 중복된 데이터가 없음.

True : 중복된 데이터인 row

이를 이용하여 조금 더 손 쉽게 중복을 확인할 수 있다.

이제 중복된 데이터를 삭제 해 보자.

df.drop_duplicates()

위의 명령어를 실행시켜보면 중복 되던 4번 인덱스의 row가 삭제 된 것을 확인 할 수 있다.

다른 예제도 살펴보자. 실제 데이터 분석을 하는 경우에는 열에 있는 값을 사용해서 중복 된 값을 알아내고, 그 중복 된 값을 제거하는 경우로 많이 사용된다. 이 방법을 알아보도록 하자. 새로운 예제를 위해 하나의 다음의 데이터 프레임을 생성한다. 다음의 데이터프레임은 John과 Nate의 이름은 중복되지만 전공이나 성별은 중복되지 않는다.

student_list = [
	{'name' : 'John', 'major' : 'Computer Science', 'sex' : 'male'},
	{'name' : 'Nate', 'major' : 'Computer Science', 'sex' : 'male'},
	{'name' : 'Edward', 'major' : 'Computer Science', 'sex' : 'male'},
	{'name' : 'Zara', 'major' : 'Psycology', 'sex' : 'female'},
	{'name' : 'Wendy', 'major' : 'Economics', 'sex' : 'female'},
	{'name' : 'Nate', 'major' : 'None', 'sex' : 'male'},
	{'name' : 'John', 'major' : 'Economics', 'sex' : 'male'},
]

df = pd.DataFrame(student_list, columns = ['name', 'major', 'sex'])

먼저 위의 데이터프레임에서 중복되는 값이 있는지를 배운 방법을 통해 확인 해 보자.

df.duplicated()

이번에는 모든 결과값이 False로 리턴되었다. 왜냐하면 정확하게 일치하는 행이 없기 때문이다. 하지만 이름이 같은 value들은 보인다. 이럴 경우에는 인자로 넣어준다.

df.duplicated(['name'])

이는 pandas에게 내가 찾고자 하는 중복은 name column에서 같은 값이 있을 경우를 중복이라 정의하고 찾고 싶어. 라는 뜻이다.

위와 같이 column을 지정해주면 row 5,6 에서 True 값을 리턴하는 것을 확인할 수 있다. 이는 이름이 같은 값을 발견했다는 뜻이다. 이제 이름이 같은 행을 모두 지워보자.

df.drop_duplicates(['name'], keep = 'first')

keep 이라는 파라미터에 first 라고 옵션을 부여하였다. 위와 같이 실행하면 가장 처음에 존재하는 JohnNate는 남고 그 다음으로 출력되는 중복되는 값은 삭제가 된다.

만약 뒤에 있는 값을 유지하고 싶다면 first가 아닌 last라고 옵션을 주면 된다.

만약 keep 값을 주지 않으면? default로 first 값이 입력되어 처음 값이 남는다.

NaN 찾아서 다른 값으로 변경하기

실제 데이터를 핸들링 하는 과정에서는 비어 있는 Nan 값을 핸들링해야하는 경우가 필수적으로 존재한다. 따라서 Nan값을 내가 원하는 다른 값으로 변경하는 방법을 알아보자.

school_id_list = [
	{'name' : 'John', 'job' : 'teacher', 'age': 40},
	{'name' : 'Nate', 'job' : 'teacher', 'age': 35},
	{'name' : 'Yuna', 'job' : 'teacher', 'age': 37},
	{'name' : 'Abraham', 'job' : 'student', 'age': 10},
	{'name' : 'Brian', 'job' : 'student', 'age': 12},
	{'name' : 'Janny', 'job' : 'student', 'age': 11},
	{'name' : 'Nate', 'job' : 'teacher', 'age': None},
	{'name' : 'John', 'job' : 'student', 'age': None},
]

df = pd.DataFrame(school_id_list, columns = ['name', 'job', 'age'])

NaN Value 유무 확인

생성 된 데이터프레임을 출력 해 보면 6, 7 row의 age 값이 NaN으로 표시된다. 데이터프레임을 생성할 때 None 값으로 생성하였기 때문이다. 중복과 마찬가지로 소량의 데이터는 눈으로 확인할 수 있지만, 많은 데이터를 눈으로 확인하긴 번거롭기 때문에 우리는 간단하게 함수로 NaN값이 있는지를 찾도록 하자.

df.info()

위의 명령어는 데이터프레임에 대한 정보를 리턴 해 준다. name, job column은 8개의 non-null의 object가 있다고 출력된다. 하지만 age의 경우 6개의 non-null 값의 object가 있다고 출력된다. 따라서 age에서는 2개의 NaN값이 존재한다고 판단 할 수 있다.

다른 방법도 있다.

df.isna()

위의 isna() 함수는 데이터프레임에 NaN값이 있는지 없는지를 Boolean 값으로 리턴 해 준다. 조금 더 한눈에 확인이 가능하다.

같은 기능을 하지만 이름이 다른 함수도 있다.

df.isnull()

출력 결과가 같은 것을 확인 할 수 있다.

다른 값으로 변경

이제 NaN 값을 확인했으니 다른 값으로 변경 해 보자.

  • NaN → 0으로 변경
df.age = df.age.fillna(0)

df라는 데이터프레임의 age column에서 NaN 값을 발견하면 0으로 바꿔줘 라는 명령이다.

하지만 위의 예제에서 선생님 또는 학생. 즉, 사람의 나이가 0살인 것은 말이 되지 않는다. 데이터 엔지니어링을 할 때, NaN 값을 변경 할 때 뭔가 그럴싸한 값으로 변경 해 줘야 한다는 것을 잊지 말도록 하자.

따라서 조금 더 변경 해 보도록 하자.

  • median 값으로 변경

위 실습을 하기 전 데이터프레임이 변경됐으니 다시 불러오고 진행하시길 바란다.

df['age'].fillna(df.groupby('job')['age'].transform('median'), inplace = True)

위는 데이터프레임에서 age 를 변경시켜라. 그리고 선생님과 학생을 구분을 짓기 위해 job 으로 그룹을 짓고 그 중 나는 age 값만 관심이 있어. 그리고 이 age 값에서 median 값을 받아서 이 값으로 NaN 값을 변경 해 주고, 이를 데이터프레임에 바로 반영시켜줘.

라는 뜻의 명령문이 된다.

apply 함수 활용

기초 사용법

이번에는 pandas의 apply function을 조금 더 심층적으로 다뤄보자.

date_list = [
	{'yyyy-mm-dd' : '2000-06-27'},
	{'yyyy-mm-dd' : '2002-09-24'},
	{'yyyy-mm-dd' : '2005-12-20'}
]

df = pd.DataFrame(date_list, columns = ['yyyy-mm-dd'])

현재는 column이 하나밖에 없다. 이를 apply 함수를 통해서 column을 추가 해 보도록 하자.

나는 year 라는 column을 만들것이고, 그 column에 들어가는 value 로는 yyyy-mm-dd column의 yyyy 값만 가지고 올 예정이다.

apply 함수를 적용 하기 전에 yyyy 값을 추출하는 함수를 하나 작성한다.

def extract_year(column):
	return column.split('-')[0]

이제 apply 함수를 적용시켜보자.

df['year'] = df['yyyy-mm-dd'].apply(extract_year)

이것이 apply 함수의 기초적인 사용 방법이다.

파라미터 전달

apply 함수를 조금 더 다뤄보자. 이번에는 apply에 파라미터를 전달 시킬 수 있는 방법을 알아 볼 것이다.

age라는 column을 추가 할 것이고, 이 column의 값은 올해년도에서 year의 값을 뺀 값을 추가 해 보자.

def get_age(year, current_year):
	return current_year - int(year)

df['age'] = df['year'].apply(get_age, current_year = 2018)

위와 같이 키워드를 통해서 파라미터를 전달 시킬 수 있다.

여러개의 파라미터 전달

여러개의 파라미터도 전달 할 수 있을까? 가능하다.

이번에는 introduce 라는 자기소개 column을 만들어보자.

def get_introduce(age, prefix, suffix):
	return prefix + str(age) + suffix

df['introduce'] = df['age'].apply(get_introduce, prefix = 'I am', suffix = 'years old')

여러개의 column에 apply 적용하기

def get_introduce_2(row):
	return 'I was born in ' + str(row.year) + 'my age is ' + str(row.age)

row.yearrow.age 로 column 두 개가 들어 간 것을 볼 수 있다.

이 함수를 활용 해 보자.

df.introduce = df.apply(get_introduce_2, axis = 1)

axis로 축을 column으로 설정 해 주면 된다.

이는

df['introduce'] = df.apply(get_introduce_2, axis = 1)

와 같다.

map, applymap 함수 활용

이번에는 map 함수와 applymap 함수를 배워보자.

date_list = [
	{'date' : '2000-06-27'},
	{'date' : '2002-09-24'},
	{'date' : '2005-12-20'}
]

df = pd.DataFrame(date_list, columns = ['date'])

map

def extract_year(date):
	return date.split('-')[0]

df['year'] = df['date'].map(extract_year)

위의 코드는 년도를 추출하여 그 값을 year 라는 column을 생성하여 채워주는 코드이다. map 의 사용이 apply의 사용과 완전히 같다.

하지만 map()은 다른 방법으로도 활용이 가능하다.

job_list = [
	{'age' : 20, 'job' : 'student'},
	{'age' : 30, 'job' : 'developer'},
	{'age' : 30, 'job' : 'teacher'},
]

df = pd.DataFrame(job_list)

위의 데이터프레임은 job 이라는 column에 student, developer , teacher 라는 값들이 있다. 데이터를 다루다 보면 텍스트를 숫자로 바꿔야 하는 경우가 생긴다. 이럴 경우 map을 사용할 수 있다.

df.job = df.job.map({'student' : 1, 'developer' : 2, 'teacher' : 3})

위와 같이 map을 사용하면

  1. column을 변경 시킬 수 있다.
  2. Dictionary 를 직접 전달함으로써 원하는 값으로 변경이 가능하다.

applymap

applymap은 언제 사용할까?

하나의 column이 아닌 모든 column에 적용을 하고 싶다면 applymap을 사용하면 된다.

x_y = [
	{'x' : 5.5, 'y' : -5.6, 'z' : -1.1},
	{'x' : -5.2, 'y' : 5.5, 'z' : -2.2},
	{'x' : -1.6, 'y' : -4.5, 'z' : -3.3}
]

df = pd.DataFrame(x_y)

위의 데이터프레임 전체를 applymap을 사용해서 바꿔보도록 하자.

import numpy as np

df = df.applymap(np.around)

모든 값을 applymap을 사용하여 반올림시켜주었다.

컬럼 내 유니크한 값 뽑아내고 갯수 확인하기

데이터프레임에서 어떤 유니크한 값이 있는지, 그리고 그 값을 뽑아내는 방법에 대해서 알아보자.

job_list = [
	{'name' : 'John', 'job' : 'teacher'},
	{'name' : 'Nate', 'job' : 'teacher'},
	{'name' : 'Fred', 'job' : 'teacher'},
	{'name' : 'Abraham', 'job' : 'student'},
	{'name' : 'Brian', 'job' : 'student'},
	{'name' : 'Janny', 'job' : 'developer'},
	{'name' : 'Nate', 'job' : 'teacher'},
	{'name' : 'Ian', 'job' : 'teacher'},
	{'name' : 'Chris', 'job' : 'banker'},
	{'name' : 'Philip', 'job' : 'lawyer'},
	{'name' : 'Janny', 'job' : 'basketball player'},
	{'name' : 'Gwen', 'job' : 'teacher'},
	{'name' : 'Jessy', 'job' : 'student'},
]

pd = DataFrame(job_list, columns = ['name', 'job'])

이제 유니크한 값을 뽑아보자.

df.job.unique()

이제 중복되는 값이 있더라고 한 들 하나의 값만 나오고, class에 있는 하나의 값만 나오기 때문에 모든 값들을 확인할 수 있다.

각 직업별로 몇개의 데이터가 있는지 확인하고 싶다면 다음과 같이 하면 된다.

df.job.value_counts()

각 직업에 대해 몇개의 데이터가 존재하는지 보여준다. 굉장히 자주 사용되는 함수이니 꼭 기억하도록 하자.

두개의 데이터프레임 합치기

Pandas에서 두 개의 데이터프레임이 있을 때, 그 두 개의 데이터프레임을 합치는 방법을 알아보자.

l1 = [
	{'name' : 'John', 'job' : 'teacher'},
	{'name' : 'Nate', 'job' : 'student'},
	{'name' : 'Fred', 'job' : 'developer'}
]

l2 = [
	{'name' : 'Ed', 'job' : 'dentist'},
	{'name' : 'Jack', 'job' : 'farmer'},
	{'name' : 'Ted', 'job' : 'designer'}
]

l3 = [
	{'name' : 'John', 'job' : 'teacher'},
	{'name' : 'Nate', 'job' : 'student'},
	{'name' : 'Jack', 'job' : 'developer'}
]

l4 = [
	{'age' : 25, 'country' : 'U.S'},
	{'age' : 30, 'country' : 'U.K'},
	{'age' : 45, 'country' : 'Korea'}
]

df1 = pd.DataFrame(l1, columns = ['name', 'job'])
df2 = pd.DataFrame(l2, columns = ['name', 'job'])

위 두개의 데이터프레임을 합쳐보자.

행 기준

df1과 df2는 column name이 같기 때문에 row를 기준으로 합쳐보도록 한다.

방법은 두가지가 존재한다.

  • pd.concat() 사용
result = pd.concat([df1, df2])

두 개의 데이터프레임이 정상적으로 row를 기준으로 합쳐졌다. 하지만 row index가 0,1,2,0,1,2 로 출력되어 보기 불편하다. 이럴 경우 하나의 파라미터만 추가해서 적어주면 된다.

result = pd.concat([df1, df2], ignore_index = True)

두번째 방법을 알아보자.

  • df.append()
result = df1.append(df2, ignore_index = True)

성공적으로 두 개의 데이터프레임을 합쳤다.

열 기준

이번에는 열을 기준으로 합치는 방법에 대해 알아보자.

df1 = pd.DataFrame(l3, columns = ['name', 'job'])
df2 = pd.DataFrame(l4, columns = ['age', 'country'])

l1l2 는 column name이 다르기 때문에 행을 기준으로 합칠 수 없다. 따라서 열을 기준으로 합쳐보도록 하자.

같은 인덱스가 있는 녀석들을 같은 행으로 붙여볼 것이다. 이럴 경우에는 행을 합칠 때와 같은 방법으로 pd.concat()을 사용하는 방법도 있다.

  • pd.concat()
result = pd.concat([df1, df2], axis = 1, ignore_index = True)

사용하는 방법은 같지만 열을 기준으로 합칠 것이라는 축에 대한 명시만 추가 해 주면 된다.

데이터프레임이 아닌 리스트를 합치는 방법도 알아보자.

이는 ML이나 DS같은 경우 예측값과 실제값을 비교해야하는 경우가 많은데 이럴 경우에 많이 사용된다.

label = [1, 2, 3, 4, 5]
prediction = [1, 2, 2, 4, 4]

리스트 형식으로 보면 어떤 value가 정확히 예측되는지 분간하기 힘들 때가 있다. 이럴 경우 데이터프레임 형식으로 만들어보면 조금 더 분간하기 수월해진다.

comparison = pd.DataFrame({'label' : label, 'prediction' : prediction})

간단히 Dict 형태로 일치시켜주면 된다.

출력값을 보면 3이 2로 잘못 출력되었고, 5가 4로 잘못 출력되었구나 라는 것을 조금 더 쉽게 확인이 가능하다.

1개의 댓글

comment-user-thumbnail
2021년 1월 1일

와우

답글 달기