220921 Day19

유예지·2022년 9월 21일

4. 데이터 가공하기

(1) 조건에 맞는 데이터만 추출하기 (검색) : df.query()

>>> import pandas as pd
	exam = pd.read_excel("excel_exam.xlsx")
	exam.head()
    
#exam에서 class 가 1인 경우만 추출
>>> exam['class'] == 1    #serise로 출력됨
>>> exam[exam['class'] == 1]    #dataframe으로 출력됨

#math >= 50 인 경우만 출력
>>> exam[exam['math'] >= 50]

* class == 1 이면서 math >= 50

#방법1 (내가 생각한 방법)
>>> class1 = exam[exam['class'] == 1]
>>> class1[class1['math'] >= 50]

#방법2
>>> exam[(exam['class'] == 1) & (exam['math'] >= 50)]

>>> cond1 = exam['class'] == 1
    cond2 = exam['math'] >= 50
    exam[cond1 & cond2]
    
#방법3 : query()를 사용하여 추출
#query('') : 괄호 안의 조건에 대해 검색하여 조건에 맞는 데이터만 추출
>>> exam.query('math >= 50')

>>> exam.query('math >= 50 & english > 90')  #'' 안에 '한 문장'이 들어간다

#df.query()를 이용하여 1반이면서 수학이 50점 이상인 경우 추출
>>> exam.query('class == 1 and math >= 50')
SyntaxError: Python keyword not valid identifier in numexpr query

#칼럼의 이름으로 'class'가 사용되어 에러
>>> exam.rename({'class' : 'nclass'}, axis = 1, inplace = True)
	exam.query('nclass == 1 and math >= 50')
    
>>> exam.query('nclass in [1, 3, 5]')    #1,3,5반 만 출력된다

#변수 in [ ] : for 문과 비슷하다, 변수의 값이 []에 입력한 목록에 해당되는지 확인
(in : '==' 역할)
'''
[1,2,3,4,5] in [1,3,5]
    1 in [1,3,5]
    2 in [1,3,5]
    3 in [1,3,5]
    4 in [1,3,5]
    5 in [1,3,5]
    6 in [1,3,5]
'''

* 문자 변수를 이용해 조건에 맞는 행 추출하기

>>> df = pd.DataFrame({'sex': ['F','M','F','M'],
						'country' : ['Korea', 'China', 'Japan', 'USA']})
	df

>>> df.query('sex == "F" and country == "Korea"')    #따옴표 사용 유의

* 필요한 변수만 추출하기

>>> exam

>>> exam.iloc[ : , [0,2,3]]

>>> exam.iloc[ : , 2: ]

>>> exam.loc[ : , ['math', 'english', 'science']]

>>> exam[:2]    #인덱스 번호 2(0,1,2) -> 2행까지(인덱스 번호 0,1) 출력

#변수 제거하기 : df.drop(columns = '제거할 변수명')
>>> exam.drop(columns = 'math')

>>> exam.drop(['id', 'nclass'], axis = 1)   #여러 변수 제거 -> []

(2) 순서대로 정렬하기

① df.sort_values()
② df.sort_index()

#오름차순 정렬
>>> exam.sort_values(by = 'math')

#내림차순 정렬
>>> exam.sort_values(by = 'math', ascending = False)

>>> exam.sort_values(by = ['math', 'english'], ascending = False)

>>> df = exam.sort_values(['math', 'english'], ascending = False)
	df
    
>>> df.sort_index()    

* 파생변수 추가하기 : df.assign()

#새로운 칼럼 total = math + english + science
#exam['total'] = exam['math'] + exam['english'] + exam['science']
>>> exam.assign(total = exam['math'] + exam['english'] + exam['science'])

(3) 집단별로 요약하기 (그룹)

① df.groupby()

>>> exam.head()
>>> exam.groupby('nclass')
>>> list(exam.groupby('nclass'))   #5개의 그룹(dataframe)으로 나뉜다

>>> exam.groupby('nclass').min()
#exam의 20개 데이터 -> groupby('nclass')로 5개 그룹으로 쪼갬 -> 각각의 그룹에 min() 함수 적용
#'nclass'가 인덱스로 되었다

>>> exam.groupby('nclass').min()['math']    #serise로 출력
>>> exam.groupby('nclass').min()[['math']]  #dataframe으로 출력

>>> exam.groupby('nclass').min()[['math', 'science']]

#다른 표기법
>>> list(exam[['nclass', 'math', 'science']].groupby('nclass'))

>>> exam[['nclass', 'math', 'science']].groupby('nclass').min()

* 집단별로 다시 집단 나누기

groupby() 에 여러 변수를 지정하면 집단을 나눈 다음 다시 하위 집단으로 나눌 수 있다

>>> pip install pydataset
>>> import pydataset

>>> mpg = pydataset.data("mpg")
	mpg

#drv와 class로 그룹을 짓고, 각 그룹별 cty의 min 값 구하기
>>> mpg.groupby(['drv', 'class']).min()[['cty']]    #인덱스가 drv, class 2개

② df.agg() : 집계함수

하나의 함수에만 적용할 때는 groupby와 agg의 결과가 동일하지만, 2개 이상의 함수에 적용할 때는 agg()를 사용해야한다

agg()는 전체를 요약한 값을 구하기 보다는 groupby()에 적용해 집단별 요약값을 구할 때 사용한다

df.groupby()에 변수를 지정하면 변수의 범주별로 데이터를 분리한다
여기에 agg()를 적용하면 집단별 요약 통계량을 구한다

#mpg.groupby(['drv', 'class']).min()
>>> mpg.groupby(['drv', 'class']).agg(min)

>>> mpg.groupby(['drv', 'class']).agg(min)[['cty', 'hwy']]

#agg() 대신에 apply()를 사용할 수도 있다
>>> mpg.groupby(['drv', 'class']).apply(min)

#2개의 함수 적용 -> agg() 사용
>>> mpg.groupby(['drv', 'class']).agg([min, max])
>>> mpg.groupby(['drv', 'class']).agg([min, max])[['cty']]

#칼럼마다 다른 함수 적용
>>> mpg.groupby(['drv', 'class']).agg({'cty' : min, 'hwy' : max})

#집단별 요약 통계량 구하기
>>> mpg.groupby(['drv', 'class']).agg(mean_cty = ('cty', 'mean'))
#groupby로 분리 후 cty 평균값 구하기

#여러 요약 통계량 한번에 구하기
>>> mpg.groupby(['drv', 'class']).agg(mean_cty = ('cty', 'mean'),
									  sum_cty = ('cty', 'sum'))

(4) 데이터 합치기 : merge / join / concat

* 가로로 합치기 : pd.merge()

기존 데이터에 변수(열)를 추가하는 것

>>> test1 = pd.DataFrame({'id' : [1,2,3,4,5], 'midterm' : [60,80,70,90,85]})
	test2 = pd.DataFrame({'id' : [1,2,3,4,5], 'final' : [70,83,65,95,80]})
>>> test1
>>> test2

>>> pd.merge(test1, test2)    #id를 기준으로 합쳐서 할당된다

>>> test1 = pd.DataFrame({'id' : [1,2,3,4,5], 'midterm' : [60,80,70,90,85]})
	test2 = pd.DataFrame({'id' : [1,2,3,6,7], 'final' : [70,83,65,95,80]})
	pd.merge(test1, test2)    #id 값이 같은 데이터만 합쳐져서 나온다
    
>>> pd.merge(test1, test2, how = 'outer')   #'outer' : 합집합의 의미

>>> pd.merge(test1, test2, how = 'left')
>>> pd.merge(test1, test2, how = 'right')
  • pd.merge() 를 응용하면 특정 변수의 값을 기준으로 다른 데이터의 값을 추가할 수 있다
>>> exam

#teacher 변수 추가
>>> teacher = pd.DataFrame({'nclass' : [1,2,3,4,5],
	                       'teacher' : ['choi','park','kim','lee','han']})
>>> teacher

>>> pd.merge(exam, teacher)

#on = '변수명' : 데이터를 합칠 때 기준으로 삼을 변수명
>>> pd.merge(exam, teacher, on = 'nclass')

* 세로로 합치기 : pd.concat()

기존 데이터에 변수(행)를 추가하는 것

>>> pd.concat([test1, test2])
>>> pd.concat([test1, test2], axis = 1)    #옆에 붙었다 
>>> pd.concat([test1, test2], axis = 1, join = 'inner')
#join = 'inner' : inner -> 교집합, '인덱스 번호를 기준으로' 합친다는 의미
  • index 생성 : wet_index() / reset_index() / reindex()
>>> test1 = pd.DataFrame({'id' : [1,2,3,4,5], 'midterm' : [60,80,70,90,85]})
	test2 = pd.DataFrame({'id' : [1,2,3,6,7], 'final' : [70,83,65,95,80]})

#test2에 'i'라는 변수 추가
>>> test2['i'] = [0, 1, 2, 4, 5]

#'i'를 test2의 인덱스 번호로
>>> test2.set_index('i', inplace = True)
>>> test2

>>> pd.concat([test1, test2], axis = 1, join = 'inner')
#test1과 test2의 겹치는 인덱스 번호로만 합쳐진다 (inner -> 교집합)
  • id별로 midterm의 평균
>>> test3 = test2.rename({'final' : 'midterm'}, axis = 1)
	test3

>>> pd.concat([test1, test3])

>>> g = pd.concat([test1, test3])

>>> g.groupby('id').mean()
>>> g.groupby('id').min()

5. 데이터 정제

결측치 : 누락된 값, 비어있는 값
이상치 : 정상 범위에서 크게 벗어난 값
결측치나 이상치가 있으면 함수가 적용되지 않거나 분석 결과가 왜곡될 수 있다

(1) 결측치 정제하기

① 결측치 만들기 : np.nan

>>> import numpy as np
>>> exam

>>> exam.iloc[0,2] = np.nan
>>> exam

>>> exam.iloc[1,3] = np.nan
	exam.iloc[2,4] = np.nan
	exam

② 결측치 확인하기 : pd.isna()

>>> df = exam.copy()
	pd.isna(df)
    
#결측치 빈도 확인 - 데이터에 결측치가 총 몇개 있는지 출력
>>> pd.isna(df).sum()    

③ 결측치 제거하기 : df.dropna()

#모든 변수에 결측치 없는 데이터 추출
>>> df.dropna()
	df

#결측치 있는 행 제거하기 : subset = ['변수명']
>>> df.dropna(subset = 'math')

#pandas에서는 Na 값이 있어도 알아서 그 값을 제외하고 계산해준다
>>> df['math']
>>> df['math'].mean()
>>> np.mean(df.math)
>>> df.apply(np.mean)

④ 결측치 대체하기 - 평균값으로 대체하기 : df.fillna(대체할 값)

결측치를 다른 값으로 대체하면 데이터가 손실되어 분석 결과가 왜곡되는 문제를 보완할 수 있다

>>> m = df['math'].mean()
	m
    
>>> df['math'].fillna(m)
>>> df

>>> df['math'] = df['math'].fillna(m)
	df     #math열에서의 Na 값이 math의 평균값으로 대체되었다

>>> df['english']
>>> df['english'].fillna(method = 'ffill') #ffill -> foward fill
>>> df['english'].fillna(method = 'bfill', inplace = True) #bfill -> back fill
	df
    
>>> s = df['science'].mean()
	df['science'].fillna(s, inplace = True) 
	df    

(2) 이상치 제거하기

결측치 : 누락된 값, 비어있는 값
이상치 : 정상 범위에서 크게 벗어난 값
결측치나 이상치가 있으면 함수가 적용되지 않거나 분석 결과가 왜곡될 수 있다

① 이상치 확인하기 : df.value_counts()

#이상치 만들기
>>> df.iloc[0,2] = 10
	df.iloc[1,3] = 10
	df
    
>>> import seaborn as sns
	sns.boxplot(data = df, x = 'math') 
>>> sns.boxplot(data = df, y = 'math')    

0개의 댓글