일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- Machine Learning
- 배열
- ML
- control statement
- 순회 크롤러
- python control statement
- sklearn
- Naive Bayes
- Titanic data set
- pandas
- 나이브베이즈
- 타이타닉 데이터
- 파이썬 크롤러
- 제어문
- scikit-learn
- KMeans Clustering
- 파이썬 크롤링
- Data pre-processing
- Python crawler
- 머신러닝
- dataframe
- 파이썬 제어문
- K평균군집화
- 넘파이
- python
- NumPy
- 파이썬 객체 지향 프로그래밍
- 파이썬
- 판다스
- 사이킷런
- Today
- Total
Try to 개발자 EthanJ의 성장 로그
Pandas Data pre-processing 판다스 데이터 전처리 본문

Pandas Data pre-processing
판다스 데이터 전처리
1. Hierarchical Indexing 계층 색인¶
행, 열의 각 축에 대해 다중 단계(계층)를 지정하여 데이터에 차원을 설정
index에 다차원 리스트를 전달하면 계층 색인을 지정할 수 있음
데이터 구조를 재배열하거나 pivot 테이블과 같은 group 기반 작업에 유용
재배열 method
stack() : column을 row로 pivot
unstack() : row를 column으로 pivo
import pandas as pd
import numpy as np
1.1. Series Hierarchical Indexing 시리즈 계층 색인¶
index에
다차원 리스트
(아이템 2개)를 전달다차원리스트[0]
: 상위계층상위계층 작성시 주의점 : 각 계층별로 속하는 하위계층 값의 개수만큼 계층명 작성
상위계층 리스트 개수 = 하위계층 리스트 개수
다차원리스트[1]
: 하위계층
row index
상위계층 :
a
,b
,c
,d
하위계층 :
a(1, 2, 3)
,b(1, 2)
,c(1, 2, 3, 4)
,d(1)
hier_sr = pd.Series(np.arange(10),
index=[['a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'c', 'd'],
[1, 2, 3, 1, 2, 1, 2, 3, 4, 1]])
hier_sr
a 1 0 2 1 3 2 b 1 3 2 4 c 1 5 2 6 3 7 4 8 d 1 9 dtype: int32
- Index 확인
hier_sr.index
MultiIndex([('a', 1), ('a', 2), ('a', 3), ('b', 1), ('b', 2), ('c', 1), ('c', 2), ('c', 3), ('c', 4), ('d', 1)], )
상위 index(상위 계층) 접근
- 계층 색인이 적용된 객체의 상위 index에 접근: 일반적인
Series indexing
으로 접근
- 계층 색인이 적용된 객체의 상위 index에 접근: 일반적인
hier_sr['c']
1 5 2 6 3 7 4 8 dtype: int32
계층색인에 대한 slicing:
stop index
도 포함['b':'d']
입력 >'b', 'c', 'd'
조회
hier_sr['b':'d']
b 1 3 2 4 c 1 5 2 6 3 7 4 8 d 1 9 dtype: int32
하위 Index(계층)에 접근
object[상위 Index 범위, 하위 Index 범위]
- 전체 상위 Index 범위, 하위 label index = 2인 data만 추출
hier_sr[:, 2]
a 1 b 4 c 6 dtype: int32
하위 Index Slicing:
df.loc
method 사용- user custom index로 stop index 지정: stop index 포함 반환
hier_sr['c'].loc[2:4]
2 6 3 7 4 8 dtype: int32
1.2. obj.unstack()
¶
the lowest row
계층을MutiIndex
의low columns
로 적용하여 상위 계층으로 올림Series
object >DataFrame
object로 재배열NaN
: 기존에는 없던 row 계층에 대한 값
- 현재 2중 row 계층, columns는 index 존재하지 않음 (0 계층)
hier_sr
a 1 0 2 1 3 2 b 1 3 2 4 c 1 5 2 6 3 7 4 8 d 1 9 dtype: int32
unstk_df = hier_sr.unstack()
unstk_df
1 | 2 | 3 | 4 | |
---|---|---|---|---|
a | 0.0 | 1.0 | 2.0 | NaN |
b | 3.0 | 4.0 | NaN | NaN |
c | 5.0 | 6.0 | 7.0 | 8.0 |
d | 9.0 | NaN | NaN | NaN |
1.3. obj.stack()
¶
columns
에 할당된 값을 >MultiIndex
의lower row index
로 내려서 재배열DataFrame
object >Series
object
unstk_df.stack()
a 1 0.0 2 1.0 3 2.0 b 1 3.0 2 4.0 c 1 5.0 2 6.0 3 7.0 4 8.0 d 1 9.0 dtype: float64
1.4. DataFrame
계층 색인¶
row index:
2017['a', 'b']
,2018['a', 'b']
column index:
'서울'['강남', '잠실']
,'경기'['분당', '수원', '판교']
area_df = pd.DataFrame(np.random.randint(1, 21, (20)).reshape(4,5),
index=[[2017, 2017, 2018, 2018],
['a', 'b', 'a', 'b']],
columns=[['서울', '서울', '경기', '경기', '경기'],
['강남', '잠실', '분당', '수원', '판교']])
area_df
서울 | 경기 | |||||
---|---|---|---|---|---|---|
강남 | 잠실 | 분당 | 수원 | 판교 | ||
2017 | a | 10 | 8 | 10 | 7 | 6 |
b | 9 | 4 | 10 | 9 | 19 | |
2018 | a | 13 | 9 | 1 | 12 | 16 |
b | 11 | 14 | 16 | 14 | 19 |
columns
의 Higher Index 접근: 일반적인 DataFrame columns indexing 방식:df[column]
area_df['서울']
강남 | 잠실 | ||
---|---|---|---|
2017 | a | 10 | 8 |
b | 9 | 4 | |
2018 | a | 13 | 9 |
b | 11 | 14 |
- 이중 계층 columns > 이중 indexing으로 하나의 item 추출 가능
df[col1][col2]
area_df['서울']['강남']
2017 a 10 b 9 2018 a 13 b 11 Name: 강남, dtype: int32
- 한 번에 두 계층 index 지정:
tuple
로 전달
area_df[('서울', '강남')]
2017 a 10 b 9 2018 a 13 b 11 Name: (서울, 강남), dtype: int32
- row의 상위 계층 접근:
df.loc[row]
area_df.loc[2017]
서울 | 경기 | ||||
---|---|---|---|---|---|
강남 | 잠실 | 분당 | 수원 | 판교 | |
a | 10 | 8 | 10 | 7 | 6 |
b | 9 | 4 | 10 | 9 | 19 |
이중 계층 row index item 접근
df.loc[idx1].loc[idx2]
df.loc[(idx1, idx2)]
area_df.loc[2017].loc['a']
서울 강남 10 잠실 8 경기 분당 10 수원 7 판교 6 Name: a, dtype: int32
area_df.loc[(2017, 'a')]
서울 강남 10 잠실 8 경기 분당 10 수원 7 판교 6 Name: (2017, a), dtype: int32
columns
하위 계층 index: '분당'~'수원' data 추출DataFrame
columns silcing
:row slicing result
에만 columns slicing 적용 가능
area_df['경기'].loc[:, '분당':'수원']
분당 | 수원 | ||
---|---|---|---|
2017 | a | 10 | 7 |
b | 10 | 9 | |
2018 | a | 1 | 12 |
b | 16 | 14 |
- DataFrame
row 최하위 Index
>columns Index
재배열
area_df
서울 | 경기 | |||||
---|---|---|---|---|---|---|
강남 | 잠실 | 분당 | 수원 | 판교 | ||
2017 | a | 10 | 8 | 10 | 7 | 6 |
b | 9 | 4 | 10 | 9 | 19 | |
2018 | a | 13 | 9 | 1 | 12 | 16 |
b | 11 | 14 | 16 | 14 | 19 |
area_df.unstack()
서울 | 경기 | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
강남 | 잠실 | 분당 | 수원 | 판교 | ||||||
a | b | a | b | a | b | a | b | a | b | |
2017 | 10 | 9 | 8 | 4 | 10 | 10 | 7 | 9 | 6 | 19 |
2018 | 13 | 11 | 9 | 14 | 1 | 16 | 12 | 14 | 16 | 19 |
- DataFrame
columns 최하위 index
>row 하위 index
재배열
area_df.stack()
경기 | 서울 | |||
---|---|---|---|---|
2017 | a | 강남 | NaN | 10.0 |
분당 | 10.0 | NaN | ||
수원 | 7.0 | NaN | ||
잠실 | NaN | 8.0 | ||
판교 | 6.0 | NaN | ||
b | 강남 | NaN | 9.0 | |
분당 | 10.0 | NaN | ||
수원 | 9.0 | NaN | ||
잠실 | NaN | 4.0 | ||
판교 | 19.0 | NaN | ||
2018 | a | 강남 | NaN | 13.0 |
분당 | 1.0 | NaN | ||
수원 | 12.0 | NaN | ||
잠실 | NaN | 9.0 | ||
판교 | 16.0 | NaN | ||
b | 강남 | NaN | 11.0 | |
분당 | 16.0 | NaN | ||
수원 | 14.0 | NaN | ||
잠실 | NaN | 14.0 | ||
판교 | 19.0 | NaN |
1.5. df.swaplevel()
¶
계층(
level index
)의int index
또는label index
를 사용하여 상하위간 교환df.swaplevel(key1, key2, axis=0)
:row index
의key1
과key2
에 해당하는 계층 교환default:
axis=0
:row index
교환axis=1
:columns index
교환
area_df.swaplevel(1, 0)
서울 | 경기 | |||||
---|---|---|---|---|---|---|
강남 | 잠실 | 분당 | 수원 | 판교 | ||
a | 2017 | 10 | 8 | 10 | 7 | 6 |
b | 2017 | 9 | 4 | 10 | 9 | 19 |
a | 2018 | 13 | 9 | 1 | 12 | 16 |
b | 2018 | 11 | 14 | 16 | 14 | 19 |
area_df.swaplevel(0, 1)
서울 | 경기 | |||||
---|---|---|---|---|---|---|
강남 | 잠실 | 분당 | 수원 | 판교 | ||
a | 2017 | 10 | 8 | 10 | 7 | 6 |
b | 2017 | 9 | 4 | 10 | 9 | 19 |
a | 2018 | 13 | 9 | 1 | 12 | 16 |
b | 2018 | 11 | 14 | 16 | 14 | 19 |
area_df.swaplevel(1, 0, axis=1)
강남 | 잠실 | 분당 | 수원 | 판교 | ||
---|---|---|---|---|---|---|
서울 | 서울 | 경기 | 경기 | 경기 | ||
2017 | a | 10 | 8 | 10 | 7 | 6 |
b | 9 | 4 | 10 | 9 | 19 | |
2018 | a | 13 | 9 | 1 | 12 | 16 |
b | 11 | 14 | 16 | 14 | 19 |
2. Sorting 정렬¶
obj.sort_index(axis=0, ascending=True)
:index
를 기준으로 정렬DataFrame
,Series
object 적용 가능parameter default:
axis=0, ascending=True
:row index
기준, 오름차순 정렬axis=1
:columns index
기준 정렬,ascending=False
: 내림차순 정렬
obj.sort_values(by, axis=0, ascending=True)
:value
값을 기준으로 정렬DataFrame
,Series
object 적용 가능parameter
by=[' ']
: 정렬의 기준이 되는 인덱스를str
또는list of str
로 전달axis=0
: default,columns
을 기준으로row label index
를 정렬,
기준값으로by=
에columns label index
전달axis=1
:row
를 기준으로columns label index
를 정렬,
기준값으로by=
에row label index
전달
st_sr = pd.Series([2, 3, 1, 7, 0], index=list('gacfd'))
st_sr
g 2 a 3 c 1 f 7 d 0 dtype: int64
index
기준 정렬
st_sr.sort_index()
a 3 c 1 d 0 f 7 g 2 dtype: int64
st_sr.sort_index(ascending=False)
g 2 f 7 d 0 c 1 a 3 dtype: int64
obj.sort_index()
: 결과 object return > 원본 영향 X
st_sr
g 2 a 3 c 1 f 7 d 0 dtype: int64
values
기준 정렬
st_sr.sort_values()
d 0 c 1 g 2 a 3 f 7 dtype: int64
st_sr.sort_values(ascending=False)
f 7 a 3 g 2 c 1 d 0 dtype: int64
np.random.seed(4)
DataFrame
생성
sort_df = pd.DataFrame(np.random.randint(20, size=(4, 5)),
index=list('dbca'),
columns=list('CBADE'))
sort_df
C | B | A | D | E | |
---|---|---|---|---|---|
d | 14 | 5 | 1 | 8 | 8 |
b | 18 | 9 | 7 | 13 | 8 |
c | 4 | 18 | 12 | 6 | 10 |
a | 3 | 0 | 9 | 6 | 6 |
row label index
기준 오름차순 정렬: default:axis=0
sort_df.sort_index()
C | B | A | D | E | |
---|---|---|---|---|---|
a | 3 | 0 | 9 | 6 | 6 |
b | 18 | 9 | 7 | 13 | 8 |
c | 4 | 18 | 12 | 6 | 10 |
d | 14 | 5 | 1 | 8 | 8 |
sort_df.sort_index(ascending=False)
C | B | A | D | E | |
---|---|---|---|---|---|
d | 14 | 5 | 1 | 8 | 8 |
c | 4 | 18 | 12 | 6 | 10 |
b | 18 | 9 | 7 | 13 | 8 |
a | 3 | 0 | 9 | 6 | 6 |
columns label index
기준 정렬:axis=1
sort_df.sort_index(axis=1)
A | B | C | D | E | |
---|---|---|---|---|---|
d | 1 | 5 | 14 | 8 | 8 |
b | 7 | 9 | 18 | 13 | 8 |
c | 12 | 18 | 4 | 6 | 10 |
a | 9 | 0 | 3 | 6 | 6 |
sort_df.sort_index(axis=1, ascending=False)
E | D | C | B | A | |
---|---|---|---|---|---|
d | 8 | 8 | 14 | 5 | 1 |
b | 8 | 13 | 18 | 9 | 7 |
c | 10 | 6 | 4 | 18 | 12 |
a | 6 | 6 | 3 | 0 | 9 |
columns label index
기준 내림차순 정렬 후,row label index
기준 오름차순 정렬
sort_df.sort_index(axis=1, ascending=False).sort_index()
E | D | C | B | A | |
---|---|---|---|---|---|
a | 6 | 6 | 3 | 0 | 9 |
b | 8 | 13 | 18 | 9 | 7 |
c | 10 | 6 | 4 | 18 | 12 |
d | 8 | 8 | 14 | 5 | 1 |
obj.sort_index
: sorted된 object return > 원본 영향 X
sort_df
C | B | A | D | E | |
---|---|---|---|---|---|
d | 14 | 5 | 1 | 8 | 8 |
b | 18 | 9 | 7 | 13 | 8 |
c | 4 | 18 | 12 | 6 | 10 |
a | 3 | 0 | 9 | 6 | 6 |
values
기준 정렬row
단위 정렬:obj.sort_values(axis=0, by='columns label')
sort_df.sort_values(axis=0, by='D')
C | B | A | D | E | |
---|---|---|---|---|---|
c | 4 | 18 | 12 | 6 | 10 |
a | 3 | 0 | 9 | 6 | 6 |
d | 14 | 5 | 1 | 8 | 8 |
b | 18 | 9 | 7 | 13 | 8 |
sort_df.sort_values(by='A', ascending=False)
C | B | A | D | E | |
---|---|---|---|---|---|
c | 4 | 18 | 12 | 6 | 10 |
a | 3 | 0 | 9 | 6 | 6 |
b | 18 | 9 | 7 | 13 | 8 |
d | 14 | 5 | 1 | 8 | 8 |
row label
의values
를 기준으로 정렬: 정렬 단위=columns
,axis=1
,by='row label'
sort_df.sort_values(by='d', axis=1)
A | B | D | E | C | |
---|---|---|---|---|---|
d | 1 | 5 | 8 | 8 | 14 |
b | 7 | 9 | 13 | 8 | 18 |
c | 12 | 18 | 6 | 10 | 4 |
a | 9 | 0 | 6 | 6 | 3 |
sort_df.sort_values(by='c', axis=1, ascending=False)
B | A | E | D | C | |
---|---|---|---|---|---|
d | 5 | 1 | 8 | 8 | 14 |
b | 9 | 7 | 8 | 13 | 18 |
c | 18 | 12 | 10 | 6 | 4 |
a | 0 | 9 | 6 | 6 | 3 |
by=
기준label index
두 개 이상:by=[list of 'str'(label index)]
Sort Priority:
by=
으로 전달 된 list의label index
순서대로 우선 순위- 1순위
label index
value가 같으면 > 2순위label index
value로 정렬
- 1순위
sort_df.sort_values(by=['E', 'D'], axis=0)
C | B | A | D | E | |
---|---|---|---|---|---|
a | 3 | 0 | 9 | 6 | 6 |
d | 14 | 5 | 1 | 8 | 8 |
b | 18 | 9 | 7 | 13 | 8 |
c | 4 | 18 | 12 | 6 | 10 |
- 각각
ascending=
parameter를 다르게 설정하고 싶다면:list of 'bool'
로 전달
sort_df.sort_values(by=['a', 'c'], axis=1, ascending=[True, False])
B | C | E | D | A | |
---|---|---|---|---|---|
d | 5 | 14 | 8 | 8 | 1 |
b | 9 | 18 | 8 | 13 | 7 |
c | 18 | 4 | 10 | 6 | 12 |
a | 0 | 3 | 6 | 6 | 9 |
1.1. 2차원 list
columns_list = [[2016, 2016, 2017, 2017], ['영어', '수학', '영어', '수학']]
row_list = ['Kim', 'Park', 'Lee', 'Jung', 'Moon']
score_df1 = pd.DataFrame(np.random.randint(50, 100, size=(5,4)),
columns=columns_list,
index=row_list)
score_df1
2016 | 2017 | |||
---|---|---|---|---|
영어 | 수학 | 영어 | 수학 | |
Kim | 52 | 96 | 80 | 58 |
Park | 99 | 52 | 73 | 82 |
Lee | 90 | 92 | 95 | 83 |
Jung | 82 | 95 | 78 | 53 |
Moon | 65 | 84 | 81 | 67 |
score_df1.columns.rename(['년도', '과목'], inplace=True)
score_df1.index.rename('학생명', inplace=True)
score_df1
년도 | 2016 | 2017 | ||
---|---|---|---|---|
과목 | 영어 | 수학 | 영어 | 수학 |
학생명 | ||||
Kim | 52 | 96 | 80 | 58 |
Park | 99 | 52 | 73 | 82 |
Lee | 90 | 92 | 95 | 83 |
Jung | 82 | 95 | 78 | 53 |
Moon | 65 | 84 | 81 | 67 |
1.2. pd.MultiIndex.from_tuples(list of tuple, names=[list of 'index name'])
columns_list_tuple = [(2016, '영어'), (2016, '수학'), (2017, '영어'), (2017, '수학')]
columns_index = pd.MultiIndex.from_tuples(columns_list_tuple, names=['년도', '과목'])
row_index = pd.Index(['Kim', 'Park', 'Lee', 'Jung', 'Moon'], name='학생명')
score_df2 = pd.DataFrame(np.random.randint(50, 100, size=(5, 4)),
columns=columns_index,
index=row_index)
score_df2
년도 | 2016 | 2017 | ||
---|---|---|---|---|
과목 | 영어 | 수학 | 영어 | 수학 |
학생명 | ||||
Kim | 98 | 67 | 75 | 59 |
Park | 98 | 62 | 73 | 80 |
Lee | 72 | 53 | 61 | 73 |
Jung | 56 | 89 | 95 | 92 |
Moon | 57 | 59 | 68 | 98 |
1.3. pd.MultiIndex.from_product([lists of each level label index])
columns_level_list = [[2016, 2017], ['영어', '수학']]
columns_index = pd.MultiIndex.from_product(columns_level_list, names=['년도', '과목'])
print(columns_index)
row_index = pd.Index(['Kim', 'Park', 'Lee', 'Jung', 'Moon'], name='학생명')
score_df = pd.DataFrame(np.random.randint(50, 100, size=(5, 4)),
columns=columns_index,
index=row_index)
score_df
MultiIndex([(2016, '영어'), (2016, '수학'), (2017, '영어'), (2017, '수학')], names=['년도', '과목'])
년도 | 2016 | 2017 | ||
---|---|---|---|---|
과목 | 영어 | 수학 | 영어 | 수학 |
학생명 | ||||
Kim | 71 | 80 | 65 | 86 |
Park | 77 | 93 | 58 | 87 |
Lee | 58 | 89 | 82 | 80 |
Jung | 54 | 61 | 58 | 86 |
Moon | 81 | 90 | 67 | 64 |
- 2016년 data만 별도의 DataFrame으로 분리 저장하시오. (deep copy)
df_2016 = score_df[2016].copy()
df_2016
과목 | 영어 | 수학 |
---|---|---|
학생명 | ||
Kim | 71 | 80 |
Park | 77 | 93 |
Lee | 58 | 89 |
Jung | 54 | 61 |
Moon | 81 | 90 |
- 2번의
DataFrame
에 대해 학생명 기준 sort by ascending
df_2016.sort_index()
과목 | 영어 | 수학 |
---|---|---|
학생명 | ||
Jung | 54 | 61 |
Kim | 71 | 80 |
Lee | 58 | 89 |
Moon | 81 | 90 |
Park | 77 | 93 |
- 2번의
DataFrame
에 대해 영어 점수 내림차순, 동점자의 경우 수학 점수 오름차순 정렬.
df_2016.sort_values(by=['영어', '수학'], ascending=[False, True])
과목 | 영어 | 수학 |
---|---|---|
학생명 | ||
Moon | 81 | 90 |
Park | 77 | 93 |
Kim | 71 | 80 |
Lee | 58 | 89 |
Jung | 54 | 61 |
3. Data merge 데이터 합병¶
pandas.merge(left_df, right_df)
두 개의
DataFrame
에 대해 특정columns
를 기준으로 합치기parameter
default:
how='inner'
: 합치는 방식,'inner', 'left', 'right', 'outer'
default:
on=None
: 합치는 기준, 공통으로 존재하는column label
DataFrame
df_name
= 고객번호no
+ 고객명name
pd.DataFrame(dict)
:key
> column label,value
> unpacking list and set values
df_name = pd.DataFrame({'no':[30, 31, 32, 33, 34],
'name':["김파썬", "이장고", "박판다", "최넘파", "강주피"]})
df_name
no | name | |
---|---|---|
0 | 30 | 김파썬 |
1 | 31 | 이장고 |
2 | 32 | 박판다 |
3 | 33 | 최넘파 |
4 | 34 | 강주피 |
DataFrame
df_amt
= 고객번호no
+ 주문수량amount
- 다른 고객번호 일부 지정
df_amt = pd.DataFrame({'no':[30, 32, 33, 40, 41],
'amount':[100, 40, 130, 40, 60]})
df_amt
no | amount | |
---|---|---|
0 | 30 | 100 |
1 | 32 | 40 |
2 | 33 | 130 |
3 | 40 | 40 |
4 | 41 | 60 |
3.1. parameter how='inner'
¶
- default:
how='inner'
: common columns만 merge
pd.merge(df_name, df_amt)
no | name | amount | |
---|---|---|---|
0 | 30 | 김파썬 | 100 |
1 | 32 | 박판다 | 40 |
2 | 33 | 최넘파 | 130 |
how='outer'
: common columns 기준교집합이 아닌 부분:
NaN
으로 처리 (누락 X)- 합집합 형태로 만듦
pd.merge(df_name, df_amt, how='outer')
no | name | amount | |
---|---|---|---|
0 | 30 | 김파썬 | 100.0 |
1 | 31 | 이장고 | NaN |
2 | 32 | 박판다 | 40.0 |
3 | 33 | 최넘파 | 130.0 |
4 | 34 | 강주피 | NaN |
5 | 40 | NaN | 40.0 |
6 | 41 | NaN | 60.0 |
how='left'
: first parameterleft_df
의 data와 교집합 data 결합
pd.merge(df_name, df_amt, how='left')
no | name | amount | |
---|---|---|---|
0 | 30 | 김파썬 | 100.0 |
1 | 31 | 이장고 | NaN |
2 | 32 | 박판다 | 40.0 |
3 | 33 | 최넘파 | 130.0 |
4 | 34 | 강주피 | NaN |
how='right'
: second parameterright_df
의 data와 교집합 data 결합
pd.merge(df_name, df_amt, how='right')
no | name | amount | |
---|---|---|---|
0 | 30 | 김파썬 | 100 |
1 | 32 | 박판다 | 40 |
2 | 33 | 최넘파 | 130 |
3 | 40 | NaN | 40 |
4 | 41 | NaN | 60 |
- 공통 컬럼이 두 개 이상인 경우
df_date_phone = pd.DataFrame({'고객명':['김파이썬', '이장고', '박팬더스'],
'날짜':['2022-10-22', '2022-10-23', '2022-10-24'],
'정보':['010', '011', '019']})
df_date_phone
고객명 | 날짜 | 정보 | |
---|---|---|---|
0 | 김파이썬 | 2022-10-22 | 010 |
1 | 이장고 | 2022-10-23 | 011 |
2 | 박팬더스 | 2022-10-24 | 019 |
df_sex = pd.DataFrame({'고객명':['김파이썬', '박팬더스', '최넘파이'],
'정보':['F', 'M', 'M']})
df_sex
고객명 | 정보 | |
---|---|---|
0 | 김파이썬 | F |
1 | 박팬더스 | M |
2 | 최넘파이 | M |
- 공통
columns index
2개 이상: parameter가 없으면 > 결과도 없다
pd.merge(df_date_phone, df_sex)
고객명 | 날짜 | 정보 |
---|
pd.merge()
기준 column:on='고객명'
common column:
정보
default:
how='inner'
pd.merge(df_date_phone, df_sex, on='고객명')
고객명 | 날짜 | 정보_x | 정보_y | |
---|---|---|---|---|
0 | 김파이썬 | 2022-10-22 | 010 | F |
1 | 박팬더스 | 2022-10-24 | 019 | M |
left_on
,right_on
: 두 개의 DataFrame에 대해서 서로 다른 기준columns index
을 지정- e.g. 동일한 속성의 자료를 저장하는 컬럼인데 표기하는 이름이 다른 경우
df_date_price = pd.DataFrame({'고객이름':['김파이썬', '박팬더스', '강주피터'],
'날짜':['2020-01-01', '2020-02-01', '2020-02-15'],
'구매금액':[1, 2, 3]})
df_date_price
고객이름 | 날짜 | 구매금액 | |
---|---|---|---|
0 | 김파이썬 | 2020-01-01 | 1 |
1 | 박팬더스 | 2020-02-01 | 2 |
2 | 강주피터 | 2020-02-15 | 3 |
df_sex = pd.DataFrame({'고객명':['김파이썬', '박팬더스'],
'성별':['F', 'M']})
df_sex
고객명 | 성별 | |
---|---|---|
0 | 김파이썬 | F |
1 | 박팬더스 | M |
pd.merge(df_date_price, df_sex)
>common columns
없음: Error
- left_df(
df_date_price
), right_df(df_sex
)에서common columns
각각 지정
df_client = pd.merge(df_date_price, df_sex, left_on='고객이름', right_on='고객명')
df_client
고객이름 | 날짜 | 구매금액 | 고객명 | 성별 | |
---|---|---|---|---|---|
0 | 김파이썬 | 2020-01-01 | 1 | 김파이썬 | F |
1 | 박팬더스 | 2020-02-01 | 2 | 박팬더스 | M |
df_client = df_client.drop('고객명', axis=1)
df_client
고객이름 | 날짜 | 구매금액 | 성별 | |
---|---|---|---|---|
0 | 김파이썬 | 2020-01-01 | 1 | F |
1 | 박팬더스 | 2020-02-01 | 2 | M |
4. Data Concatenate 데이터 연결 pd.concat()
¶
특정 key
를 기준으로 데이터를 합치지 않고,row
,column
기준으로 데이터를 연결
> data crawling에서 많이 사용됨main parameter
axis
: default:axis=0
행의 축 방향, $\downarrow$,column
을 key로 합친다.
axis=1
: 열의 축 방향, $\rightarrow$,row
를 key로 합친다.join
: DataFrame끼리 연결할 때, 합치는 방법, default:outer
,inner
ignore_index
: 합친 후 기존 인덱스를 유지 또는 새로운 인덱스를 지정
'a', 'c'
만 공통label index
로 가지고 있는Series
sr_1 = pd.Series([1, 2, 3], index=list('abc'))
sr_2 = pd.Series([5, 6, 7, 8], index=list('acef'))
print(sr_1)
print(sr_2)
a 1 b 2 c 3 dtype: int64 a 5 c 6 e 7 f 8 dtype: int64
pd.concat(list of DataFrame)
default:
axis=0
: 행의 축 방향 $\downarrow$첫 번째로 전달된
first_obj
가 위에, 두 번째로 전달된second_obj
가 아래로 연결label index
는 기존 값 유지
pd.concat([sr_1, sr_2])
a 1 b 2 c 3 a 5 c 6 e 7 f 8 dtype: int64
- 새로운 index로 초기화: optional parameter
ignore_index=True
pd.concat([sr_1, sr_2], ignore_index=True)
0 1 1 2 2 3 3 5 4 6 5 7 6 8 dtype: int64
print(sr_1, sr_2)
a 1 b 2 c 3 dtype: int64 a 5 c 6 e 7 f 8 dtype: int64
axis=1
: 열의 축 방향, $\rightarrow$, row 단위 연결- columns 길이(row 개수)가 다른 경우
pd.concat([sr_1, sr_2], axis=1)
0 | 1 | |
---|---|---|
a | 1.0 | 5.0 |
b | 2.0 | NaN |
c | 3.0 | 6.0 |
e | NaN | 7.0 |
f | NaN | 8.0 |
column label index
설정하며 연결:keys
parameter에colums label index
list 전달
pd.concat([sr_1, sr_2], axis=1, keys=['c1', 'c2'], sort=False)
c1 | c2 | |
---|---|---|
a | 1.0 | 5.0 |
b | 2.0 | NaN |
c | 3.0 | 6.0 |
e | NaN | 7.0 |
f | NaN | 8.0 |
> 연습문제¶
df_date_price = pd.DataFrame({'고객명':['김파이썬', '이장고', '박팬더스'],
'날짜':['2022-10-22', '2022-10-23', '2022-12-14'],
'구매금액':[1, 2, 3]})
df_date_price
고객명 | 날짜 | 구매금액 | |
---|---|---|---|
0 | 김파이썬 | 2022-10-22 | 1 |
1 | 이장고 | 2022-10-23 | 2 |
2 | 박팬더스 | 2022-12-14 | 3 |
df_sex = pd.DataFrame({'고객명':['김파이썬', '최넘파이'],
'성별':['F', 'M']})
df_sex
고객명 | 성별 | |
---|---|---|
0 | 김파이썬 | F |
1 | 최넘파이 | M |
- 행의 축 방향으로 DataFrame 연결:row 개수 증가
pd.concat([df_date_price, df_sex], axis=0)
고객명 | 날짜 | 구매금액 | 성별 | |
---|---|---|---|---|
0 | 김파이썬 | 2022-10-22 | 1.0 | NaN |
1 | 이장고 | 2022-10-23 | 2.0 | NaN |
2 | 박팬더스 | 2022-12-14 | 3.0 | NaN |
0 | 김파이썬 | NaN | NaN | F |
1 | 최넘파이 | NaN | NaN | M |
- 열의 축 방향으로 DataFrame 연결: columns 개수 증가
pd.concat([df_date_price, df_sex], axis=1)
고객명 | 날짜 | 구매금액 | 고객명 | 성별 | |
---|---|---|---|---|---|
0 | 김파이썬 | 2022-10-22 | 1 | 김파이썬 | F |
1 | 이장고 | 2022-10-23 | 2 | 최넘파이 | M |
2 | 박팬더스 | 2022-12-14 | 3 | NaN | NaN |
5. Data 집계¶
df.groupby('columns label')
특정 속성(
columns label
)을 기준으로 묶어서 다양한 집계 함수 적용대표적인 집계 함수
.sum()
: 총합.mean()
: 평균값.min()
: 최소값.max()
: 최대값.count()
: 개수.std()
: 표준편차
- pivot table
df.pivot('columns label' to be row, 'colmns label' to be column, 'columns label' to be tuple values, 집계함수)
- 일차원으로 columns, row가 단순 나열된 형식: 데이터 파악에 부적합 >
df.pivot()
을 통해 hierarchical indexing 및 형태 변경을 수행
- 일차원으로 columns, row가 단순 나열된 형식: 데이터 파악에 부적합 >
pop_data = pd.read_excel('data/인구수예제.xlsx')
pop_data
도시 | 자치구 | 연도 | 남자인구 | 여자인구 | 총인구 | |
---|---|---|---|---|---|---|
0 | 서울 | 강남구 | 2013 | 73 | 92 | 165 |
1 | 서울 | 강남구 | 2014 | 139 | 55 | 194 |
2 | 서울 | 강남구 | 2015 | 123 | 83 | 206 |
3 | 서울 | 강남구 | 2016 | 147 | 150 | 297 |
4 | 서울 | 강남구 | 2017 | 57 | 133 | 190 |
5 | 서울 | 서대문구 | 2013 | 95 | 111 | 206 |
6 | 서울 | 서대문구 | 2014 | 149 | 150 | 299 |
7 | 서울 | 서대문구 | 2015 | 106 | 77 | 183 |
8 | 서울 | 서대문구 | 2016 | 56 | 109 | 165 |
9 | 서울 | 서대문구 | 2017 | 82 | 96 | 178 |
10 | 서울 | 종로구 | 2013 | 121 | 68 | 189 |
11 | 서울 | 종로구 | 2014 | 107 | 55 | 162 |
12 | 서울 | 종로구 | 2015 | 50 | 79 | 129 |
13 | 서울 | 종로구 | 2016 | 100 | 80 | 180 |
14 | 서울 | 종로구 | 2017 | 105 | 91 | 196 |
15 | 서울 | 영등포구 | 2013 | 146 | 113 | 259 |
16 | 서울 | 영등포구 | 2014 | 127 | 117 | 244 |
17 | 서울 | 영등포구 | 2015 | 70 | 72 | 142 |
18 | 서울 | 영등포구 | 2016 | 141 | 136 | 277 |
19 | 서울 | 영등포구 | 2017 | 145 | 124 | 269 |
20 | 서울 | 송파구 | 2013 | 90 | 130 | 220 |
21 | 서울 | 송파구 | 2014 | 121 | 66 | 187 |
22 | 서울 | 송파구 | 2015 | 62 | 121 | 183 |
23 | 서울 | 송파구 | 2016 | 80 | 92 | 172 |
24 | 서울 | 송파구 | 2017 | 62 | 150 | 212 |
25 | 서울 | 도봉구 | 2013 | 113 | 138 | 251 |
26 | 서울 | 도봉구 | 2014 | 145 | 140 | 285 |
27 | 서울 | 도봉구 | 2015 | 56 | 139 | 195 |
28 | 서울 | 도봉구 | 2016 | 60 | 71 | 131 |
29 | 서울 | 도봉구 | 2017 | 111 | 62 | 173 |
30 | 서울 | 동작구 | 2013 | 120 | 117 | 237 |
31 | 서울 | 동작구 | 2014 | 94 | 108 | 202 |
32 | 서울 | 동작구 | 2015 | 74 | 139 | 213 |
33 | 서울 | 동작구 | 2016 | 87 | 84 | 171 |
34 | 서울 | 동작구 | 2017 | 79 | 134 | 213 |
35 | 부산 | 해운대구 | 2013 | 124 | 103 | 227 |
36 | 부산 | 해운대구 | 2014 | 101 | 144 | 245 |
37 | 부산 | 해운대구 | 2015 | 115 | 70 | 185 |
38 | 부산 | 해운대구 | 2016 | 134 | 126 | 260 |
39 | 부산 | 해운대구 | 2017 | 146 | 72 | 218 |
40 | 부산 | 수영구 | 2013 | 134 | 94 | 228 |
41 | 부산 | 수영구 | 2014 | 74 | 138 | 212 |
42 | 부산 | 수영구 | 2015 | 69 | 81 | 150 |
43 | 부산 | 수영구 | 2016 | 81 | 148 | 229 |
44 | 부산 | 수영구 | 2017 | 144 | 98 | 242 |
45 | 부산 | 동래구 | 2013 | 83 | 65 | 148 |
46 | 부산 | 동래구 | 2014 | 139 | 87 | 226 |
47 | 부산 | 동래구 | 2015 | 147 | 115 | 262 |
48 | 부산 | 동래구 | 2016 | 61 | 102 | 163 |
49 | 부산 | 동래구 | 2017 | 132 | 105 | 237 |
pop_data.shape
(50, 6)
int index
기반 상위 5개 data만 추출:df.head()
pop_data.head()
도시 | 자치구 | 연도 | 남자인구 | 여자인구 | 총인구 | |
---|---|---|---|---|---|---|
0 | 서울 | 강남구 | 2013 | 73 | 92 | 165 |
1 | 서울 | 강남구 | 2014 | 139 | 55 | 194 |
2 | 서울 | 강남구 | 2015 | 123 | 83 | 206 |
3 | 서울 | 강남구 | 2016 | 147 | 150 | 297 |
4 | 서울 | 강남구 | 2017 | 57 | 133 | 190 |
- 하위 5개 data만 추출:
df.tail()
pop_data.tail()
도시 | 자치구 | 연도 | 남자인구 | 여자인구 | 총인구 | |
---|---|---|---|---|---|---|
45 | 부산 | 동래구 | 2013 | 83 | 65 | 148 |
46 | 부산 | 동래구 | 2014 | 139 | 87 | 226 |
47 | 부산 | 동래구 | 2015 | 147 | 115 | 262 |
48 | 부산 | 동래구 | 2016 | 61 | 102 | 163 |
49 | 부산 | 동래구 | 2017 | 132 | 105 | 237 |
- 상위 n개 data 추출:
df.head(n)
pop_data.head(10)
도시 | 자치구 | 연도 | 남자인구 | 여자인구 | 총인구 | |
---|---|---|---|---|---|---|
0 | 서울 | 강남구 | 2013 | 73 | 92 | 165 |
1 | 서울 | 강남구 | 2014 | 139 | 55 | 194 |
2 | 서울 | 강남구 | 2015 | 123 | 83 | 206 |
3 | 서울 | 강남구 | 2016 | 147 | 150 | 297 |
4 | 서울 | 강남구 | 2017 | 57 | 133 | 190 |
5 | 서울 | 서대문구 | 2013 | 95 | 111 | 206 |
6 | 서울 | 서대문구 | 2014 | 149 | 150 | 299 |
7 | 서울 | 서대문구 | 2015 | 106 | 77 | 183 |
8 | 서울 | 서대문구 | 2016 | 56 | 109 | 165 |
9 | 서울 | 서대문구 | 2017 | 82 | 96 | 178 |
5.1. df.groupby(column name)
¶
'자치구'
별'남자인구'
,'여자인구'
의 5개년 총합
pop_data.groupby('자치구')[['남자인구', '여자인구']].sum()
남자인구 | 여자인구 | |
---|---|---|
자치구 | ||
강남구 | 539 | 513 |
도봉구 | 485 | 550 |
동래구 | 562 | 474 |
동작구 | 454 | 582 |
서대문구 | 488 | 543 |
송파구 | 415 | 559 |
수영구 | 502 | 559 |
영등포구 | 629 | 562 |
종로구 | 483 | 373 |
해운대구 | 620 | 515 |
'도시'
별'남자인구', '여자인구'
총합
pop_data.groupby('도시')[['남자인구', '여자인구']].sum()
남자인구 | 여자인구 | |
---|---|---|
도시 | ||
부산 | 1684 | 1548 |
서울 | 3493 | 3682 |
집계 기준 2개:
'연도', '도시'
columns label index
미지정시 > 집계기준 column
제외 나머지 전부 추출
pop_data.groupby(['연도', '도시']).sum()
남자인구 | 여자인구 | 총인구 | ||
---|---|---|---|---|
연도 | 도시 | |||
2013 | 부산 | 341 | 262 | 603 |
서울 | 758 | 769 | 1527 | |
2014 | 부산 | 314 | 369 | 683 |
서울 | 882 | 691 | 1573 | |
2015 | 부산 | 331 | 266 | 597 |
서울 | 541 | 710 | 1251 | |
2016 | 부산 | 276 | 376 | 652 |
서울 | 671 | 722 | 1393 | |
2017 | 부산 | 422 | 275 | 697 |
서울 | 641 | 790 | 1431 |
'도시', '연도'
별'총인구'
평균
pop_data.groupby(['도시', '연도'])[['총인구']].mean()
총인구 | ||
---|---|---|
도시 | 연도 | |
부산 | 2013 | 201.000000 |
2014 | 227.666667 | |
2015 | 199.000000 | |
2016 | 217.333333 | |
2017 | 232.333333 | |
서울 | 2013 | 218.142857 |
2014 | 224.714286 | |
2015 | 178.714286 | |
2016 | 199.000000 | |
2017 | 204.428571 |
- 데이터 파악에 쉽게 row index
unstack()
: 가장 낮은row label index
를column index
로
pop_data.groupby(['도시', '연도'])[['총인구']].mean().unstack()
총인구 | |||||
---|---|---|---|---|---|
연도 | 2013 | 2014 | 2015 | 2016 | 2017 |
도시 | |||||
부산 | 201.000000 | 227.666667 | 199.000000 | 217.333333 | 232.333333 |
서울 | 218.142857 | 224.714286 | 178.714286 | 199.000000 | 204.428571 |
'도시'
row label indexunstack()
: MultiIndex의 0번째 index 올림:unstack(0)
pop_data.groupby(['도시', '연도'])[['총인구']].mean().unstack(0)
총인구 | ||
---|---|---|
도시 | 부산 | 서울 |
연도 | ||
2013 | 201.000000 | 218.142857 |
2014 | 227.666667 | 224.714286 |
2015 | 199.000000 | 178.714286 |
2016 | 217.333333 | 199.000000 |
2017 | 232.333333 | 204.428571 |
6.통계¶
주요 통계 함수
obj.value_count()
: 각 고유값의 중복개수obj.count()
: NaN 값을 제외한 값의 개수obj.describe()
: 각 컬럼에 대한 기술통계-요약통계 계산(count, mean, std, min, 1사분위수, 중위값, 3사분위수, max)obj.min()
,obj.max()
: 최소, 최대 값obj.sum()
: 총 합obj.cumsum()
: 누적합obj.mean()
: 평균obj.median()
: 중위값, 전체 데이터를 나열 했을 때 중간에 위치한 값obj.var()
: 분산, $\sigma^2$, 데이터가 전체적으로 흩어진 정도, 편차제곱의 평균obj.std()
: 표준편차, 분산의 양의 제곱근: $\sigma$
주요 parameter
axis
: 연산의 기준이 되는 축, default:axis=0
> 행의 축 방향($\downarrow$),axis=1
> 열의 축 방향($\rightarrow$)skipna
: NaN 값을 제외할지 여부를 설정, default:skipna=True
my_index = pd.Index(['Kim', 'Park', 'Lee', 'Jung', 'Moon'], name='학생명')
my_columns = pd.MultiIndex.from_product([[2016, 2017], ['영어', '수학']],
names=['연도', '과목'])
df_score = pd.DataFrame(np.random.randint(50, 100, (5, 4)),
index=my_index, columns=my_columns)
df_score
연도 | 2016 | 2017 | ||
---|---|---|---|---|
과목 | 영어 | 수학 | 영어 | 수학 |
학생명 | ||||
Kim | 59 | 54 | 53 | 54 |
Park | 89 | 56 | 90 | 82 |
Lee | 53 | 93 | 72 | 94 |
Jung | 92 | 67 | 77 | 83 |
Moon | 93 | 72 | 65 | 63 |
obj.describe()
: 기술통계-요약통계
df_score.describe()
연도 | 2016 | 2017 | ||
---|---|---|---|---|
과목 | 영어 | 수학 | 영어 | 수학 |
count | 5.000000 | 5.000000 | 5.000000 | 5.000000 |
mean | 77.200000 | 68.400000 | 71.400000 | 75.200000 |
std | 19.524344 | 15.662056 | 13.758634 | 16.269604 |
min | 53.000000 | 54.000000 | 53.000000 | 54.000000 |
25% | 59.000000 | 56.000000 | 65.000000 | 63.000000 |
50% | 89.000000 | 67.000000 | 72.000000 | 82.000000 |
75% | 92.000000 | 72.000000 | 77.000000 | 83.000000 |
max | 93.000000 | 93.000000 | 90.000000 | 94.000000 |
'2017'
column index만 분리해서 저장
df_2017 = df_score[[2017]].copy()
df_2017
연도 | 2017 | |
---|---|---|
과목 | 영어 | 수학 |
학생명 | ||
Kim | 53 | 54 |
Park | 90 | 82 |
Lee | 72 | 94 |
Jung | 77 | 83 |
Moon | 65 | 63 |
df_2017.shape
(5, 2)
obj.count()
:NaN
을 제외한 data의 개수
축 기준 설정: default:
axis=0
:행의 축 방향, 열별 행 개수axis=1
: 열의 축 방향, 행별 열 개수
df_2017.count()
연도 과목 2017 영어 5 수학 5 dtype: int64
df_2017.count(axis=1)
학생명 Kim 2 Park 2 Lee 2 Jung 2 Moon 2 dtype: int64
- 엑셀 데이터(
.xlsx
) Loading
pop_data = pd.read_excel('data/인구수예제.xlsx')
pop_data
도시 | 자치구 | 연도 | 남자인구 | 여자인구 | 총인구 | |
---|---|---|---|---|---|---|
0 | 서울 | 강남구 | 2013 | 73 | 92 | 165 |
1 | 서울 | 강남구 | 2014 | 139 | 55 | 194 |
2 | 서울 | 강남구 | 2015 | 123 | 83 | 206 |
3 | 서울 | 강남구 | 2016 | 147 | 150 | 297 |
4 | 서울 | 강남구 | 2017 | 57 | 133 | 190 |
5 | 서울 | 서대문구 | 2013 | 95 | 111 | 206 |
6 | 서울 | 서대문구 | 2014 | 149 | 150 | 299 |
7 | 서울 | 서대문구 | 2015 | 106 | 77 | 183 |
8 | 서울 | 서대문구 | 2016 | 56 | 109 | 165 |
9 | 서울 | 서대문구 | 2017 | 82 | 96 | 178 |
10 | 서울 | 종로구 | 2013 | 121 | 68 | 189 |
11 | 서울 | 종로구 | 2014 | 107 | 55 | 162 |
12 | 서울 | 종로구 | 2015 | 50 | 79 | 129 |
13 | 서울 | 종로구 | 2016 | 100 | 80 | 180 |
14 | 서울 | 종로구 | 2017 | 105 | 91 | 196 |
15 | 서울 | 영등포구 | 2013 | 146 | 113 | 259 |
16 | 서울 | 영등포구 | 2014 | 127 | 117 | 244 |
17 | 서울 | 영등포구 | 2015 | 70 | 72 | 142 |
18 | 서울 | 영등포구 | 2016 | 141 | 136 | 277 |
19 | 서울 | 영등포구 | 2017 | 145 | 124 | 269 |
20 | 서울 | 송파구 | 2013 | 90 | 130 | 220 |
21 | 서울 | 송파구 | 2014 | 121 | 66 | 187 |
22 | 서울 | 송파구 | 2015 | 62 | 121 | 183 |
23 | 서울 | 송파구 | 2016 | 80 | 92 | 172 |
24 | 서울 | 송파구 | 2017 | 62 | 150 | 212 |
25 | 서울 | 도봉구 | 2013 | 113 | 138 | 251 |
26 | 서울 | 도봉구 | 2014 | 145 | 140 | 285 |
27 | 서울 | 도봉구 | 2015 | 56 | 139 | 195 |
28 | 서울 | 도봉구 | 2016 | 60 | 71 | 131 |
29 | 서울 | 도봉구 | 2017 | 111 | 62 | 173 |
30 | 서울 | 동작구 | 2013 | 120 | 117 | 237 |
31 | 서울 | 동작구 | 2014 | 94 | 108 | 202 |
32 | 서울 | 동작구 | 2015 | 74 | 139 | 213 |
33 | 서울 | 동작구 | 2016 | 87 | 84 | 171 |
34 | 서울 | 동작구 | 2017 | 79 | 134 | 213 |
35 | 부산 | 해운대구 | 2013 | 124 | 103 | 227 |
36 | 부산 | 해운대구 | 2014 | 101 | 144 | 245 |
37 | 부산 | 해운대구 | 2015 | 115 | 70 | 185 |
38 | 부산 | 해운대구 | 2016 | 134 | 126 | 260 |
39 | 부산 | 해운대구 | 2017 | 146 | 72 | 218 |
40 | 부산 | 수영구 | 2013 | 134 | 94 | 228 |
41 | 부산 | 수영구 | 2014 | 74 | 138 | 212 |
42 | 부산 | 수영구 | 2015 | 69 | 81 | 150 |
43 | 부산 | 수영구 | 2016 | 81 | 148 | 229 |
44 | 부산 | 수영구 | 2017 | 144 | 98 | 242 |
45 | 부산 | 동래구 | 2013 | 83 | 65 | 148 |
46 | 부산 | 동래구 | 2014 | 139 | 87 | 226 |
47 | 부산 | 동래구 | 2015 | 147 | 115 | 262 |
48 | 부산 | 동래구 | 2016 | 61 | 102 | 163 |
49 | 부산 | 동래구 | 2017 | 132 | 105 | 237 |
obj.value_counts()
: 범주형 데이터(문자열 등)에 대한 각 고유값의 개수
pop_data['도시'].value_counts()
서울 35 부산 15 Name: 도시, dtype: int64
obj.sum()
: 해당 열, 행의 총합을 계산- default:
axis=0
: 행의 축 방향, column별 총합,axis=1
: 열의 축 방향, row별 총합
- default:
# axis=0: 과목별 총합
df_2017.sum()
연도 과목 2017 영어 357 수학 376 dtype: int64
# axis=1: 학생별 총합
df_2017.sum(axis=1)
학생명 Kim 107 Park 172 Lee 166 Jung 160 Moon 128 dtype: int64
obj.mean()
: 해당 열, 행의 평균- default:
axis=0
: 행의 축 방향, 열별 평균,axis=1
: 열의 축 방향, 행별 평균
- default:
# default: axis=0: 과목별 평균
df_2017.mean()
연도 과목 2017 영어 71.4 수학 75.2 dtype: float64
# axis=1: 학생별 평균
df_2017.mean(axis=1)
학생명 Kim 53.5 Park 86.0 Lee 83.0 Jung 80.0 Moon 64.0 dtype: float64
> 연습문제¶
df_score
연도 | 2016 | 2017 | ||
---|---|---|---|---|
과목 | 영어 | 수학 | 영어 | 수학 |
학생명 | ||||
Kim | 59 | 54 | 53 | 54 |
Park | 89 | 56 | 90 | 82 |
Lee | 53 | 93 | 72 | 94 |
Jung | 92 | 67 | 77 | 83 |
Moon | 93 | 72 | 65 | 63 |
- 2016, 2017년도별, 과목별 평균 성적
df_mean = df_score[[2016, 2017]].mean(axis=0)
df_mean
연도 과목 2016 영어 77.2 수학 68.4 2017 영어 71.4 수학 75.2 dtype: float64
1번
결과의 년도별, 과목별 평균의 row > 연도, column > 과목이 되도록 수정
df_mean.unstack(1)
과목 | 수학 | 영어 |
---|---|---|
연도 | ||
2016 | 68.4 | 77.2 |
2017 | 75.2 | 71.4 |
- 학생별 전체 평균
df_score.mean(axis=1)
학생명 Kim 55.00 Park 79.25 Lee 78.00 Jung 79.75 Moon 73.25 dtype: float64
7. 날짜 형식¶
7.1. 날짜 데이터: str 타입¶
str_date = ['2022/11/01', '2022.10.31', '2021-10-09']
# Series로 저장
pd.Series(str_date)
0 2022/11/01 1 2022.10.31 2 2021-10-09 dtype: object
- str 타입을
datetime
타입으로 변환 후 pandas 저장
pd.to_datetime()
pd.to_datetime(str_date)
DatetimeIndex(['2022-11-01', '2022-10-31', '2021-10-09'], dtype='datetime64[ns]', freq=None)
type(pd.to_datetime(str_date))
pandas.core.indexes.datetimes.DatetimeIndex
- str 타입으로 저장 후 data type 변경
Series.dtype
: dtype 확인Series.astype()
: dtype 변경
pd.Series(str_date).astype('datetime64')
0 2022-11-01 1 2022-10-31 2 2021-10-09 dtype: datetime64[ns]
stamp_date = [1234000, 1256000, 1278000, 1290000, 1234567]
pd.Series(stamp_date)
0 1234000 1 1256000 2 1278000 3 1290000 4 1234567 dtype: int64
datetime
타입으로 변환 후 저장timestampe
의 기본unit=ns
(nano seconds) 나노세컨즈: 10억분의 1초- optional parameter
unit
default:ns
, days:D
, seconds :s
, milli seconds:ms
, micro seconds:us
pd.Series(pd.to_datetime(stamp_date))
0 1970-01-01 00:00:00.001234000 1 1970-01-01 00:00:00.001256000 2 1970-01-01 00:00:00.001278000 3 1970-01-01 00:00:00.001290000 4 1970-01-01 00:00:00.001234567 dtype: datetime64[ns]
unit='s'
: 초
pd.Series(pd.to_datetime(stamp_date, unit='s'))
0 1970-01-15 06:46:40 1 1970-01-15 12:53:20 2 1970-01-15 19:00:00 3 1970-01-15 22:20:00 4 1970-01-15 06:56:07 dtype: datetime64[ns]
unit='D'
: 날짜 > 2038년 문제
pd.Series(pd.to_datetime(stamp_date, unit='D'))
--------------------------------------------------------------------------- OverflowError Traceback (most recent call last) ~\anaconda3\lib\site-packages\pandas\_libs\tslib.pyx in pandas._libs.tslib.array_with_unit_to_datetime() ~\anaconda3\lib\site-packages\pandas\_libs\tslibs\conversion.pyx in pandas._libs.tslibs.conversion.cast_from_unit() OverflowError: int too big to convert During handling of the above exception, another exception occurred: OutOfBoundsDatetime Traceback (most recent call last) ~\AppData\Local\Temp\ipykernel_596\2430875186.py in <module> ----> 1 pd.Series(pd.to_datetime(stamp_date, unit='D')) ~\anaconda3\lib\site-packages\pandas\core\tools\datetimes.py in to_datetime(arg, errors, dayfirst, yearfirst, utc, format, exact, unit, infer_datetime_format, origin, cache) 1074 result = _convert_and_box_cache(arg, cache_array) 1075 else: -> 1076 result = convert_listlike(arg, format) 1077 else: 1078 result = convert_listlike(np.array([arg]), format)[0] ~\anaconda3\lib\site-packages\pandas\core\tools\datetimes.py in _convert_listlike_datetimes(arg, format, name, tz, unit, errors, infer_datetime_format, dayfirst, yearfirst, exact) 355 if format is not None: 356 raise ValueError("cannot specify both format and unit") --> 357 return _to_datetime_with_unit(arg, unit, name, tz, errors) 358 elif getattr(arg, "ndim", 1) > 1: 359 raise TypeError( ~\anaconda3\lib\site-packages\pandas\core\tools\datetimes.py in _to_datetime_with_unit(arg, unit, name, tz, errors) 528 else: 529 arg = np.asarray(arg) --> 530 arr, tz_parsed = tslib.array_with_unit_to_datetime(arg, unit, errors=errors) 531 532 if errors == "ignore": ~\anaconda3\lib\site-packages\pandas\_libs\tslib.pyx in pandas._libs.tslib.array_with_unit_to_datetime() OutOfBoundsDatetime: cannot convert input 1234000 with the unit 'D'
unit='ms'
: 밀리세컨즈
pd.Series(pd.to_datetime(stamp_date, unit='ms'))
0 1970-01-01 00:20:34.000 1 1970-01-01 00:20:56.000 2 1970-01-01 00:21:18.000 3 1970-01-01 00:21:30.000 4 1970-01-01 00:20:34.567 dtype: datetime64[ns]
- default:
unit-='us'
: 나노세컨즈
pd.Series(pd.to_datetime(stamp_date, unit='us'))
0 1970-01-01 00:00:01.234000 1 1970-01-01 00:00:01.256000 2 1970-01-01 00:00:01.278000 3 1970-01-01 00:00:01.290000 4 1970-01-01 00:00:01.234567 dtype: datetime64[ns]
8. label 형식 통일¶
- data encoding 작업에 포함
map()
dict 타입으로 encoding map을 생성해서 적용
gender:
0
=남자,1
=여자
gender_df = pd.DataFrame({'gender':[0, 1, 0, 0, 0, 1]})
gender_map = {0:'Male', 1:'Female'}
gender_df
gender | |
---|---|
0 | 0 |
1 | 1 |
2 | 0 |
3 | 0 |
4 | 0 |
5 | 1 |
gender_df
변수의gender
column값을map
함수를 이용해0
은M
으로,1
은F
로 변환
gender_df['gender'].map(gender_map)
0 Male 1 Female 2 Male 3 Male 4 Male 5 Female Name: gender, dtype: object
- Python 내장함수
replace()
도 사용 가능
gender_df['gender'].replace(0, "Male").replace(1, "Female")
0 Male 1 Female 2 Male 3 Male 4 Male 5 Female Name: gender, dtype: object
gender_df['gender'].replace([0, 1], ['Male', 'Female'])
0 Male 1 Female 2 Male 3 Male 4 Male 5 Female Name: gender, dtype: object
gender_df['gender'].replace(gender_map)
0 Male 1 Female 2 Male 3 Male 4 Male 5 Female Name: gender, dtype: object
9. 문자 형식(대소문자, 기호 등) 통일¶
my_data = {'Name':['Jane', 'Albert', 'John'],
'Age':[18, 19, 21]}
my_df = pd.DataFrame(my_data)
my_df
Name | Age | |
---|---|---|
0 | Jane | 18 |
1 | Albert | 19 |
2 | John | 21 |
column name을 소문자로 바꾸는 방법:
str.lower()
빈 list에 소문자로 변경한 column을 모두 적재한 뒤 대입
my_df1 = my_df.copy()
new_cols = list()
for col in my_df.columns:
print(col.lower())
new_cols.append(col.lower())
name age
new_cols
['name', 'age']
my_df1.columns = new_cols
my_df1
name | age | |
---|---|---|
0 | Jane | 18 |
1 | Albert | 19 |
2 | John | 21 |
columns
에 바로upper()
적용 가능:df.columns.str.upper()
my_df2 = my_df.copy()
my_df2.columns = my_df2.columns.str.upper()
my_df2
NAME | AGE | |
---|---|---|
0 | Jane | 18 |
1 | Albert | 19 |
2 | John | 21 |
내부 item (
NAME
column)의 모든 data를 소문자로 통일column
age
: 정수 자료 > excludeobj.apply(method)
: 해당 method의 return value로 내부 data를 일괄적으로 변환
def change_lower(value):
return value.lower()
my_df2['NAME'].apply(change_lower)
0 jane 1 albert 2 john Name: NAME, dtype: object
.apply()
는map
으로 대체 가능
my_df2
NAME | AGE | |
---|---|---|
0 | Jane | 18 |
1 | Albert | 19 |
2 | John | 21 |
my_df2['NAME'].map(change_lower)
0 jane 1 albert 2 john Name: NAME, dtype: object
AGE
column의 value를 20기준으로 return하는is_adult()
함수 정의 후.apply()
로 적용
def is_adult(value: int) -> str :
if value >= 20:
return "성인"
else:
return "미성년자"
my_df2['AGE'].map(is_adult)
0 미성년자 1 미성년자 2 성인 Name: AGE, dtype: object
10. data value에 대한 처리¶
결측값(NaN)
이상치(예측 범위 밖의 value)
단순 중복 data
동일한 의미, 다른 명칭의 중복 data
중복 속성
- 다중공선성: 통계학의 회귀분석에서 독립변수들 간에 강한 상관관계가 나타나는 문제
불규칙한 data 수집(differs in step, unit)
- Data Loading
this_sample = pd.read_csv('data/csv_exam_nan.csv')
this_sample
math | english | science | |
---|---|---|---|
0 | 70.0 | NaN | NaN |
1 | 75.0 | 65.0 | 80.0 |
2 | NaN | NaN | NaN |
3 | 56.0 | 89.0 | NaN |
4 | 89.0 | 95.0 | 83.0 |
5 | 90.0 | 100.0 | 89.0 |
10.1. 결측치 처리 - 삭제, 선택¶
결측치
NaN
가 하나라도 있는 레코드 삭제모든 값이 결측인 레코드 삭제
결측치가 하나라도 있는 데이터만 선택
- 결측치가 하나 이상인 레코드(row) 삭제
df.dropna(how='any')
df.dropna()
parameter default:how='any'
> 하나라도NaN
이면 row 삭제optional parameter:
inplace=True or False
> 원본 data에 반영 여부 결정
this_sample.dropna()
math | english | science | |
---|---|---|---|
1 | 75.0 | 65.0 | 80.0 |
4 | 89.0 | 95.0 | 83.0 |
5 | 90.0 | 100.0 | 89.0 |
- 모든 값이
NaN
인 record만 삭제:how='all'
this_sample.dropna(how='all')
math | english | science | |
---|---|---|---|
0 | 70.0 | NaN | NaN |
1 | 75.0 | 65.0 | 80.0 |
3 | 56.0 | 89.0 | NaN |
4 | 89.0 | 95.0 | 83.0 |
5 | 90.0 | 100.0 | 89.0 |
3.결측치가 하나라도 있는 data만 선택 > 조건색인 활용
obj.isnull()
:NaN
인 cell은True
, 아닌 셀은False
로 출력
this_sample.isnull()
math | english | science | |
---|---|---|---|
0 | False | True | True |
1 | False | False | False |
2 | True | True | True |
3 | False | False | True |
4 | False | False | False |
5 | False | False | False |
obj.isnull().any(axis=0)
: 해당 column에isnull()
의 결과값이True
인 셀이 있는지 체크default:
axis=0
: column 단위 기준axis=1
: row 단위 기준
this_sample.isnull().any()
math True english True science True dtype: bool
this_sample.isnull().any(axis=1)
0 True 1 False 2 True 3 True 4 False 5 False dtype: bool
- column별
axis=0
결측치 개수 총합
this_sample.isnull().sum()
math 1 english 2 science 3 dtype: int64
- 결측치가 하나라도 있는 record(row) 선택
this_sample[this_sample.isnull().any(axis=1)]
math | english | science | |
---|---|---|---|
0 | 70.0 | NaN | NaN |
2 | NaN | NaN | NaN |
3 | 56.0 | 89.0 | NaN |
10.2. 결측치 처리 - 대체값¶
연속형 : 임의값(0 등...), mean, median, 예측값, 도메인지식 활용
명목형 : mode(최빈값), 예측값, 도메인지식 활용
연속형: 임의의 값으로 대체
df.fillna(value)
sample = this_sample
sample.fillna(0)
math | english | science | |
---|---|---|---|
0 | 70.0 | 0.0 | 0.0 |
1 | 75.0 | 65.0 | 80.0 |
2 | 0.0 | 0.0 | 0.0 |
3 | 56.0 | 89.0 | 0.0 |
4 | 89.0 | 95.0 | 83.0 |
5 | 90.0 | 100.0 | 89.0 |
obj.mean()
: 전체 데이터의 평균값df.mean()
: DataFrame의 column별 평균값,NaN
무시`
sample.mean()
math 76.00 english 87.25 science 84.00 dtype: float64
df.values.mean()
: arr타입 연산,NaN
값이 하나라도 있으면 결과도NaN
sample.values.mean()
: 전체 평균을 구할 수 있지만NaN
df.fillna(0)
: 결측치 보완 >obj.mean()
평균 구하기
tot_avg = sample.fillna(0).values.mean()
sample.fillna(tot_avg)
math | english | science | |
---|---|---|---|
0 | 70.0 | 54.5 | 54.5 |
1 | 75.0 | 65.0 | 80.0 |
2 | 54.5 | 54.5 | 54.5 |
3 | 56.0 | 89.0 | 54.5 |
4 | 89.0 | 95.0 | 83.0 |
5 | 90.0 | 100.0 | 89.0 |
obj.mean()
: 결측치가 존재하는 속성(column)의 평균 값df.mean()
: 컬럼별 평균 > indexing으로 과목별 평균 추출
print(sample.mean()[0])
print(sample.mean()[1])
print(sample.mean()[2])
76.0 87.25 84.0
math
column 지정 후 평균 구하기
# 컬럼 지정 후 평균 구하기
sample['math'].mean()
76.0
obj.fillna()
로 결측치 대신 각 column의 평균값 넣기
sample.columns
Index(['math', 'english', 'science'], dtype='object')
for col in sample.columns:
print(sample[col].fillna(sample[col].mean()))
0 70.0 1 75.0 2 76.0 3 56.0 4 89.0 5 90.0 Name: math, dtype: float64 0 87.25 1 65.00 2 87.25 3 89.00 4 95.00 5 100.00 Name: english, dtype: float64 0 84.0 1 80.0 2 84.0 3 84.0 4 83.0 5 89.0 Name: science, dtype: float64
obj.median()
: 전체 데이터에 대한 중위값Series
나DataFrame
은 벡터연산시 자동으로NaN
배제전체 데이터의 중위값을 구하기 위해 먼저
Series
로 바꿔줌obj.reshape(obj.size)
: 1차원 배열크기로 변경
sample_1dim = pd.Series(sample.values.reshape(sample.size))
sample_1dim
0 70.0 1 NaN 2 NaN 3 75.0 4 65.0 5 80.0 6 NaN 7 NaN 8 NaN 9 56.0 10 89.0 11 NaN 12 89.0 13 95.0 14 83.0 15 90.0 16 100.0 17 89.0 dtype: float64
sample_median = sample_1dim.median()
sample_median
86.0
sample.fillna(sample_median)
math | english | science | |
---|---|---|---|
0 | 70.0 | 86.0 | 86.0 |
1 | 75.0 | 65.0 | 80.0 |
2 | 86.0 | 86.0 | 86.0 |
3 | 56.0 | 89.0 | 86.0 |
4 | 89.0 | 95.0 | 83.0 |
5 | 90.0 | 100.0 | 89.0 |
mode
: 범주형 data에서 최빈값 사용obj.descrive()
: 통계분석, 기술통계obj.value_counts()
: 고유값(value)의 counter
df = pd.DataFrame({'label':['A', 'B', 'B', 'C', 'C', 'C', 'D']})
df
label | |
---|---|
0 | A |
1 | B |
2 | B |
3 | C |
4 | C |
5 | C |
6 | D |
obj.describe()
: 범주형 데이터 통계분석시count
: 총 데이터 item의 개수unique
: 고유값(value)이 몇 개인지top
: 가장 많이 존재하는 itemfreq
:top
item의 빈도(개수)
df.describe()
label | |
---|---|
count | 7 |
unique | 4 |
top | C |
freq | 3 |
column label
지정:Series
추출obj.value_counts
: 각 범주형 data별 개수 추출
df.label.value_counts()
C 3 B 2 A 1 D 1 Name: label, dtype: int64
from collections import Counter
collections
libraryCounter
importCounter()
를 이용해서Counter
type data 생성Counter.most_common()
: return[(value1, count1), (value2, count2), ...]
colors = ['red', 'blue', 'pink', 'blue', 'blue', 'red']
counter = Counter(colors)
counter
Counter({'red': 2, 'blue': 3, 'pink': 1})
counter.most_common()
[('blue', 3), ('red', 2), ('pink', 1)]
DataFrame.column
을Counter()
의 parameter로 사용 가능
Counter(df.label).most_common()
[('C', 3), ('B', 2), ('A', 1), ('D', 1)]
표준화 : (요소값(하나의 데이터) - 평균) / 표준편차
몸무게 vs 키
표준화 결과 : 몸무게 < 0, 키 > 0
- 해석 : 몸무게는 평균 이하, 키는 평균 이상
- 전처리 기능 제공
sklearn
library 및 module 가져오기
from sklearn.preprocessing import scale, minmax_scale
- $-3 \leq x \leq 5$인 정수 x를 가지는 9 X 1 배열 생성
arr_x = (np.arange(9)-3).reshape(-1, 1)
arr_x
array([[-3], [-2], [-1], [ 0], [ 1], [ 2], [ 3], [ 4], [ 5]])
arr_x
,scale(arr_x)
,minmax_scale(arr_x)
를 column으로 가지는DataFrame
생성
type(arr_x)
numpy.ndarray
scale(arr_x)
array([[-1.54919334], [-1.161895 ], [-0.77459667], [-0.38729833], [ 0. ], [ 0.38729833], [ 0.77459667], [ 1.161895 ], [ 1.54919334]])
minmax_scale(arr_x)
array([[0. ], [0.125], [0.25 ], [0.375], [0.5 ], [0.625], [0.75 ], [0.875], [1. ]])
np.hstack([obj1, obj2, ...])
: 가로축 방향으로 붙임np.vstack([obj1, obj2, ...])
: 세로축 방향으로 붙임
my_df = pd.DataFrame(np.hstack([arr_x, scale(arr_x), minmax_scale(arr_x)]),
columns=['arr_x', 'scale', 'minmax_scale'])
my_df
arr_x | scale | minmax_scale | |
---|---|---|---|
0 | -3.0 | -1.549193 | 0.000 |
1 | -2.0 | -1.161895 | 0.125 |
2 | -1.0 | -0.774597 | 0.250 |
3 | 0.0 | -0.387298 | 0.375 |
4 | 1.0 | 0.000000 | 0.500 |
5 | 2.0 | 0.387298 | 0.625 |
6 | 3.0 | 0.774597 | 0.750 |
7 | 4.0 | 1.161895 | 0.875 |
8 | 5.0 | 1.549193 | 1.000 |
my_df.std()
arr_x 2.738613 scale 1.060660 minmax_scale 0.342327 dtype: float64
'CS & DS > Numpy & Pandas' 카테고리의 다른 글
Pandas Data visualization with matplotlib 판다스 데이터 시각화 (0) | 2022.11.12 |
---|---|
Pandas Data analysis with Baseball player 판다스 야구 선수 데이터 분석 (0) | 2022.11.12 |
Pandas Data Loading 판다스 데이터 적재 (0) | 2022.11.05 |
Pandas DataFrame 판다스 데이터프레임 (0) | 2022.11.05 |
Pandas Series 판다스 시리즈 (0) | 2022.11.03 |