자드's

[ Pandas ] Python의 pandas 라이브러리를 이용한 데이터분석의 기초 ( Series, DataFrame ) - (2) : 구조와 기능 본문

프로그래밍/PANDAS

[ Pandas ] Python의 pandas 라이브러리를 이용한 데이터분석의 기초 ( Series, DataFrame ) - (2) : 구조와 기능

최자드 2022. 11. 7. 00:56
728x90

Pandas의 기능들

 

이번 글은 Pandas의 기능들에 대해서 몇가지 알아보려고 한다

먼저 Series와 DataFrame의 재구조 및 기술적 통계와 관련된 함수
DataFrame의 범주화 및 병합을 알아보자

 

Series 와 DataFrame의 재구조

 

Series의 재색인, 재배치

 

index를 재배치 하면 그에 맞는 value도 재배치가 된다

reindex( )를 하면서 index의 갯수를 늘려주면 value에는 NaN이 채워진다

import pandas as pd
import numpy as np

# Series의 재 색인
data = pd.Series([1,3,2], index=(1,4,2)) # index는 list, tuple, set 가능

# reindex()로 순서를 재 배치
data2 = data.reindex((1,2,4)) # 각 index에 맞는 value도 재배치가 된다

data3 = data2.reindex([0,1,2,3,4,5]) # 대응값이 없는 인덱스에는 NaN이 됨

# NaN(결측값) 채우기

data3 = data2.reindex([0,1,2,3,4,5], method='ffill') # NaN의 이전값으로 NaN을 채움
data3 = data2.reindex([0,1,2,3,4,5], method='pad') # 위와 같음

data3 = data2.reindex([0,1,2,3,4,5], method='bfill') # NaN의 이후값으로 NaN을 채움
data3 = data2.reindex([0,1,2,3,4,5], method='backfill') # 위와 같음

 

 

 

DataFrame의 재배치

 

reshape('행','열) 함수로 DataFrame의 크기를 재배치할 수 있다

행과 열에 맞게 index와 columns를 부여한다

크기에 맞지않는 index와 columns를 부여하면 에러

df = pd.DataFrame(np.arange(12).reshape(4,3),  # 예시로 0~11까지의 숫자로 4행 3열짜리 배열을 만든다
                  index=['1월', '2월','3월','4월'], # 인덱스 이름 부여 가능
                  columns=['강남','강북','서초']) # 칼럼 이름 부여 가능

 

행과 열은 stack / unstack 으로
columns을 index를 기준으로 쌓아서

좀 더 가시성을 확보할 수 있다

# DataFrame의 재구조화 : stack / unstack

import numpy as np
import pandas as pd

df = pd.DataFrame(1000+np.arange(6).reshape(2,3),
                  columns = ['2020','2021','2022'],
                  index = ['대전','서울'])
print(df)
print()
df_row = df.stack() # index를 기준으로 칼럼쌓기
# 대전  2020    1000
#      2021    1001
#      2022    1002
# 서울  2020    1003
#      2021    1004
#      2022    1005
print(df_row)

print()
df_col = df_row.unstack() # stack결과를 원래대로 되돌림, 인덱스를 열로 보내는 역할
#      2020  2021  2022
# 대전  1000  1001  1002
# 서울  1003  1004  1005
print(df_col)

 

 

 

 

 

 

슬라이싱 관련 메소드(loc, iloc)와 연산

 

loc와 iloc를 통한 슬라이싱

 

loc : [ 이상 : 이하 , 이상 : 이하 ] 형식으로 슬라이싱

* df.loc[:'2월', ['서초']]

괄호를 입히면 칼럼명을 같이

df.loc[:'2월', '서초']

괄호를 빼면 칼럼명을 빼고 출력

 

 

iloc : [ 이상 : 미만 , 이상 : 미만 ]  형식으로 슬라이싱   

* 0이 1행에 해당함

# loc - 라벨 지원, iloc - 숫자 지원

print('--loc--')
print(df.loc['3월', :]) # ['3월', :]
print(df.loc[:'2월']) #    
print(df.loc[:'2월', ['서초']]) # 2월 이하의 행의 서초 열만 출력    

print('--iloc--')
print(df.iloc[2]) # 3번째 행의 모든 열의 값 
print(df.iloc[2,:]) # 3번째 행의 모든 열의 값 
print(df.iloc[:3]) # 3행 까지의 모든 열의 값
print(df.iloc[:3,2]) # 3행 까지의 2번째 열의 값
print(df.iloc[1:3, 1:3]) # 2,3행의 2,3열의 값

print('산술 연산')
s1 = pd.Series([1,2,3], index=['a','b','c'])
s2 = pd.Series([4,5,6,7], index=['a','b','d','c'])
print(s1)
print(s2)
print(s1+s2) # 인덱스가 대응되는 값들만 연산이됨  # d = NaN
print(s1.add(s2)) # add(+), sub(-), mul(*), div(/) 사칙연산 메소드

print()
df1 = pd.DataFrame(np.arange(9).reshape(3,3), columns=list('kbs'),index=['서울','대전','부산'])
df2 = pd.DataFrame(np.arange(12).reshape(4,3), columns=list('kbs'),index=['서울','대전','제주','목포'])
print(df1)
print(df2)
print(df1+df2) # 인덱스가 대응되는 값들만 연산이됨  # 목포, 부산, 제주 = NaN
print(df1.add(df2)) # 인덱스가 대응되는 값들만 연산이됨  # 목포, 부산, 제주 = NaN
print(df1.add(df2, fill_value=0)) # NaN은 특정 값으로 채울때 fill_value()

 

 

 

 

 

DataFrame의 기술적 통계와 관련된 함수

 

df = pd.DataFrame([[1.4,np.nan],[7,-4.5],[np.NaN,None], [0.5,-1]],columns=['one','two'])
print(df)
print(df.drop(1))
print(df.isnull()) # 결측치 탐지 ( boolean 리턴 )
print(df.notnull()) # 위와 반대
print()
print(df.dropna()) # NaN을 탐지해서 모두 지움 (하나라도 NaN이면 지움)
print(df.dropna(how='any')) # NaN을 탐지해서 모두 지움 (하나라도 NaN이면 지움)
print(df.dropna(how='all')) # NaN을 탐지해서 모두 지움 (모두 NaN이면 지움)
print(df.dropna(axis='rows')) # NaN이 포함된 행을 지움
print(df.dropna(axis='columns')) # NaN이 포함된 열을 지움
print(df.dropna(axis='columns', how='all')) # 응용 : 모든 열이 NaN인 열을 지움

print()
print(df.fillna(0)) # 결측치를 0 또는 평균등의 값으로 대체
print(df.fillna(method='ffill')) # 결측치를 앞의 값으로 대체
print(df.fillna(method='bfill')) # 결측치를 뒤의 값으로 대체
print(df.dropna(subset=['one'])) # one열 중에서 NaN이 있는 행을 지움

print('---')
print(df)
print(df.sum()) # NaN은 연산에서 제외
print(df.sum(axis=0)) # 열의 합
print(df.sum(axis=1)) # 행의 합
print(df.mean(axis=1)) # 행의 평균
print(df.mean(axis=1,skipna=True))
print(df.mean(axis=1,skipna=False)) # NaN를 연산에 포함하기 때문에 하나라도 NaN이면 결과가 NaN
print()
print(df.describe()) # 요약 통계량 
print(df.info()) # 구조 확인

 

 

 

 

 

DataFrame의 범주화

 

소량의 데이터일 때는 범주화를 하지 않아도

확인하기 쉽지만

 

하나의 모집단에는 수많은 데이터들이 들어있는 경우가 대부분이기 때문에

범주화를 통해 원하는 범주에 있는 데이터를 한눈에 확인할 수 있도록 하는 방법은 필수요소이다

print('------ 데이터 범주화 (연속형 => 범주형) ------')
price=[10.3, 5.5, 7.8, 3.6]
cut = [3,7,9,11] # 구간 기준값
result_cut = pd.cut(price, cut)
print(result_cut) # [(9, 11] = 9 < x <= 11,
#                    (3, 7] = 3 < x <= 7,...
print(pd.value_counts(result_cut)) # 범주화의 결과를 카운팅

print()
datas = pd.Series(np.arange(1,1001)) # 시리즈 DataFrame 아님
print(datas.head(2))
print(datas.tail(2))

# cut = [1,500,100] # 구간 기준값
# result_cut2 = pd.qcut(datas, cut) # 범주가 아주 많을 때
# print(result_cut2)

result_cut2 = pd.qcut(datas, 3) # 1~1000의 정수를 3개의 범주로 나는다는 의미
print(result_cut2)
# 0       (0.999, 334.0]  # 334까지
# 1       (0.999, 334.0]
# 2       (0.999, 334.0]
# 3       (0.999, 334.0]
# 4       (0.999, 334.0]
#             ...         #  334~ 667까지
# 995    (667.0, 1000.0]  #  667 ~ 1000까지
# 996    (667.0, 1000.0]
# 997    (667.0, 1000.0]
# 998    (667.0, 1000.0]
# 999    (667.0, 1000.0]
# Length: 1000, dtype: category

print(pd.value_counts(result_cut2))
# (0.999, 334.0]     334
# (334.0, 667.0]     333
# (667.0, 1000.0]    333

 

 

범주화한 그룹의 연산도 가능하다

print()
# 각 범주의 그룹별 연산
group_col= datas.groupby(result_cut2)
# print(group_col)

print(group_col.agg('count')) 
print(group_col.agg(['count','mean','std','min'])) # [ ]에 여러개의 연산을 한번에 요청할 수 있다

# 직접 함수를 작성하여 그룹별 연산
def summary_func(gr):
    return {
        'count':gr.count(),
        'mean':gr.mean(),
        'std':gr.std(),
        'min':gr.min(),
        }
print(group_col.apply(summary_func)) # 함수를 실행하는 함수
print(group_col.apply(summary_func).unstack()) # group_col.agg(['count','mean','std','min']) 과 같은 모양

 

 

 

 

 

DataFrame의 병합 및 그룹화 연산

 

 

DataFrame 끼리 병합을 해서

하나의 DataFrame으로 만들 수 있다

 

공통된 columns을 가지고 있을 때와

 

공통된  columns이 없을 때로 나뉜다

 

먼저,  columns이 있을땐
inner join과 outer join 으로 나뉘는데

 

다음과 같다,

# DataFrame merge (병합)

import numpy as np
import pandas as pd

df1 = pd.DataFrame({'data1': range(7),'key':['b','b','b','c','a','a','b']})
print(df1)
df2 = pd.DataFrame({'key': ['a','b','d'],'data2':range(3)})
print(df2)

print()
print(pd.merge(df1,df2, on='key', how='inner')) # 공통 column 'key'를 기준으로 병합 (inner join)
						# 공통된 key값의 데이터만 (b,d)
print()
print(pd.merge(df1,df2, on='key', how='outer')) # 공통 column 'key'를 기준으로 병합 (full outer join)
						# 공통되지 않는 key값 (c와 d를 포함한 모든 데이터)
print()
print(pd.merge(df1,df2, on='key', how='left')) # 공통 column 'key'를 기준으로 병합 (left outer join)
						# 공통되지 않는 key값 중 왼쪽 Dataframe의 칼럼 값을 모두 (data2 의 c값은 NaN)
print()
print(pd.merge(df1,df2, on='key', how='right')) # 공통 column 'key'를 기준으로 병합 (right outer join)
						# 공통되지 않는 key값 중 오른쪽 Dataframe의 칼럼 값을 모두 (data1 의 d값은 NaN)

 

 

공통된  columns이 없을 땐

합칠 기준이 되는 columns를 선택 해주어야 한다

print()
# 공통 칼럼이 없는 경우  # df1 vs df3
df3 = pd.DataFrame({'key2': ['a','b','d'],'data2':range(3)})
print(df3)
print(pd.merge(df1,df3, left_on='key', right_on='key2')) 

print()
print(pd.concat([df1,df3])) # 이어 붙이기 axix=0, # 행단위
print(pd.concat([df1,df3],axis=1))             # 열단위

 

 

 

 

그룹화 연산 방법

 

도시별 인구, 학번별 성별 등..

어떤 데이터를 기준으로 다른 데이터의 값을 구하려고 할 때 사용한다

 

어떠한 Data에서 원하는 값을 얻어내기 위한 방법으로

그룹화연산 또한 필수적으로 알아둬야할 방법이다

print('\n-------- 그룹화 연산 : pivot, groupby, pivot_table --------')
# 데이터 열 중에서 두개의 키를 사용하여 데이터를 선택 후 연산. 구조 변경 후 집계표 작성.
data = {
    'city':['강남','강북','강남','강북'],
    'year':[2000,2001,2002,2002],
    'pop':[3.3, 2.5, 3.0, 2.0]
    }
df = pd.DataFrame(data)
print(df)
print('---pivot---')
print(df.pivot('city','year','pop')) # 행, 열, 계산 = 행, 열을 지정해서 구조를 변경
print()
print(df.pivot('year','city','pop')) # 행, 열, 계산
print()
print(df.set_index(['city','year']).unstack()) # 1번과 같은 결과

print('---groupby---')
print(df.groupby(['city']).sum())
print(df.groupby(['city']).agg('sum'))
print(df.groupby(['city','year']).mean())

print()
print(df.pivot_table(index=['city']),'피봇테이블')
print(df.pivot_table(index=['city'],aggfunc=np.mean)) # aggfunc=np.mean 이 기본값
print(df.pivot_table(index=['city','year'],aggfunc=np.mean))
print(df.pivot_table(index=['city','year'],aggfunc=[len,np.sum]))
print(df.pivot_table(values=['pop'],index=['city'])) #city별 pop의 평균   # aggfunc=np.mean 이 기본값
print(df.pivot_table(values=['pop'],index=['city'], aggfunc=np.mean))
print(df.pivot_table(values=['pop'],index=['city'],columns='year'))
print(df.pivot_table(values=['pop'],index=['year'],columns='city', margins=True)) # 행과 열의 합 All 출력
print(df.pivot_table(values=['pop'],index=['year'],columns='city', margins=True, fill_value=0)) # NaN은 0으로 출력

 

 

매우 중요한 부분이다

 

데이터 분석에 있어서 필수적인 연산과 범주화 등

 

꼭 기억해야할 내용들이 들어있는 부분이기에

 

포스팅을 끝내고도 다시 한번 봐야할 것 같다.

 

 

 

 

다음 글에서는

 

pandas를 이용해서 파일과 웹 등에서 Data를 읽어오는 방법을 복습해볼 것이다

 

이부분도 아주 중요한 부분이기 때문에 꼭 봐야합니다

 

3번 글로 돌아오겠습니다

728x90
Comments