40 분 소요

Pandas (3)

8. 데이터 정제 및 준비

import pandas as pd
import numpy as np

8.2 데이터 변형

  • 중복 제거하기
data = pd.DataFrame({'k1' : ['one', 'two'] * 3 + ['two'],
                     'k2' : [1, 1, 2, 3, 3, 4, 4]} )
data
k1 k2
0 one 1
1 two 1
2 one 2
3 two 3
4 one 3
5 two 4
6 two 4
data.duplicated(keep='first') # keep='first' (기본값값)
0    False
1    False
2    False
3    False
4    False
5    False
6     True
dtype: bool
data.duplicated(keep='last')
0    False
1    False
2    False
3    False
4    False
5     True
6    False
dtype: bool
data.duplicated(['k1'])
0    False
1    False
2     True
3     True
4     True
5     True
6     True
dtype: bool
# 중복 삭제
data.drop_duplicates()
k1 k2
0 one 1
1 two 1
2 one 2
3 two 3
4 one 3
5 two 4
# k1 열 기준으로 삭제제
data.drop_duplicates(['k1'])
k1 k2
0 one 1
1 two 1
data.drop_duplicates(['k1'], keep='last')
k1 k2
4 one 3
6 two 4
data['v1'] = range(7)
data
k1 k2 v1
0 one 1 0
1 two 1 1
2 one 2 2
3 two 3 3
4 one 3 4
5 two 4 5
6 two 4 6
data.duplicated()
0    False
1    False
2    False
3    False
4    False
5    False
6    False
dtype: bool
data.drop_duplicates(['k1', 'k2'])
k1 k2 v1
0 one 1 0
1 two 1 1
2 one 2 2
3 two 3 3
4 one 3 4
5 two 4 5
  • 함수나 매핑을 이용해서 데이터 변형하기
data = pd.DataFrame({'food': ['bacon', 'pulled pork', 'bacon',
                              'Pastrami', 'corned beef', 'Bacon',
                              'pastrami', 'honey ham', 'nova lox'],
                     'ounces': [4, 3, 12, 6, 7.5, 8, 3, 5, 6]})
data
food ounces
0 bacon 4.0
1 pulled pork 3.0
2 bacon 12.0
3 Pastrami 6.0
4 corned beef 7.5
5 Bacon 8.0
6 pastrami 3.0
7 honey ham 5.0
8 nova lox 6.0
meat_to_animal = {
  'bacon': 'pig',
  'pulled pork': 'pig',
  'pastrami': 'cow',
  'corned beef': 'cow',
  'honey ham': 'pig',
  'nova lox': 'salmon'
}
"ABC".lower()
'abc'
lowercased = data['food'].str.lower()
lowercased
0          bacon
1    pulled pork
2          bacon
3       pastrami
4    corned beef
5          bacon
6       pastrami
7      honey ham
8       nova lox
Name: food, dtype: object
data['animal']= lowercased.map(meat_to_animal)
  • 값 치환하기
data = pd.Series([1, -999, 2, -999, -1000, 3])
data
0       1
1    -999
2       2
3    -999
4   -1000
5       3
dtype: int64
data.replace(-999, np.nan)
0       1.0
1       NaN
2       2.0
3       NaN
4   -1000.0
5       3.0
dtype: float64
data.replace([-999, -1000], np.nan)
0    1.0
1    NaN
2    2.0
3    NaN
4    NaN
5    3.0
dtype: float64
data.replace({-999:np.nan, -1000:0})
0    1.0
1    NaN
2    2.0
3    NaN
4    0.0
5    3.0
dtype: float64
  • 축 색인 이름 바꾸기
data = pd.DataFrame(np.arange(12).reshape(3, 4),
                   index=['Ohio', 'Colorado', 'New York'],
                   columns=['one', 'two', 'three', 'four'])
data
one two three four
Ohio 0 1 2 3
Colorado 4 5 6 7
New York 8 9 10 11
data.index
Index(['Ohio', 'Colorado', 'New York'], dtype='object')
def trans_upper(x):
  return x.upper()

data.index.map(trans_upper)  
Index(['OHIO', 'COLORADO', 'NEW YORK'], dtype='object')
data.index.map(lambda x:x.upper())
Index(['OHIO', 'COLORADO', 'NEW YORK'], dtype='object')
data.index.map(lambda x:x.title())
Index(['Ohio', 'Colorado', 'New York'], dtype='object')
data.rename(index = str.lower, columns= str.title) # rename 함수의 index/columns 에 함수를 적용할 수 있음
One Two Three Four
ohio 0 1 2 3
colorado 4 5 6 7
new york 8 9 10 11
data
one two three four
Ohio 0 1 2 3
Colorado 4 5 6 7
New York 8 9 10 11
  • 벡터화된 문자열 함수
data = {'Dave':'dave@gmail.com',
        'Steve': 'steve@gmail.com',
        'Rob':'rob@gmail.com',
        'Wes':np.nan,
        'Puppy':'p',
        'Number':'123'}
sr_data= pd.Series(data)        
sr_data
Dave       dave@gmail.com
Steve     steve@gmail.com
Rob         rob@gmail.com
Wes                   NaN
Puppy                   p
Number                123
dtype: object
'dave@gmail.com'.upper()
'DAVE@GMAIL.COM'
sr_data.str.upper()
Dave       DAVE@GMAIL.COM
Steve     STEVE@GMAIL.COM
Rob         ROB@GMAIL.COM
Wes                   NaN
Puppy                   P
Number                123
dtype: object
'123'.isnumeric()
True
'dave@gmail.com'.isnumeric()
False
sr_data.str.isnumeric()
Dave      False
Steve     False
Rob       False
Wes         NaN
Puppy     False
Number     True
dtype: object
sr_data.str.isalpha()
Dave      False
Steve     False
Rob       False
Wes         NaN
Puppy      True
Number    False
dtype: object
sr_data.str.contains('gmail')
Dave       True
Steve      True
Rob        True
Wes         NaN
Puppy     False
Number    False
dtype: object
  • 데이터 구간 분할
# 수치데이터(양적데이터) -> 범주형데이터(질적데이터터)

ages = [18, 20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32]
ages
[18, 20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32]
cats = pd.cut(ages, 4) # 범위 안에서 4구간으로 나눌 수 있음음
cats
bins= [18, 25, 35, 60, 100]
cats = pd.cut(ages, bins) # bins를 통해 원하는 구간을 지정할 수 있음음
cats
bins= [18, 25, 35, 60, 100]
cats = pd.cut(ages, bins, include_lowest=True) # 가장 작은수가 포함시키는 옵션션
cats
[(17.999, 25.0], (17.999, 25.0], (17.999, 25.0], (17.999, 25.0], (25.0, 35.0], ..., (25.0, 35.0], (60.0, 100.0], (35.0, 60.0], (35.0, 60.0], (25.0, 35.0]]
Length: 13
Categories (4, interval[float64, right]): [(17.999, 25.0] < (25.0, 35.0] < (35.0, 60.0] <
                                           (60.0, 100.0]]
cats = pd.cut(ages, bins, include_lowest=True, labels=['youth', 'youngadult', 'middleages', 'senior'])
cats
['youth', 'youth', 'youth', 'youth', 'youngadult', ..., 'youngadult', 'senior', 'middleages', 'middleages', 'youngadult']
Length: 13
Categories (4, object): ['youth' < 'youngadult' < 'middleages' < 'senior']
cats.value_counts() # 범주형 데이터로 변환되었기 때문에 빈도수도 카운트 할 수 있음음
youth         6
youngadult    3
middleages    3
senior        1
dtype: int64
cats = pd.cut(ages, 4) # 범위 안에서 4구간으로 나눌 수 있음
cats.value_counts()
(17.957, 28.75]    7
(28.75, 39.5]      3
(39.5, 50.25]      2
(50.25, 61.0]      1
dtype: int64
cats = pd.qcut(ages, 4) # 4구간안에 동일한 양이 들어가도록 분할
cats.value_counts()
(17.999, 22.0]    4
(22.0, 27.0]      3
(27.0, 37.0]      3
(37.0, 61.0]      3
dtype: int64
  • 특이값(바깥값, outlier) 찾고 제외하기
data = pd.DataFrame(np.random.randn(1000, 4))
data.describe()
0 1 2 3
count 1000.000000 1000.000000 1000.000000 1000.000000
mean -0.073027 -0.039069 -0.025754 -0.033337
std 1.019392 0.991063 0.979328 0.977642
min -4.479930 -3.135338 -3.763374 -3.288864
25% -0.761516 -0.672036 -0.667080 -0.659778
50% -0.077066 -0.033668 -0.001968 -0.003941
75% 0.637678 0.637472 0.604178 0.677430
max 2.931344 3.449874 3.090328 3.284176
# 3보다 큰 값을 특잇값(바깥값, outlier)로 가정하고, 해당되는 값을 3으로 치환환
data > 3
0 1 2 3
0 False False False False
1 False False False False
2 False False False False
3 False False False False
4 False False False False
... ... ... ... ...
995 False False False False
996 False False False False
997 False False False False
998 False False False False
999 False False False False

1000 rows × 4 columns

(data > 3).any(axis=1) # 열축을 따라서 True 값이 하나라도 있는지 확인
0      False
1      False
2      False
3      False
4      False
       ...  
995    False
996    False
997    False
998    False
999    False
Length: 1000, dtype: bool
(data > 3).any(axis=1).sum()
3
data[(data > 3).any(axis=1)]
0 1 2 3
84 -1.034572 3.449874 1.025486 -0.294470
704 -2.300875 -0.342656 3.090328 0.381429
860 -1.471528 0.187926 0.499964 3.284176
data[data > 3] = 3
data.describe()
0 1 2 3
count 1000.000000 1000.000000 1000.000000 1000.000000
mean -0.073027 -0.039519 -0.025844 -0.033622
std 1.019392 0.989579 0.979044 0.976717
min -4.479930 -3.135338 -3.763374 -3.288864
25% -0.761516 -0.672036 -0.667080 -0.659778
50% -0.077066 -0.033668 -0.001968 -0.003941
75% 0.637678 0.637472 0.604178 0.677430
max 2.931344 3.000000 3.000000 3.000000
  • 더미변수 계산하기(one-hot encoding)
df = pd.DataFrame({'fruit' : ['apple', 'apple', 'pear', 'peach', 'pear'],
                   'data' : range(5)})
df
fruit data
0 apple 0
1 apple 1
2 pear 2
3 peach 3
4 pear 4
dummies = pd.get_dummies(df['fruit'], prefix='fruit')
dummies
fruit_apple fruit_peach fruit_pear
0 1 0 0
1 1 0 0
2 0 0 1
3 0 1 0
4 0 0 1
df[['data']]
data
0 0
1 1
2 2
3 3
4 4
pd.concat([dummies, df[['data']]], axis=1)
fruit_apple fruit_peach fruit_pear data
0 1 0 0 0
1 1 0 0 1
2 0 0 1 2
3 0 1 0 3
4 0 0 1 4

9. 데이터 재구성

9.1 계층적 색인

data = pd.Series(np.random.randn(9),
                 index = [['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd'],
                          [1, 2, 3, 1, 3, 1, 2, 2, 3]])
data
a  1    0.759512
   2    2.266371
   3   -0.547481
b  1    0.900922
   3   -1.452136
c  1    0.321089
   2   -0.123710
d  2    0.133820
   3   -1.512736
dtype: float64
data.index
MultiIndex([('a', 1),
            ('a', 2),
            ('a', 3),
            ('b', 1),
            ('b', 3),
            ('c', 1),
            ('c', 2),
            ('d', 2),
            ('d', 3)],
           )
data.loc['b']
1    0.900922
3   -1.452136
dtype: float64
data.loc['b' : 'c'] # 라벨 색인
b  1    0.900922
   3   -1.452136
c  1    0.321089
   2   -0.123710
dtype: float64
data.iloc[3: 7] # 정수 색인
b  1    0.900922
   3   -1.452136
c  1    0.321089
   2   -0.123710
dtype: float64
data # index가 쌓여있는 상태(stack)
a  1    0.759512
   2    2.266371
   3   -0.547481
b  1    0.900922
   3   -1.452136
c  1    0.321089
   2   -0.123710
d  2    0.133820
   3   -1.512736
dtype: float64
unstacked_data = data.unstack()
unstacked_data
1 2 3
a 0.759512 2.266371 -0.547481
b 0.900922 NaN -1.452136
c 0.321089 -0.123710 NaN
d NaN 0.133820 -1.512736
stacked_data = unstacked_data.stack()
stacked_data
a  1    0.759512
   2    2.266371
   3   -0.547481
b  1    0.900922
   3   -1.452136
c  1    0.321089
   2   -0.123710
d  2    0.133820
   3   -1.512736
dtype: float64
stacked_data.unstack()
1 2 3
a 0.759512 2.266371 -0.547481
b 0.900922 NaN -1.452136
c 0.321089 -0.123710 NaN
d NaN 0.133820 -1.512736
unstacked_data.reset_index()
index 1 2 3
0 a 0.759512 2.266371 -0.547481
1 b 0.900922 NaN -1.452136
2 c 0.321089 -0.123710 NaN
3 d NaN 0.133820 -1.512736
stacked_data.reset_index()
level_0 level_1 0
0 a 1 0.759512
1 a 2 2.266371
2 a 3 -0.547481
3 b 1 0.900922
4 b 3 -1.452136
5 c 1 0.321089
6 c 2 -0.123710
7 d 2 0.133820
8 d 3 -1.512736

9.2 데이터 합치기

  • 데이터베이스 스타일로 DataFrame 합치기

  • inner join

df1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],
                    'data1': range(7)})
df2 = pd.DataFrame({'key': ['a', 'b', 'd'],
                    'data2': range(3)})
df1
key data1
0 b 0
1 b 1
2 a 2
3 c 3
4 a 4
5 a 5
6 b 6
df2
key data2
0 a 0
1 b 1
2 d 2
pd.merge(df1, df2, on='key', how='inner')
key data1 data2
0 b 0 1
1 b 1 1
2 b 6 1
3 a 2 0
4 a 4 0
5 a 5 0
# 위의 merge 함수 사용법은 아래 query문과 같음
# SELECT a.key, data1, data2
#   FROM df1 a
#   INNER JOIN df2
#     ON a.key = b.key;
pd.merge(df1, df2, on='key') # how='inner'가 기본값값
key data1 data2
0 b 0 1
1 b 1 1
2 b 6 1
3 a 2 0
4 a 4 0
5 a 5 0
df3 = pd.DataFrame({'lkey': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7)})
df4 = pd.DataFrame({'rkey': ['a', 'b', 'd'], 'data2': range(3)})
df3
lkey data1
0 b 0
1 b 1
2 a 2
3 c 3
4 a 4
5 a 5
6 b 6
df4
rkey data2
0 a 0
1 b 1
2 d 2
pd.merge(df3, df4, left_on= 'lkey', right_on='rkey')
lkey data1 rkey data2
0 b 0 b 1
1 b 1 b 1
2 b 6 b 1
3 a 2 a 0
4 a 4 a 0
5 a 5 a 0
# 위의 merge 함수 사용법은 아래 query문과 같음
# SELECT a.lkey, data1, b.rkey, data2
#   FROM df3 a
#   INNER JOIN df4
#     ON a.lkey = b.rkey;
  • outer join
df1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],
                    'data1': range(7)})
df2 = pd.DataFrame({'key': ['a', 'b', 'd'],
                    'data2': range(3)})
df1
key data1
0 b 0
1 b 1
2 a 2
3 c 3
4 a 4
5 a 5
6 b 6
df2
key data2
0 a 0
1 b 1
2 d 2
pd.merge(df1, df2, on='key', how='left')
key data1 data2
0 b 0 1.0
1 b 1 1.0
2 a 2 0.0
3 c 3 NaN
4 a 4 0.0
5 a 5 0.0
6 b 6 1.0
pd.merge(df1, df2, how='left') # join할 대상의 컬럼명이 같으면 on 파라미터 생략 가능 (natural join)
key data1 data2
0 b 0 1.0
1 b 1 1.0
2 a 2 0.0
3 c 3 NaN
4 a 4 0.0
5 a 5 0.0
6 b 6 1.0
pd.merge(df1, df2, how='right')
key data1 data2
0 a 2.0 0
1 a 4.0 0
2 a 5.0 0
3 b 0.0 1
4 b 1.0 1
5 b 6.0 1
6 d NaN 2
# df의 위치만 변경시키면 위의 right join과 동일
pd.merge(df2, df1, how='left')
key data2 data1
0 a 0 2.0
1 a 0 4.0
2 a 0 5.0
3 b 1 0.0
4 b 1 1.0
5 b 1 6.0
6 d 2 NaN
pd.merge(df1, df2, how='outer') # left, right를 모두 포함한 join (한쪽에만 있는 데이터도 모두 취함)
key data1 data2
0 b 0.0 1.0
1 b 1.0 1.0
2 b 6.0 1.0
3 a 2.0 0.0
4 a 4.0 0.0
5 a 5.0 0.0
6 c 3.0 NaN
7 d NaN 2.0
  • 색인 병합하기
left1 = pd.DataFrame({'key': ['a', 'b', 'a', 'a', 'b', 'c'], 'value': range(6)})
right1 = pd.DataFrame({'group_val': [3.5, 7]}, index=['a', 'b'])
left1
key value
0 a 0
1 b 1
2 a 2
3 a 3
4 b 4
5 c 5
right1
group_val
a 3.5
b 7.0
pd.merge(left1, right1, left_on='key', right_index=True) # inner join
key value group_val
0 a 0 3.5
2 a 2 3.5
3 a 3 3.5
1 b 1 7.0
4 b 4 7.0
pd.merge(left1, right1, left_on='key', right_index=True, how='outer') # outer join
key value group_val
0 a 0 3.5
2 a 2 3.5
3 a 3 3.5
1 b 1 7.0
4 b 4 7.0
5 c 5 NaN
left2 = pd.DataFrame([[1., 2.], [3., 4.], [5., 6.]],
                     index=['a', 'c', 'e'],
                     columns=['Ohio', 'Nevada'])
right2 = pd.DataFrame([[7., 8.], [9., 10.], [11., 12.], [13, 14]],
                      index=['b', 'c', 'd', 'e'],
                      columns=['Missouri', 'Alabama'])
left2
Ohio Nevada
a 1.0 2.0
c 3.0 4.0
e 5.0 6.0
right2
Missouri Alabama
b 7.0 8.0
c 9.0 10.0
d 11.0 12.0
e 13.0 14.0
pd.merge(left2, right2, left_index=True, right_index=True) # inner join
Ohio Nevada Missouri Alabama
c 3.0 4.0 9.0 10.0
e 5.0 6.0 13.0 14.0
# join 함수는 인덱스 값을 기준으로 조인을 함
# 위의 pd.merge 결과와 동일
left2.join(right2, how='inner') # join 함수의 how='left'가 기본값이므로 inner로 변경경

Ohio Nevada Missouri Alabama
c 3.0 4.0 9.0 10.0
e 5.0 6.0 13.0 14.0
left1
key value
0 a 0
1 b 1
2 a 2
3 a 3
4 b 4
5 c 5
right1
group_val
a 3.5
b 7.0
pd.merge(left1, right1, left_on='key', right_index=True, how='inner')
key value group_val
0 a 0 3.5
2 a 2 3.5
3 a 3 3.5
1 b 1 7.0
4 b 4 7.0
# join 함수를 사용해서 위와 동일하게 합치려면면
left1.join(right1, on='key', how='inner')
key value group_val
0 a 0 3.5
2 a 2 3.5
3 a 3 3.5
1 b 1 7.0
4 b 4 7.0
  • 축따라 이어붙이기

참고 np.concatenate

arr = np.arange(12).reshape(3, 4)
arr
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
np.concatenate([arr, arr], axis=0) # axis=0 기본값, 0번축을 따라서 이어붙임
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
np.concatenate([arr, arr], axis=1)
array([[ 0,  1,  2,  3,  0,  1,  2,  3],
       [ 4,  5,  6,  7,  4,  5,  6,  7],
       [ 8,  9, 10, 11,  8,  9, 10, 11]])
s1 = pd.Series([0, 1], index=['a', 'b'])
s2 = pd.Series([2, 3, 4], index=['c', 'd', 'e'])
s3 = pd.Series([5, 6], index=['f', 'g'])
s1
a    0
b    1
dtype: int64
s2
c    2
d    3
e    4
dtype: int64
s3
f    5
g    6
dtype: int64
pd.concat([s1, s2, s3], axis=0)
a    0
b    1
c    2
d    3
e    4
f    5
g    6
dtype: int64
pd.concat([s1, s2, s3], axis=1)
0 1 2
a 0.0 NaN NaN
b 1.0 NaN NaN
c NaN 2.0 NaN
d NaN 3.0 NaN
e NaN 4.0 NaN
f NaN NaN 5.0
g NaN NaN 6.0
df1 = pd.DataFrame(np.random.randn(3, 4), columns=['a', 'b', 'c', 'd'])
df2 = pd.DataFrame(np.random.randn(2, 3), columns=['b', 'd', 'a'])
df1
a b c d
0 -1.127909 1.862198 -1.044944 1.537435
1 -0.243453 -0.300529 2.783077 0.080733
2 -0.917728 -1.234895 -0.285104 3.605365
df2
b d a
0 -0.967257 0.747703 1.636920
1 0.947134 -0.868835 0.943723
pd.concat([df1, df2], axis=0)
a b c d
0 -1.127909 1.862198 -1.044944 1.537435
1 -0.243453 -0.300529 2.783077 0.080733
2 -0.917728 -1.234895 -0.285104 3.605365
0 1.636920 -0.967257 NaN 0.747703
1 0.943723 0.947134 NaN -0.868835
pd.concat([df1, df2], axis=0, ignore_index=True)
a b c d
0 -1.127909 1.862198 -1.044944 1.537435
1 -0.243453 -0.300529 2.783077 0.080733
2 -0.917728 -1.234895 -0.285104 3.605365
3 1.636920 -0.967257 NaN 0.747703
4 0.943723 0.947134 NaN -0.868835

Workshop

  • 축따라 이어붙이기
df1 = pd.DataFrame({'a': ['a0', 'a1', 'a2', 'a3'],
                    'b': ['b0', 'b1', 'b2', 'b3'],
                    'c': ['c0', 'c1', 'c2', 'c3']},
                    index=[0, 1, 2, 3])
 
df2 = pd.DataFrame({'a': ['a2', 'a3', 'a4', 'a5'],
                    'b': ['b2', 'b3', 'b4', 'b5'],
                    'c': ['c2', 'c3', 'c4', 'c5'],
                    'd': ['d2', 'd3', 'd4', 'd5']},
                    index=[2, 3, 4, 5])
df1
a b c
0 a0 b0 c0
1 a1 b1 c1
2 a2 b2 c2
3 a3 b3 c3
df2
a b c d
2 a2 b2 c2 d2
3 a3 b3 c3 d3
4 a4 b4 c4 d4
5 a5 b5 c5 d5
# 2개의 데이터프레임을 위, 아래 (행축으로) 이어붙이듯 연결하기
pd.concat([df1, df2], axis=0)
a b c d
0 a0 b0 c0 NaN
1 a1 b1 c1 NaN
2 a2 b2 c2 NaN
3 a3 b3 c3 NaN
2 a2 b2 c2 d2
3 a3 b3 c3 d3
4 a4 b4 c4 d4
5 a5 b5 c5 d5
# 인덱스를 재 설정 (ignore_index 사용용)
pd.concat([df1, df2], axis=0, ignore_index=True)
a b c d
0 a0 b0 c0 NaN
1 a1 b1 c1 NaN
2 a2 b2 c2 NaN
3 a3 b3 c3 NaN
4 a2 b2 c2 d2
5 a3 b3 c3 d3
6 a4 b4 c4 d4
7 a5 b5 c5 d5
# 2개의 데이터프레임을 좌, 우 (열축으로) 이어붙이듯 연결하기
pd.concat([df1, df2], axis=1)
a b c a b c d
0 a0 b0 c0 NaN NaN NaN NaN
1 a1 b1 c1 NaN NaN NaN NaN
2 a2 b2 c2 a2 b2 c2 d2
3 a3 b3 c3 a3 b3 c3 d3
4 NaN NaN NaN a4 b4 c4 d4
5 NaN NaN NaN a5 b5 c5 d5
sr = pd.Series(['e0', 'e1', 'e2', 'e3'], name='e')
df1
a b c
0 a0 b0 c0
1 a1 b1 c1
2 a2 b2 c2
3 a3 b3 c3
sr
0    e0
1    e1
2    e2
3    e3
Name: e, dtype: object
# df1과 sr을 좌, 우(열축으로) 이어붙이듯 연결하기
pd.concat([df1, sr], axis=1)
a b c e
0 a0 b0 c0 e0
1 a1 b1 c1 e1
2 a2 b2 c2 e2
3 a3 b3 c3 e3
  • 데이터베이스 스타일로 DataFrame 합치기
df1 = pd.read_excel('./examples/stock price.xlsx')
df2 = pd.read_excel('./examples/stock valuation.xlsx')
df1
id stock_name value price
0 128940 한미약품 59385.666667 421000
1 130960 CJ E&M 58540.666667 98900
2 138250 엔에스쇼핑 14558.666667 13200
3 139480 이마트 239230.833333 254500
4 142280 녹십자엠에스 468.833333 10200
5 145990 삼양사 82750.000000 82000
6 185750 종근당 40293.666667 100500
7 192400 쿠쿠홀딩스 179204.666667 177500
8 199800 툴젠 -2514.333333 115400
9 204210 모두투어리츠 3093.333333 3475
df2
id name eps bps per pbr
0 130960 CJ E&M 6301.333333 54068 15.695091 1.829178
1 136480 하림 274.166667 3551 11.489362 0.887074
2 138040 메리츠금융지주 2122.333333 14894 6.313806 0.899691
3 139480 이마트 18268.166667 295780 13.931338 0.860437
4 145990 삼양사 5741.000000 108090 14.283226 0.758627
5 161390 한국타이어 5648.500000 51341 7.453306 0.820007
6 181710 NHN엔터테인먼트 2110.166667 78434 30.755864 0.827447
7 185750 종근당 3990.333333 40684 25.185866 2.470259
8 204210 모두투어리츠 85.166667 5335 40.802348 0.651359
9 207940 삼성바이오로직스 4644.166667 60099 89.790059 6.938551
# id 를 조인 조건으로 해서 inner join
pd.merge(df1, df2, on='id', how='inner')
id stock_name value price name eps bps per pbr
0 130960 CJ E&M 58540.666667 98900 CJ E&M 6301.333333 54068 15.695091 1.829178
1 139480 이마트 239230.833333 254500 이마트 18268.166667 295780 13.931338 0.860437
2 145990 삼양사 82750.000000 82000 삼양사 5741.000000 108090 14.283226 0.758627
3 185750 종근당 40293.666667 100500 종근당 3990.333333 40684 25.185866 2.470259
4 204210 모두투어리츠 3093.333333 3475 모두투어리츠 85.166667 5335 40.802348 0.651359
pd.merge(df1, df2) # 양쪽 데이터프레임의 컬럼명이 id로 동일하므로 생략 가능
                   # merge 함수의 how='inner' 가 기본값이므로 생략 가능
id stock_name value price name eps bps per pbr
0 130960 CJ E&M 58540.666667 98900 CJ E&M 6301.333333 54068 15.695091 1.829178
1 139480 이마트 239230.833333 254500 이마트 18268.166667 295780 13.931338 0.860437
2 145990 삼양사 82750.000000 82000 삼양사 5741.000000 108090 14.283226 0.758627
3 185750 종근당 40293.666667 100500 종근당 3990.333333 40684 25.185866 2.470259
4 204210 모두투어리츠 3093.333333 3475 모두투어리츠 85.166667 5335 40.802348 0.651359
# id 를 조인 조건으로 해서 outer join
pd.merge(df1, df2, on='id', how='outer')
id stock_name value price name eps bps per pbr
0 128940 한미약품 59385.666667 421000.0 NaN NaN NaN NaN NaN
1 130960 CJ E&M 58540.666667 98900.0 CJ E&M 6301.333333 54068.0 15.695091 1.829178
2 138250 엔에스쇼핑 14558.666667 13200.0 NaN NaN NaN NaN NaN
3 139480 이마트 239230.833333 254500.0 이마트 18268.166667 295780.0 13.931338 0.860437
4 142280 녹십자엠에스 468.833333 10200.0 NaN NaN NaN NaN NaN
5 145990 삼양사 82750.000000 82000.0 삼양사 5741.000000 108090.0 14.283226 0.758627
6 185750 종근당 40293.666667 100500.0 종근당 3990.333333 40684.0 25.185866 2.470259
7 192400 쿠쿠홀딩스 179204.666667 177500.0 NaN NaN NaN NaN NaN
8 199800 툴젠 -2514.333333 115400.0 NaN NaN NaN NaN NaN
9 204210 모두투어리츠 3093.333333 3475.0 모두투어리츠 85.166667 5335.0 40.802348 0.651359
10 136480 NaN NaN NaN 하림 274.166667 3551.0 11.489362 0.887074
11 138040 NaN NaN NaN 메리츠금융지주 2122.333333 14894.0 6.313806 0.899691
12 161390 NaN NaN NaN 한국타이어 5648.500000 51341.0 7.453306 0.820007
13 181710 NaN NaN NaN NHN엔터테인먼트 2110.166667 78434.0 30.755864 0.827447
14 207940 NaN NaN NaN 삼성바이오로직스 4644.166667 60099.0 89.790059 6.938551
pd.merge(df1, df2, how='outer') # 양쪽 데이터프레임의 컬럼명이 id로 동일하므로 생략 가능
id stock_name value price name eps bps per pbr
0 128940 한미약품 59385.666667 421000.0 NaN NaN NaN NaN NaN
1 130960 CJ E&M 58540.666667 98900.0 CJ E&M 6301.333333 54068.0 15.695091 1.829178
2 138250 엔에스쇼핑 14558.666667 13200.0 NaN NaN NaN NaN NaN
3 139480 이마트 239230.833333 254500.0 이마트 18268.166667 295780.0 13.931338 0.860437
4 142280 녹십자엠에스 468.833333 10200.0 NaN NaN NaN NaN NaN
5 145990 삼양사 82750.000000 82000.0 삼양사 5741.000000 108090.0 14.283226 0.758627
6 185750 종근당 40293.666667 100500.0 종근당 3990.333333 40684.0 25.185866 2.470259
7 192400 쿠쿠홀딩스 179204.666667 177500.0 NaN NaN NaN NaN NaN
8 199800 툴젠 -2514.333333 115400.0 NaN NaN NaN NaN NaN
9 204210 모두투어리츠 3093.333333 3475.0 모두투어리츠 85.166667 5335.0 40.802348 0.651359
10 136480 NaN NaN NaN 하림 274.166667 3551.0 11.489362 0.887074
11 138040 NaN NaN NaN 메리츠금융지주 2122.333333 14894.0 6.313806 0.899691
12 161390 NaN NaN NaN 한국타이어 5648.500000 51341.0 7.453306 0.820007
13 181710 NaN NaN NaN NHN엔터테인먼트 2110.166667 78434.0 30.755864 0.827447
14 207940 NaN NaN NaN 삼성바이오로직스 4644.166667 60099.0 89.790059 6.938551
# 왼쪽 데이터프레임(df1)에서는 stock_name, 오른쪽 데이터프레임(df2)에서는 name을 조인조건으로 하되
# left join
pd.merge(df1, df2, left_on='stock_name', right_on='name', how='left')
id_x stock_name value price id_y name eps bps per pbr
0 128940 한미약품 59385.666667 421000 NaN NaN NaN NaN NaN NaN
1 130960 CJ E&M 58540.666667 98900 130960.0 CJ E&M 6301.333333 54068.0 15.695091 1.829178
2 138250 엔에스쇼핑 14558.666667 13200 NaN NaN NaN NaN NaN NaN
3 139480 이마트 239230.833333 254500 139480.0 이마트 18268.166667 295780.0 13.931338 0.860437
4 142280 녹십자엠에스 468.833333 10200 NaN NaN NaN NaN NaN NaN
5 145990 삼양사 82750.000000 82000 145990.0 삼양사 5741.000000 108090.0 14.283226 0.758627
6 185750 종근당 40293.666667 100500 185750.0 종근당 3990.333333 40684.0 25.185866 2.470259
7 192400 쿠쿠홀딩스 179204.666667 177500 NaN NaN NaN NaN NaN NaN
8 199800 툴젠 -2514.333333 115400 NaN NaN NaN NaN NaN NaN
9 204210 모두투어리츠 3093.333333 3475 204210.0 모두투어리츠 85.166667 5335.0 40.802348 0.651359
# 왼쪽 데이터프레임(df1)에서는 stock_name, 오른쪽 데이터프레임(df2)에서는 name을 조인조건으로 하되
# right join
pd.merge(df1, df2, left_on='stock_name', right_on='name', how='right')
id_x stock_name value price id_y name eps bps per pbr
0 130960.0 CJ E&M 58540.666667 98900.0 130960 CJ E&M 6301.333333 54068 15.695091 1.829178
1 NaN NaN NaN NaN 136480 하림 274.166667 3551 11.489362 0.887074
2 NaN NaN NaN NaN 138040 메리츠금융지주 2122.333333 14894 6.313806 0.899691
3 139480.0 이마트 239230.833333 254500.0 139480 이마트 18268.166667 295780 13.931338 0.860437
4 145990.0 삼양사 82750.000000 82000.0 145990 삼양사 5741.000000 108090 14.283226 0.758627
5 NaN NaN NaN NaN 161390 한국타이어 5648.500000 51341 7.453306 0.820007
6 NaN NaN NaN NaN 181710 NHN엔터테인먼트 2110.166667 78434 30.755864 0.827447
7 185750.0 종근당 40293.666667 100500.0 185750 종근당 3990.333333 40684 25.185866 2.470259
8 204210.0 모두투어리츠 3093.333333 3475.0 204210 모두투어리츠 85.166667 5335 40.802348 0.651359
9 NaN NaN NaN NaN 207940 삼성바이오로직스 4644.166667 60099 89.790059 6.938551
  • 색인 병합으로 데이터프레임 합치기
df1 = pd.read_excel('./examples/stock price.xlsx', index_col = 'id')
df2 = pd.read_excel('./examples/stock valuation.xlsx', index_col = 'id')
df1
stock_name value price
id
128940 한미약품 59385.666667 421000
130960 CJ E&M 58540.666667 98900
138250 엔에스쇼핑 14558.666667 13200
139480 이마트 239230.833333 254500
142280 녹십자엠에스 468.833333 10200
145990 삼양사 82750.000000 82000
185750 종근당 40293.666667 100500
192400 쿠쿠홀딩스 179204.666667 177500
199800 툴젠 -2514.333333 115400
204210 모두투어리츠 3093.333333 3475
df2
name eps bps per pbr
id
130960 CJ E&M 6301.333333 54068 15.695091 1.829178
136480 하림 274.166667 3551 11.489362 0.887074
138040 메리츠금융지주 2122.333333 14894 6.313806 0.899691
139480 이마트 18268.166667 295780 13.931338 0.860437
145990 삼양사 5741.000000 108090 14.283226 0.758627
161390 한국타이어 5648.500000 51341 7.453306 0.820007
181710 NHN엔터테인먼트 2110.166667 78434 30.755864 0.827447
185750 종근당 3990.333333 40684 25.185866 2.470259
204210 모두투어리츠 85.166667 5335 40.802348 0.651359
207940 삼성바이오로직스 4644.166667 60099 89.790059 6.938551
# 데이터프레임 인덱스를 기준으로 병합 (왼쪽 데이터프레임(df1) 기준)
df1.join(df2) # how='left' 가 기본값
stock_name value price name eps bps per pbr
id
128940 한미약품 59385.666667 421000 NaN NaN NaN NaN NaN
130960 CJ E&M 58540.666667 98900 CJ E&M 6301.333333 54068.0 15.695091 1.829178
138250 엔에스쇼핑 14558.666667 13200 NaN NaN NaN NaN NaN
139480 이마트 239230.833333 254500 이마트 18268.166667 295780.0 13.931338 0.860437
142280 녹십자엠에스 468.833333 10200 NaN NaN NaN NaN NaN
145990 삼양사 82750.000000 82000 삼양사 5741.000000 108090.0 14.283226 0.758627
185750 종근당 40293.666667 100500 종근당 3990.333333 40684.0 25.185866 2.470259
192400 쿠쿠홀딩스 179204.666667 177500 NaN NaN NaN NaN NaN
199800 툴젠 -2514.333333 115400 NaN NaN NaN NaN NaN
204210 모두투어리츠 3093.333333 3475 모두투어리츠 85.166667 5335.0 40.802348 0.651359
# 데이터프레임 인덱스를 기준으로 병합 (공통된 인덱스만)
df1.join(df2, how='inner')
stock_name value price name eps bps per pbr
id
130960 CJ E&M 58540.666667 98900 CJ E&M 6301.333333 54068 15.695091 1.829178
139480 이마트 239230.833333 254500 이마트 18268.166667 295780 13.931338 0.860437
145990 삼양사 82750.000000 82000 삼양사 5741.000000 108090 14.283226 0.758627
185750 종근당 40293.666667 100500 종근당 3990.333333 40684 25.185866 2.470259
204210 모두투어리츠 3093.333333 3475 모두투어리츠 85.166667 5335 40.802348 0.651359

9.3 그룹연산

(1) 그룹 객체 만들기

titanic = pd.read_csv('./datasets/titanic_train.csv')
titanic.head()
titanic['Pclass'].unique()
array([3, 1, 2])
titanic['Pclass'].value_counts()
3    491
1    216
2    184
Name: Pclass, dtype: int64
  • 한 컬럼을 기준으로 그룹화
grouped = titanic.groupby('Pclass')
grouped
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x7f040107bfa0>
# grouped 객체를 순회
for group_key, group in grouped:
  print('group key :', group_key)
  print('length of group : ', len(group))
  
last_group = group.head(3)
last_group  
group key : 1
length of group :  216
group key : 2
length of group :  184
group key : 3
length of group :  491
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.250 NaN S
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.925 NaN S
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.050 NaN S
# 각 그룹들의 평균
grouped.mean() 
PassengerId Survived Age SibSp Parch Fare
Pclass
1 461.597222 0.629630 38.233441 0.416667 0.356481 84.154687
2 445.956522 0.472826 29.877630 0.402174 0.380435 20.662183
3 439.154786 0.242363 25.140620 0.615071 0.393075 13.675550
grouped.mean()['Survived'] # 그룹별 생존률
Pclass
1    0.629630
2    0.472826
3    0.242363
Name: Survived, dtype: float64
grouped.mean()['Age'] # 그룹별 나이 평균
Pclass
1    38.233441
2    29.877630
3    25.140620
Name: Age, dtype: float64
grouped.mean()['Fare'] # 그룹별 요금 평균균
Pclass
1    84.154687
2    20.662183
3    13.675550
Name: Fare, dtype: float64
# 한 그룹만 추출
first_group = grouped.get_group(1) # Pclass =1 인 그룹만 DF 으로 반환
first_group.head(3)
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
6 7 0 1 McCarthy, Mr. Timothy J male 54.0 0 0 17463 51.8625 E46 S
  • 두 컬럼을 기준으로 그룹화
grouped2 = titanic.groupby(['Pclass', 'Sex'])
grouped2
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x7f0401056400>
# grouped2 객체를 순회
for group_key, group in grouped2:
  print('group key :', group_key)
  print('length of group :', len(group))
group key : (1, 'female')
length of group : 94
group key : (1, 'male')
length of group : 122
group key : (2, 'female')
length of group : 76
group key : (2, 'male')
length of group : 108
group key : (3, 'female')
length of group : 144
group key : (3, 'male')
length of group : 347
# 각 그룹들의 평균
grouped2.mean()
PassengerId Survived Age SibSp Parch Fare
Pclass Sex
1 female 469.212766 0.968085 34.611765 0.553191 0.457447 106.125798
male 455.729508 0.368852 41.281386 0.311475 0.278689 67.226127
2 female 443.105263 0.921053 28.722973 0.486842 0.605263 21.970121
male 447.962963 0.157407 30.740707 0.342593 0.222222 19.741782
3 female 399.729167 0.500000 21.750000 0.895833 0.798611 16.118810
male 455.515850 0.135447 26.507589 0.498559 0.224784 12.661633
grouped2.mean()['Survived'] # 각 그룹의 생존률률
Pclass  Sex   
1       female    0.968085
        male      0.368852
2       female    0.921053
        male      0.157407
3       female    0.500000
        male      0.135447
Name: Survived, dtype: float64
grouped2.mean()['Age']
Pclass  Sex   
1       female    34.611765
        male      41.281386
2       female    28.722973
        male      30.740707
3       female    21.750000
        male      26.507589
Name: Age, dtype: float64
grouped2.mean()['Fare']
Pclass  Sex   
1       female    106.125798
        male       67.226127
2       female     21.970121
        male       19.741782
3       female     16.118810
        male       12.661633
Name: Fare, dtype: float64
first_female_group = grouped2.get_group((1, 'female'))
first_female_group.head()
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
11 12 1 1 Bonnell, Miss. Elizabeth female 58.0 0 0 113783 26.5500 C103 S
31 32 1 1 Spencer, Mrs. William Augustus (Marie Eugenie) female NaN 1 0 PC 17569 146.5208 B78 C
52 53 1 1 Harper, Mrs. Henry Sleeper (Myna Haxtun) female 49.0 1 0 PC 17572 76.7292 D33 C

(2) 그룹 연산 메소드

grouped = titanic.groupby('Pclass')
grouped.mean() # 그룹별 평균
PassengerId Survived Age SibSp Parch Fare
Pclass
1 461.597222 0.629630 38.233441 0.416667 0.356481 84.154687
2 445.956522 0.472826 29.877630 0.402174 0.380435 20.662183
3 439.154786 0.242363 25.140620 0.615071 0.393075 13.675550
grouped.agg('mean') # agg(적용하고자 하는 함수), mean은 이미 제공되는 함수라서 문자열로 배치
PassengerId Survived Age SibSp Parch Fare
Pclass
1 461.597222 0.629630 38.233441 0.416667 0.356481 84.154687
2 445.956522 0.472826 29.877630 0.402174 0.380435 20.662183
3 439.154786 0.242363 25.140620 0.615071 0.393075 13.675550
def min_max(x):
  return x.max() - x.min()
grouped.agg(min_max) # agg(적용하고자 하는 함수), min_max를 적용함으로 각 열의 최댓값과 최솟값의 차이를 조회해 볼 수 있음음
# grouped[['PassengerId', 'Survived', 'Age', 'SibSp', 'Parch', 'Fare']].agg(min_max)
/usr/local/lib/python3.8/dist-packages/pandas/core/groupby/generic.py:303: FutureWarning: Dropping invalid columns in SeriesGroupBy.agg is deprecated. In a future version, a TypeError will be raised. Before calling .agg, select only columns which should be valid for the aggregating function.
  results[key] = self.aggregate(func)
PassengerId Survived Age SibSp Parch Fare
Pclass
1 888 1 79.08 3 4 512.3292
2 877 1 69.33 3 3 73.5000
3 890 1 73.58 8 6 69.5500
grouped.agg(['mean', 'min', 'max']) # 여러 함수를 매핑할 수도 있음
PassengerId Survived Age SibSp Parch Fare
mean min max mean min max mean min max mean min max mean min max mean min max
Pclass
1 461.597222 2 890 0.629630 0 1 38.233441 0.92 80.0 0.416667 0 3 0.356481 0 4 84.154687 0.0 512.3292
2 445.956522 10 887 0.472826 0 1 29.877630 0.67 70.0 0.402174 0 3 0.380435 0 3 20.662183 0.0 73.5000
3 439.154786 1 891 0.242363 0 1 25.140620 0.42 74.0 0.615071 0 8 0.393075 0 6 13.675550 0.0 69.5500
grouped.agg({'Survived' :'mean', 'Age':['min', 'max']}) 
Survived Age
mean min max
Pclass
1 0.629630 0.92 80.0
2 0.472826 0.67 70.0
3 0.242363 0.42 74.0
# 데이터 변환
grouped['Fare'].transform(lambda x: x*1.2) # 파운드를 달러로 변환
0       8.70000
1      85.53996
2       9.51000
3      63.72000
4       9.66000
         ...   
886    15.60000
887    36.00000
888    28.14000
889    36.00000
890     9.30000
Name: Fare, Length: 891, dtype: float64
# 데이터 필터링
grouped.filter(lambda x : len(x) >= 200) # 그룹의 갯수가 200개 이상인 그룹만 가져옴
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S
... ... ... ... ... ... ... ... ... ... ... ... ...
885 886 0 3 Rice, Mrs. William (Margaret Norton) female 39.0 0 5 382652 29.1250 NaN Q
887 888 1 1 Graham, Miss. Margaret Edith female 19.0 0 0 112053 30.0000 B42 S
888 889 0 3 Johnston, Miss. Catherine Helen "Carrie" female NaN 1 2 W./C. 6607 23.4500 NaN S
889 890 1 1 Behr, Mr. Karl Howell male 26.0 0 0 111369 30.0000 C148 C
890 891 0 3 Dooley, Mr. Patrick male 32.0 0 0 370376 7.7500 NaN Q

707 rows × 12 columns

grouped.filter(lambda x: x.Age.mean() < 30) # Age열의 그룹 평균이 30보다 작은 그룹만을 선택(2, 3 Class)
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S
5 6 0 3 Moran, Mr. James male NaN 0 0 330877 8.4583 NaN Q
7 8 0 3 Palsson, Master. Gosta Leonard male 2.0 3 1 349909 21.0750 NaN S
... ... ... ... ... ... ... ... ... ... ... ... ...
884 885 0 3 Sutehall, Mr. Henry Jr male 25.0 0 0 SOTON/OQ 392076 7.0500 NaN S
885 886 0 3 Rice, Mrs. William (Margaret Norton) female 39.0 0 5 382652 29.1250 NaN Q
886 887 0 2 Montvila, Rev. Juozas male 27.0 0 0 211536 13.0000 NaN S
888 889 0 3 Johnston, Miss. Catherine Helen "Carrie" female NaN 1 2 W./C. 6607 23.4500 NaN S
890 891 0 3 Dooley, Mr. Patrick male 32.0 0 0 370376 7.7500 NaN Q

675 rows × 12 columns

# 함수 매핑
grouped.apply(lambda x: x.describe())
# grouped.filter(lambda x: x.Age.mean() < 30) # filter : 조건에 해당하는 그룹까지 가져오기
grouped.apply(lambda x: x.Age.mean() < 30) # apply : 해당식의 판별 결과 가져오기
Pclass
1    False
2     True
3     True
dtype: bool
t = titanic.groupby(['Pclass', 'Survived']).size()
t
Pclass  Survived
1       0            80
        1           136
2       0            97
        1            87
3       0           372
        1           119
dtype: int64
t.index
MultiIndex([(1, 0),
            (1, 1),
            (2, 0),
            (2, 1),
            (3, 0),
            (3, 1)],
           names=['Pclass', 'Survived'])
t.unstack()
Survived 0 1
Pclass
1 80 136
2 97 87
3 372 119
t.unstack().stack()
Pclass  Survived
1       0            80
        1           136
2       0            97
        1            87
3       0           372
        1           119
dtype: int64

9.4 Pivot, Melt

from IPython.display import Image
Image('./images/reshaping_pivot.png', width=600)

png

# Pandas example

df = pd.DataFrame({'foo': ['one', 'one', 'one', 'two', 'two',
                           'two'],
                   'bar': ['A', 'B', 'C', 'A', 'B', 'C'],
                   'baz': [1, 2, 3, 4, 5, 6],
                   'zoo': ['x', 'y', 'z', 'q', 'w', 't']})
df
foo bar baz zoo
0 one A 1 x
1 one B 2 y
2 one C 3 z
3 two A 4 q
4 two B 5 w
5 two C 6 t
df.pivot(index='foo', columns='bar', values='baz')
bar A B C
foo
one 1 2 3
two 4 5 6
Image('./images/reshaping_melt.png', width=600)

png

cheese = pd.DataFrame(
    {
        "first": ["John", "Mary"],
        "last": ["Doe", "Bo"],
        "height": [5.5, 6.0],
        "weight": [130, 150],
    }
)
cheese
first last height weight
0 John Doe 5.5 130
1 Mary Bo 6.0 150
cheese.melt(id_vars=['first', 'last'])
first last variable value
0 John Doe height 5.5
1 Mary Bo height 6.0
2 John Doe weight 130.0
3 Mary Bo weight 150.0

추가 예제

Image('./images/long_wide_format.png', width=600)

png

df = pd.DataFrame(
    {
        'Item': ['Cereals', 'Dairy', 'Frozen', 'Meat'],
        'Price': [100, 50, 200, 250],
        'Hour_1': [5, 5, 3, 8],
        'Hour_2': [8, 8, 2, 1],
        'Hour_3': [7, 7, 8, 2]
    }
)
df
Item Price Hour_1 Hour_2 Hour_3
0 Cereals 100 5 8 7
1 Dairy 50 5 8 7
2 Frozen 200 3 2 8
3 Meat 250 8 1 2

from wide format to long format

melted_df = pd.melt(df, id_vars=['Item'], value_vars=('Hour_1', 'Hour_2', 'Hour_3'),
        var_name='Hour', value_name='Sales')
melted_df
Item Hour Sales
0 Cereals Hour_1 5
1 Dairy Hour_1 5
2 Frozen Hour_1 3
3 Meat Hour_1 8
4 Cereals Hour_2 8
5 Dairy Hour_2 8
6 Frozen Hour_2 2
7 Meat Hour_2 1
8 Cereals Hour_3 7
9 Dairy Hour_3 7
10 Frozen Hour_3 8
11 Meat Hour_3 2
melted_df.groupby('Item').sum()
Sales
Item
Cereals 20
Dairy 20
Frozen 13
Meat 11
melted_df.groupby('Hour').sum()
Sales
Hour
Hour_1 21
Hour_2 19
Hour_3 24
# price 포함
melted_df = pd.melt(df, id_vars=['Item', 'Price'],
                    value_vars = ('Hour_1', 'Hour_2', 'Hour_3'),
                    var_name = 'Hour',
                    value_name = 'Sales')
melted_df
Item Price Hour Sales
0 Cereals 100 Hour_1 5
1 Dairy 50 Hour_1 5
2 Frozen 200 Hour_1 3
3 Meat 250 Hour_1 8
4 Cereals 100 Hour_2 8
5 Dairy 50 Hour_2 8
6 Frozen 200 Hour_2 2
7 Meat 250 Hour_2 1
8 Cereals 100 Hour_3 7
9 Dairy 50 Hour_3 7
10 Frozen 200 Hour_3 8
11 Meat 250 Hour_3 2
melted_df['Sale_amt'] = melted_df['Price'] * melted_df['Sales']
melted_df
Item Price Hour Sales Sale_amt
0 Cereals 100 Hour_1 5 500
1 Dairy 50 Hour_1 5 250
2 Frozen 200 Hour_1 3 600
3 Meat 250 Hour_1 8 2000
4 Cereals 100 Hour_2 8 800
5 Dairy 50 Hour_2 8 400
6 Frozen 200 Hour_2 2 400
7 Meat 250 Hour_2 1 250
8 Cereals 100 Hour_3 7 700
9 Dairy 50 Hour_3 7 350
10 Frozen 200 Hour_3 8 1600
11 Meat 250 Hour_3 2 500
melted_df.groupby('Hour').sum()['Sale_amt'] # 시간대별 매출량 집계계
Hour
Hour_1    3350
Hour_2    1850
Hour_3    3150
Name: Sale_amt, dtype: int64
melted_df.groupby('Item').sum()['Sale_amt']
Item
Cereals    2000
Dairy      1000
Frozen     2600
Meat       2750
Name: Sale_amt, dtype: int64

from long format to wide format

pivoted_df = melted_df.pivot(index=['Item', 'Price'], columns='Hour', values='Sales')
pivoted_df
Hour Hour_1 Hour_2 Hour_3
Item Price
Cereals 100 5 8 7
Dairy 50 5 8 7
Frozen 200 3 2 8
Meat 250 8 1 2

Workshop

cpi = pd.read_excel('./datasets/CPI2.xlsx')
cpi
Year Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
0 2001 175.100 175.800 176.200 176.900 177.700 178.000 177.500 177.500 178.300 177.700 177.400 176.700
1 2002 177.100 177.800 178.800 179.800 179.800 179.900 180.100 180.700 181.000 181.300 181.300 180.900
2 2003 181.700 183.100 184.200 183.800 183.500 183.700 183.900 184.600 185.200 185.000 184.500 184.300
3 2004 185.200 186.200 187.400 188.000 189.100 189.700 189.400 189.500 189.900 190.900 191.000 190.300
4 2005 190.700 191.800 193.300 194.600 194.400 194.500 195.400 196.400 198.800 199.200 197.600 196.800
5 2006 198.300 198.700 199.800 201.500 202.500 202.900 203.500 203.900 202.900 201.800 201.500 201.800
6 2007 202.416 203.499 205.352 206.686 207.949 208.352 208.299 207.917 208.490 208.936 210.177 210.036
7 2008 211.080 211.693 213.528 214.823 216.632 218.815 219.964 219.086 218.783 216.573 212.425 210.228
8 2009 211.143 212.193 212.709 213.240 213.856 215.693 215.351 215.834 215.969 216.177 216.330 215.949
9 2010 216.687 216.741 217.631 218.009 218.178 217.965 218.011 218.312 218.439 218.711 218.803 219.179
10 2011 220.223 221.309 223.467 224.906 225.964 225.722 225.922 226.545 226.889 226.421 226.230 225.672
11 2012 226.665 227.663 229.392 230.085 229.815 229.478 229.104 230.379 231.407 231.317 230.221 229.601
12 2013 230.280 232.166 232.773 232.531 232.945 233.504 233.596 233.877 234.149 233.546 233.069 233.049
13 2014 233.916 234.781 236.293 237.072 237.900 238.343 238.250 237.852 238.031 237.433 236.151 234.812
14 2015 233.707 234.722 236.119 236.599 237.805 238.638 238.654 238.316 237.945 237.838 237.336 236.525
15 2016 236.916 237.111 238.132 239.261 240.229 241.018 240.628 240.849 241.428 241.729 241.353 241.432
16 2017 242.839 243.603 243.801 244.524 244.733 244.955 244.786 245.519 246.819 246.663 246.669 246.524
17 2018 247.867 248.991 249.554 250.546 251.588 251.989 252.006 252.146 252.439 252.885 252.038 251.233
18 2019 251.712 252.776 254.202 255.548 256.092 256.143 256.571 256.558 256.759 257.346 257.208 256.974
19 2020 257.971 258.678 258.115 256.389 256.394 257.797 259.101 259.918 260.280 260.388 260.229 260.474
20 2021 261.582 263.014 264.877 267.054 269.195 271.696 273.003 273.567 274.310 276.589 277.948 278.802
21 2022 281.148 283.716 287.504 289.109 292.296 296.311 296.276 296.171 296.808 298.012 297.711 296.797
22 2023 299.170 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
  • wide to long format
melted_cpi = cpi.melt(id_vars=['Year'], var_name='Month', value_name='cpi')
melted_cpi
Year Month cpi
0 2001 Jan 175.100
1 2002 Jan 177.100
2 2003 Jan 181.700
3 2004 Jan 185.200
4 2005 Jan 190.700
... ... ... ...
271 2019 Dec 256.974
272 2020 Dec 260.474
273 2021 Dec 278.802
274 2022 Dec 296.797
275 2023 Dec NaN

276 rows × 3 columns

melted_cpi.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 276 entries, 0 to 275
Data columns (total 3 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   Year    276 non-null    int64  
 1   Month   276 non-null    object 
 2   cpi     265 non-null    float64
dtypes: float64(1), int64(1), object(1)
memory usage: 6.6+ KB

image.png

# 참고
x = pd.to_datetime(melted_cpi['Month'], format='%b')
x
0     1900-01-01
1     1900-01-01
2     1900-01-01
3     1900-01-01
4     1900-01-01
         ...    
271   1900-12-01
272   1900-12-01
273   1900-12-01
274   1900-12-01
275   1900-12-01
Name: Month, Length: 276, dtype: datetime64[ns]
melted_cpi['Month'] = melted_cpi['Month'].map(lambda x: pd.to_datetime(x, format='%b')).dt.month
melted_cpi
Year Month cpi
0 2001 1 175.100
1 2002 1 177.100
2 2003 1 181.700
3 2004 1 185.200
4 2005 1 190.700
... ... ... ...
271 2019 12 256.974
272 2020 12 260.474
273 2021 12 278.802
274 2022 12 296.797
275 2023 12 NaN

276 rows × 3 columns

  • 월별 cpi 평균 구하기
melted_cpi.groupby('Month').mean()['cpi']
Month
1     224.931391
2     222.548000
3     223.779500
4     224.590091
5     225.389591
6     226.141773
7     226.332818
8     226.611182
9     227.047500
10    227.112000
11    226.690818
12    226.276682
Name: cpi, dtype: float64
  • 연도별 cpi 평균 구하기
melted_cpi.groupby('Year').mean()['cpi']
Year
2001    177.066667
2002    179.875000
2003    183.958333
2004    188.883333
2005    195.291667
2006    201.591667
2007    207.342417
2008    215.302500
2009    214.537000
2010    218.055500
2011    224.939167
2012    229.593917
2013    232.957083
2014    236.736167
2015    237.017000
2016    240.007167
2017    245.119583
2018    251.106833
2019    255.657417
2020    258.811167
2021    270.969750
2022    292.654917
2023    299.170000
Name: cpi, dtype: float64
  • long to wide format
pivoted_cpi = melted_cpi.pivot(index='Year', columns='Month', values='cpi')
pivoted_cpi
Month 1 2 3 4 5 6 7 8 9 10 11 12
Year
2001 175.100 175.800 176.200 176.900 177.700 178.000 177.500 177.500 178.300 177.700 177.400 176.700
2002 177.100 177.800 178.800 179.800 179.800 179.900 180.100 180.700 181.000 181.300 181.300 180.900
2003 181.700 183.100 184.200 183.800 183.500 183.700 183.900 184.600 185.200 185.000 184.500 184.300
2004 185.200 186.200 187.400 188.000 189.100 189.700 189.400 189.500 189.900 190.900 191.000 190.300
2005 190.700 191.800 193.300 194.600 194.400 194.500 195.400 196.400 198.800 199.200 197.600 196.800
2006 198.300 198.700 199.800 201.500 202.500 202.900 203.500 203.900 202.900 201.800 201.500 201.800
2007 202.416 203.499 205.352 206.686 207.949 208.352 208.299 207.917 208.490 208.936 210.177 210.036
2008 211.080 211.693 213.528 214.823 216.632 218.815 219.964 219.086 218.783 216.573 212.425 210.228
2009 211.143 212.193 212.709 213.240 213.856 215.693 215.351 215.834 215.969 216.177 216.330 215.949
2010 216.687 216.741 217.631 218.009 218.178 217.965 218.011 218.312 218.439 218.711 218.803 219.179
2011 220.223 221.309 223.467 224.906 225.964 225.722 225.922 226.545 226.889 226.421 226.230 225.672
2012 226.665 227.663 229.392 230.085 229.815 229.478 229.104 230.379 231.407 231.317 230.221 229.601
2013 230.280 232.166 232.773 232.531 232.945 233.504 233.596 233.877 234.149 233.546 233.069 233.049
2014 233.916 234.781 236.293 237.072 237.900 238.343 238.250 237.852 238.031 237.433 236.151 234.812
2015 233.707 234.722 236.119 236.599 237.805 238.638 238.654 238.316 237.945 237.838 237.336 236.525
2016 236.916 237.111 238.132 239.261 240.229 241.018 240.628 240.849 241.428 241.729 241.353 241.432
2017 242.839 243.603 243.801 244.524 244.733 244.955 244.786 245.519 246.819 246.663 246.669 246.524
2018 247.867 248.991 249.554 250.546 251.588 251.989 252.006 252.146 252.439 252.885 252.038 251.233
2019 251.712 252.776 254.202 255.548 256.092 256.143 256.571 256.558 256.759 257.346 257.208 256.974
2020 257.971 258.678 258.115 256.389 256.394 257.797 259.101 259.918 260.280 260.388 260.229 260.474
2021 261.582 263.014 264.877 267.054 269.195 271.696 273.003 273.567 274.310 276.589 277.948 278.802
2022 281.148 283.716 287.504 289.109 292.296 296.311 296.276 296.171 296.808 298.012 297.711 296.797
2023 299.170 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
pivoted_cpi.columns
Int64Index([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], dtype='int64', name='Month')

Reference

파이썬 라이브러리를 활용한 데이터 분석 (웨스 맥키니 저)

댓글남기기