머신러닝과 데이터 분석 A-Z 올인원 패키지 - 데이터 분석을 위한 Python(Pandas) – (3)

2020. 9. 30. 15:49·AI Study/ML_Basic
반응형

* 위 강의노트는 패스트캠퍼스에서 주관하는 강의를 수강하고 작성한 노트입니다. 

1. DataFrame group by 이해하기¶

In [1]:
import pandas as pd
import numpy as np
 

group by¶

  • 아래의 세 단계를 적용하여 데이터를 그룹화(groupping) (SQL의 group by 와 개념적으로는 동일, 사용법은 유사)
    • 데이터 분할
    • operation 적용
    • 데이터 병합
In [21]:
# data 출처: https://www.kaggle.com/hesh97/titanicdataset-traincsv/data
df = pd.read_csv('./train.csv')
df.head()
Out[21]:
  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
 

GroupBy groups 속성¶

  • 각 그룹과 그룹에 속한 index를 dict 형태로 표현
In [3]:
class_group = df.groupby('Pclass') ## groupby 객체 만들기
class_group
Out[3]:
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000018AEB057F08>
In [4]:
class_group.groups
Out[4]:
{1: Int64Index([  1,   3,   6,  11,  23,  27,  30,  31,  34,  35,
             ...
             853, 856, 857, 862, 867, 871, 872, 879, 887, 889],
            dtype='int64', length=216),
 2: Int64Index([  9,  15,  17,  20,  21,  33,  41,  43,  53,  56,
             ...
             848, 854, 861, 864, 865, 866, 874, 880, 883, 886],
            dtype='int64', length=184),
 3: Int64Index([  0,   2,   4,   5,   7,   8,  10,  12,  13,  14,
             ...
             875, 876, 877, 878, 881, 882, 884, 885, 888, 890],
            dtype='int64', length=491)}
In [6]:
gender_group = df.groupby('Sex') ## groupby 객체 만들기
gender_group.groups
Out[6]:
{'female': Int64Index([  1,   2,   3,   8,   9,  10,  11,  14,  15,  18,
             ...
             866, 871, 874, 875, 879, 880, 882, 885, 887, 888],
            dtype='int64', length=314),
 'male': Int64Index([  0,   4,   5,   6,   7,  12,  13,  16,  17,  20,
             ...
             873, 876, 877, 878, 881, 883, 884, 886, 889, 890],
            dtype='int64', length=577)}
 

groupping 함수¶

  • 그룹 데이터에 적용 가능한 통계 함수(NaN은 제외하여 연산)
  • count - 데이터 개수
  • sum - 데이터의 합
  • mean, std, var - 평균, 표준편차, 분산
  • min, max - 최소, 최대값
In [7]:
class_group.count()
Out[7]:
  PassengerId Survived Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
Pclass                      
1 216 216 216 216 186 216 216 216 216 176 214
2 184 184 184 184 173 184 184 184 184 16 184
3 491 491 491 491 355 491 491 491 491 12 491
In [8]:
class_group.sum()
Out[8]:
  PassengerId Survived Age SibSp Parch Fare
Pclass            
1 99705 136 7111.42 90 77 18177.4125
2 82056 87 5168.83 74 70 3801.8417
3 215625 119 8924.92 302 193 6714.6951
In [10]:
class_group.mean()['Survived'] # Column 따로 구하기
Out[10]:
Pclass
1    0.629630
2    0.472826
3    0.242363
Name: Survived, dtype: float64
In [11]:
class_group.max()
Out[11]:
  PassengerId Survived Name Sex Age SibSp Parch Ticket Fare
Pclass                  
1 890 1 Young, Miss. Marie Grice male 80.0 3 4 WE/P 5735 512.3292
2 887 1 del Carlo, Mr. Sebastiano male 70.0 3 3 W/C 14208 73.5000
3 891 1 van Melkebeke, Mr. Philemon male 74.0 8 6 W./C. 6609 69.5500
 
  • 성별에 따른 생존율 구해보기
In [12]:
df.groupby('Sex').mean()['Survived']
Out[12]:
Sex
female    0.742038
male      0.188908
Name: Survived, dtype: float64
 

복수 columns로 groupping 하기¶

  • groupby에 column 리스트를 전달
  • 통계함수를 적용한 결과는 multiindex를 갖는 dataframe
 
  • 클래스와 성별에 따른 생존률 구해보기
In [14]:
df.groupby(['Pclass', 'Sex']).mean()['Survived']
Out[14]:
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
In [15]:
df.groupby(['Pclass', 'Sex']).mean().loc[(2, 'female')]
Out[15]:
PassengerId    443.105263
Survived         0.921053
Age             28.722973
SibSp            0.486842
Parch            0.605263
Fare            21.970121
Name: (2, female), dtype: float64
 

index를 이용한 group by¶

  • index가 있는 경우, groupby 함수에 level 사용 가능
    • level은 index의 depth를 의미하며, 가장 왼쪽부터 0부터 증가
 
  • set_index 함수
    • column 데이터를 index 레벨로 변경
  • reset_index 함수
    • 인덱스 초기화
In [18]:
df.set_index(['Pclass']) # 인덱스초기화
Out[18]:
  PassengerId Survived Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
Pclass                      
3 1 0 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
3 3 1 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
1 4 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
3 5 0 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S
... ... ... ... ... ... ... ... ... ... ... ...
2 887 0 Montvila, Rev. Juozas male 27.0 0 0 211536 13.0000 NaN S
1 888 1 Graham, Miss. Margaret Edith female 19.0 0 0 112053 30.0000 B42 S
3 889 0 Johnston, Miss. Catherine Helen "Carrie" female NaN 1 2 W./C. 6607 23.4500 NaN S
1 890 1 Behr, Mr. Karl Howell male 26.0 0 0 111369 30.0000 C148 C
3 891 0 Dooley, Mr. Patrick male 32.0 0 0 370376 7.7500 NaN Q

891 rows × 11 columns

In [19]:
df.set_index(['Pclass', 'Age']) # 멀티인덱스
Out[19]:
    PassengerId Survived Name Sex SibSp Parch Ticket Fare Cabin Embarked
Pclass Age                    
3 22.0 1 0 Braund, Mr. Owen Harris male 1 0 A/5 21171 7.2500 NaN S
1 38.0 2 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 1 0 PC 17599 71.2833 C85 C
3 26.0 3 1 Heikkinen, Miss. Laina female 0 0 STON/O2. 3101282 7.9250 NaN S
1 35.0 4 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 1 0 113803 53.1000 C123 S
3 35.0 5 0 Allen, Mr. William Henry male 0 0 373450 8.0500 NaN S
... ... ... ... ... ... ... ... ... ... ... ...
2 27.0 887 0 Montvila, Rev. Juozas male 0 0 211536 13.0000 NaN S
1 19.0 888 1 Graham, Miss. Margaret Edith female 0 0 112053 30.0000 B42 S
3 NaN 889 0 Johnston, Miss. Catherine Helen "Carrie" female 1 2 W./C. 6607 23.4500 NaN S
1 26.0 890 1 Behr, Mr. Karl Howell male 0 0 111369 30.0000 C148 C
3 32.0 891 0 Dooley, Mr. Patrick male 0 0 370376 7.7500 NaN Q

891 rows × 10 columns

In [21]:
df.set_index(['Pclass', 'Age']).reset_index()
Out[21]:
  Pclass Age PassengerId Survived Name Sex SibSp Parch Ticket Fare Cabin Embarked
0 3 22.0 1 0 Braund, Mr. Owen Harris male 1 0 A/5 21171 7.2500 NaN S
1 1 38.0 2 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 1 0 PC 17599 71.2833 C85 C
2 3 26.0 3 1 Heikkinen, Miss. Laina female 0 0 STON/O2. 3101282 7.9250 NaN S
3 1 35.0 4 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 1 0 113803 53.1000 C123 S
4 3 35.0 5 0 Allen, Mr. William Henry male 0 0 373450 8.0500 NaN S
... ... ... ... ... ... ... ... ... ... ... ... ...
886 2 27.0 887 0 Montvila, Rev. Juozas male 0 0 211536 13.0000 NaN S
887 1 19.0 888 1 Graham, Miss. Margaret Edith female 0 0 112053 30.0000 B42 S
888 3 NaN 889 0 Johnston, Miss. Catherine Helen "Carrie" female 1 2 W./C. 6607 23.4500 NaN S
889 1 26.0 890 1 Behr, Mr. Karl Howell male 0 0 111369 30.0000 C148 C
890 3 32.0 891 0 Dooley, Mr. Patrick male 0 0 370376 7.7500 NaN Q

891 rows × 12 columns

In [22]:
df.set_index('Age').groupby(level = 0).mean() # setindex후 0번째로 groupby
Out[22]:
  PassengerId Survived Pclass SibSp Parch Fare
Age            
0.42 804.0 1.0 3.0 0.0 1.0 8.5167
0.67 756.0 1.0 2.0 1.0 1.0 14.5000
0.75 557.5 1.0 3.0 2.0 1.0 19.2583
0.83 455.5 1.0 2.0 0.5 1.5 23.8750
0.92 306.0 1.0 1.0 1.0 2.0 151.5500
... ... ... ... ... ... ...
70.00 709.5 0.0 1.5 0.5 0.5 40.7500
70.50 117.0 0.0 3.0 0.0 0.0 7.7500
71.00 295.5 0.0 1.0 0.0 0.0 42.0792
74.00 852.0 0.0 3.0 0.0 0.0 7.7750
80.00 631.0 1.0 1.0 0.0 0.0 30.0000

88 rows × 6 columns

 

나이대별로 생존률 구하기¶

In [23]:
import math
def age_categorize(age):
    if math.isnan(age):
        return -1
    return math.floor(age/10) * 10
In [24]:
# age groupby
df.set_index('Age').groupby(age_categorize).mean()
Out[24]:
  PassengerId Survived Pclass SibSp Parch Fare
-1 435.581921 0.293785 2.598870 0.564972 0.180791 22.158567
0 424.741935 0.612903 2.629032 1.854839 1.403226 30.576679
10 444.362745 0.401961 2.470588 0.666667 0.470588 32.535132
20 433.231818 0.350000 2.450000 0.322727 0.250000 27.278937
30 472.449102 0.437126 2.113772 0.353293 0.329341 40.377294
40 465.606742 0.382022 1.966292 0.370787 0.471910 38.002297
50 440.187500 0.416667 1.562500 0.291667 0.270833 47.933333
60 433.736842 0.315789 1.473684 0.263158 0.368421 48.367542
70 496.500000 0.000000 1.833333 0.166667 0.166667 30.197233
80 631.000000 1.000000 1.000000 0.000000 0.000000 30.000000
 

MultiIndex를 이용한 groupping¶

In [26]:
df.set_index(['Pclass', 'Sex']).groupby(level = [0, 1]).mean()
Out[26]:
    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
 

aggregate(집계) 함수 사용하기¶

  • groupby 결과에 집계함수를 적용하여 그룹별 데이터 확인 가능
In [27]:
df.set_index(['Pclass', 'Sex']).groupby(level = [0, 1]).aggregate([np.mean, np.sum, np.max])
Out[27]:
    PassengerId Survived Age SibSp Parch Fare
    mean sum amax mean sum amax mean sum amax mean sum amax mean sum amax mean sum amax
Pclass Sex                                    
1 female 469.212766 44106 888 0.968085 91 1 34.611765 2942.00 63.0 0.553191 52 3 0.457447 43 2 106.125798 9975.8250 512.3292
male 455.729508 55599 890 0.368852 45 1 41.281386 4169.42 80.0 0.311475 38 3 0.278689 34 4 67.226127 8201.5875 512.3292
2 female 443.105263 33676 881 0.921053 70 1 28.722973 2125.50 57.0 0.486842 37 3 0.605263 46 3 21.970121 1669.7292 65.0000
male 447.962963 48380 887 0.157407 17 1 30.740707 3043.33 70.0 0.342593 37 2 0.222222 24 2 19.741782 2132.1125 73.5000
3 female 399.729167 57561 889 0.500000 72 1 21.750000 2218.50 63.0 0.895833 129 8 0.798611 115 6 16.118810 2321.1086 69.5500
male 455.515850 158064 891 0.135447 47 1 26.507589 6706.42 74.0 0.498559 173 8 0.224784 78 5 12.661633 4393.5865 69.5500
 

2. Transform 함수의 이해 및 활용하기¶

 

transform 함수¶

  • groupby 후 transform 함수를 사용하면 원래의 index를 유지한 상태로 통계함수를 적용
  • 전체 데이터의 집계가 아닌 각 그룹에서의 집계를 계산
  • 따라서 새로 생성된 데이터를 원본 dataframe과 합치기 쉬움
In [3]:
df.groupby('Pclass').mean() ## 그룹별 평균
Out[3]:
  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
In [4]:
df.groupby('Pclass').transform(np.mean) #원본의 인덱스를 유지한채로 각 그룹별 mean을 적용
Out[4]:
  PassengerId Survived Age SibSp Parch Fare
0 439.154786 0.242363 25.140620 0.615071 0.393075 13.675550
1 461.597222 0.629630 38.233441 0.416667 0.356481 84.154687
2 439.154786 0.242363 25.140620 0.615071 0.393075 13.675550
3 461.597222 0.629630 38.233441 0.416667 0.356481 84.154687
4 439.154786 0.242363 25.140620 0.615071 0.393075 13.675550
... ... ... ... ... ... ...
886 445.956522 0.472826 29.877630 0.402174 0.380435 20.662183
887 461.597222 0.629630 38.233441 0.416667 0.356481 84.154687
888 439.154786 0.242363 25.140620 0.615071 0.393075 13.675550
889 461.597222 0.629630 38.233441 0.416667 0.356481 84.154687
890 439.154786 0.242363 25.140620 0.615071 0.393075 13.675550

891 rows × 6 columns

In [5]:
df['Age2'] = df.groupby('Pclass').transform(np.mean)['Age']
df
Out[5]:
  PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked Age2
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S 25.140620
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C 38.233441
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S 25.140620
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S 38.233441
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S 25.140620
... ... ... ... ... ... ... ... ... ... ... ... ... ...
886 887 0 2 Montvila, Rev. Juozas male 27.0 0 0 211536 13.0000 NaN S 29.877630
887 888 1 1 Graham, Miss. Margaret Edith female 19.0 0 0 112053 30.0000 B42 S 38.233441
888 889 0 3 Johnston, Miss. Catherine Helen "Carrie" female NaN 1 2 W./C. 6607 23.4500 NaN S 25.140620
889 890 1 1 Behr, Mr. Karl Howell male 26.0 0 0 111369 30.0000 C148 C 38.233441
890 891 0 3 Dooley, Mr. Patrick male 32.0 0 0 370376 7.7500 NaN Q 25.140620

891 rows × 13 columns

In [9]:
df[df['Pclass'] == 2]['Age2'] ## 전부 동일
Out[9]:
9      29.87763
15     29.87763
17     29.87763
20     29.87763
21     29.87763
         ...   
866    29.87763
874    29.87763
880    29.87763
883    29.87763
886    29.87763
Name: Age2, Length: 184, dtype: float64
In [10]:
## 다중 그룹핑 사용
df['Age3'] = df.groupby(['Pclass', 'Sex']).transform(np.mean)['Age']
df.head()
Out[10]:
  PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked Age2 Age3
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S 25.140620 26.507589
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C 38.233441 34.611765
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S 25.140620 21.750000
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S 38.233441 34.611765
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S 25.140620 26.507589
 

3. pivot, pivot_table 함수의 이해 및 활용¶

In [24]:
df = pd.DataFrame({
    '지역': ['서울', '서울', '서울', '경기', '경기', '부산', '서울', '서울', '부산', '경기', '경기', '경기'],
    '요일': ['월요일', '화요일', '수요일', '월요일', '화요일', '월요일', '목요일', '금요일', '화요일', '수요일', '목요일', '금요일'],
    '강수량': [100, 80, 1000, 200, 200, 100, 50, 100, 200, 100, 50, 100],
    '강수확률': [80, 70, 90, 10, 20, 30, 50, 90, 20, 80, 50, 10]
                  })

df
Out[24]:
  지역 요일 강수량 강수확률
0 서울 월요일 100 80
1 서울 화요일 80 70
2 서울 수요일 1000 90
3 경기 월요일 200 10
4 경기 화요일 200 20
5 부산 월요일 100 30
6 서울 목요일 50 50
7 서울 금요일 100 90
8 부산 화요일 200 20
9 경기 수요일 100 80
10 경기 목요일 50 50
11 경기 금요일 100 10
 

pivot¶

  • dataframe의 형태를 변경
  • 인덱스, 컬럼, 데이터로 사용할 컬럼을 명시
In [25]:
df.pivot(index = '지역', columns = '요일') # value를 따로 지정하지 않으면 자동 지정
Out[25]:
  강수량 강수확률
요일 금요일 목요일 수요일 월요일 화요일 금요일 목요일 수요일 월요일 화요일
지역                    
경기 100.0 50.0 100.0 200.0 200.0 10.0 50.0 80.0 10.0 20.0
부산 NaN NaN NaN 100.0 200.0 NaN NaN NaN 30.0 20.0
서울 100.0 50.0 1000.0 100.0 80.0 90.0 50.0 90.0 80.0 70.0
In [26]:
df.pivot(index = '요일', columns = '지역')
Out[26]:
  강수량 강수확률
지역 경기 부산 서울 경기 부산 서울
요일            
금요일 100.0 NaN 100.0 10.0 NaN 90.0
목요일 50.0 NaN 50.0 50.0 NaN 50.0
수요일 100.0 NaN 1000.0 80.0 NaN 90.0
월요일 200.0 100.0 100.0 10.0 30.0 80.0
화요일 200.0 200.0 80.0 20.0 20.0 70.0
In [29]:
df.pivot(index = '요일', columns = '지역', values = '강수량')
Out[29]:
지역 경기 부산 서울
요일      
금요일 100.0 NaN 100.0
목요일 50.0 NaN 50.0
수요일 100.0 NaN 1000.0
월요일 200.0 100.0 100.0
화요일 200.0 200.0 80.0
 

pivot_table¶

  • 기능적으로 pivot과 동일
  • pivot과의 차이점
    • 중복되는 모호한 값이 있을 경우, aggregation 함수 사용하여 값을 채움
In [30]:
## 중복된 데이터 적용한 df
df = pd.DataFrame({
    '지역': ['서울', '서울', '서울', '경기', '경기', '부산', '서울', '서울', '부산', '경기', '경기', '경기'],
    '요일': ['월요일', '월요일', '수요일', '월요일', '화요일', '월요일', '목요일', '금요일', '화요일', '수요일', '목요일', '금요일'],
    '강수량': [100, 80, 1000, 200, 200, 100, 50, 100, 200, 100, 50, 100],
    '강수확률': [80, 70, 90, 10, 20, 30, 50, 90, 20, 80, 50, 10]
                  })

df
Out[30]:
  지역 요일 강수량 강수확률
0 서울 월요일 100 80
1 서울 월요일 80 70
2 서울 수요일 1000 90
3 경기 월요일 200 10
4 경기 화요일 200 20
5 부산 월요일 100 30
6 서울 목요일 50 50
7 서울 금요일 100 90
8 부산 화요일 200 20
9 경기 수요일 100 80
10 경기 목요일 50 50
11 경기 금요일 100 10
In [31]:
## 중복 허용 후 호출 --> ERROR
df.pivot(index = '지역', columns = '요일')
 
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-31-87ad897658bd> in <module>
      1 ## 중복 허용 후 호출
----> 2 df.pivot(index = '지역', columns = '요일') # value를 따로 지정하지 않으면 자동 지정

~\Anaconda3\lib\site-packages\pandas\core\frame.py in pivot(self, index, columns, values)
   5917         from pandas.core.reshape.pivot import pivot
   5918 
-> 5919         return pivot(self, index=index, columns=columns, values=values)
   5920 
   5921     _shared_docs[

~\Anaconda3\lib\site-packages\pandas\core\reshape\pivot.py in pivot(data, index, columns, values)
    428         else:
    429             indexed = data._constructor_sliced(data[values].values, index=index)
--> 430     return indexed.unstack(columns)
    431 
    432 

~\Anaconda3\lib\site-packages\pandas\core\frame.py in unstack(self, level, fill_value)
   6376         from pandas.core.reshape.reshape import unstack
   6377 
-> 6378         return unstack(self, level, fill_value)
   6379 
   6380     _shared_docs[

~\Anaconda3\lib\site-packages\pandas\core\reshape\reshape.py in unstack(obj, level, fill_value)
    410     if isinstance(obj, DataFrame):
    411         if isinstance(obj.index, MultiIndex):
--> 412             return _unstack_frame(obj, level, fill_value=fill_value)
    413         else:
    414             return obj.T.stack(dropna=False)

~\Anaconda3\lib\site-packages\pandas\core\reshape\reshape.py in _unstack_frame(obj, level, fill_value)
    440             value_columns=obj.columns,
    441             fill_value=fill_value,
--> 442             constructor=obj._constructor,
    443         )
    444         return unstacker.get_result()

~\Anaconda3\lib\site-packages\pandas\core\reshape\reshape.py in __init__(self, values, index, level, value_columns, fill_value, constructor)
    140 
    141         self._make_sorted_values_labels()
--> 142         self._make_selectors()
    143 
    144     def _make_sorted_values_labels(self):

~\Anaconda3\lib\site-packages\pandas\core\reshape\reshape.py in _make_selectors(self)
    178 
    179         if mask.sum() < len(self.index):
--> 180             raise ValueError("Index contains duplicate entries, " "cannot reshape")
    181 
    182         self.group_index = comp_index

ValueError: Index contains duplicate entries, cannot reshape
In [32]:
## 중복된 값은 aggfunc으로 처리
pd.pivot_table(df, index = '지역', columns = '요일', aggfunc = np.mean)
Out[32]:
  강수량 강수확률
요일 금요일 목요일 수요일 월요일 화요일 금요일 목요일 수요일 월요일 화요일
지역                    
경기 100.0 50.0 100.0 200.0 200.0 10.0 50.0 80.0 10.0 20.0
부산 NaN NaN NaN 100.0 200.0 NaN NaN NaN 30.0 20.0
서울 100.0 50.0 1000.0 90.0 NaN 90.0 50.0 90.0 75.0 NaN
 

4. stack, unstack함수의 이해 및 활용하기¶

 

stack & unstack¶

  • stack : 컬럼 레벨에서 인덱스 레벨로 dataframe 변경
    • 즉, 데이터를 쌓아올리는 개념으로 이해하면 쉬움
  • unstack : 인덱스 레벨에서 컬럼 레벨로 dataframe 변경

    • stack의 반대 operation
  • 둘은 역의 관계에 있음

In [35]:
df = pd.DataFrame({
    '지역': ['서울', '서울', '서울', '경기', '경기', '부산', '서울', '서울', '부산', '경기', '경기', '경기'],
    '요일': ['월요일', '화요일', '수요일', '월요일', '화요일', '월요일', '목요일', '금요일', '화요일', '수요일', '목요일', '금요일'],
    '강수량': [100, 80, 1000, 200, 200, 100, 50, 100, 200, 100, 50, 100],
    '강수확률': [80, 70, 90, 10, 20, 30, 50, 90, 20, 80, 50, 10]
                  })

df
Out[35]:
  지역 요일 강수량 강수확률
0 서울 월요일 100 80
1 서울 화요일 80 70
2 서울 수요일 1000 90
3 경기 월요일 200 10
4 경기 화요일 200 20
5 부산 월요일 100 30
6 서울 목요일 50 50
7 서울 금요일 100 90
8 부산 화요일 200 20
9 경기 수요일 100 80
10 경기 목요일 50 50
11 경기 금요일 100 10
In [37]:
# 멀티 인덱스 생성
new_df = df.set_index(['지역', '요일'])
new_df
Out[37]:
    강수량 강수확률
지역 요일    
서울 월요일 100 80
화요일 80 70
수요일 1000 90
경기 월요일 200 10
화요일 200 20
부산 월요일 100 30
서울 목요일 50 50
금요일 100 90
부산 화요일 200 20
경기 수요일 100 80
목요일 50 50
금요일 100 10
In [38]:
new_df.unstack(0)  # 0번째 인덱스 (지역 인덱스)를 column 레벨로 올려라
Out[38]:
  강수량 강수확률
지역 경기 부산 서울 경기 부산 서울
요일            
금요일 100.0 NaN 100.0 10.0 NaN 90.0
목요일 50.0 NaN 50.0 50.0 NaN 50.0
수요일 100.0 NaN 1000.0 80.0 NaN 90.0
월요일 200.0 100.0 100.0 10.0 30.0 80.0
화요일 200.0 200.0 80.0 20.0 20.0 70.0
In [39]:
new_df.unstack(1)  # 0번째 인덱스 (요일 인덱스)를 column 레벨로 올려라
Out[39]:
  강수량 강수확률
요일 금요일 목요일 수요일 월요일 화요일 금요일 목요일 수요일 월요일 화요일
지역                    
경기 100.0 50.0 100.0 200.0 200.0 10.0 50.0 80.0 10.0 20.0
부산 NaN NaN NaN 100.0 200.0 NaN NaN NaN 30.0 20.0
서울 100.0 50.0 1000.0 100.0 80.0 90.0 50.0 90.0 80.0 70.0
In [40]:
new_df.unstack(0).stack(0)  # 0번째 컬럼(안쪽부터)을 인덱스 레벨로 올려라
Out[40]:
  지역 경기 부산 서울
요일        
금요일 강수량 100.0 NaN 100.0
강수확률 10.0 NaN 90.0
목요일 강수량 50.0 NaN 50.0
강수확률 50.0 NaN 50.0
수요일 강수량 100.0 NaN 1000.0
강수확률 80.0 NaN 90.0
월요일 강수량 200.0 100.0 100.0
강수확률 10.0 30.0 80.0
화요일 강수량 200.0 200.0 80.0
강수확률 20.0 20.0 70.0
In [41]:
new_df.unstack(0).stack(1)  # 1번째 컬럼(안쪽부터)을 인덱스 레벨로 올려라
Out[41]:
    강수량 강수확률
요일 지역    
금요일 경기 100.0 10.0
서울 100.0 90.0
목요일 경기 50.0 50.0
서울 50.0 50.0
수요일 경기 100.0 80.0
서울 1000.0 90.0
월요일 경기 200.0 10.0
부산 100.0 30.0
서울 100.0 80.0
화요일 경기 200.0 20.0
부산 200.0 20.0
서울 80.0 70.0
 

5. concat 함수로 데이터 프레임 병합하기¶

 

concat 함수 사용하여 dataframe 병합하기¶

  • pandas.concat 함수
  • 축을 따라 dataframe을 병합 가능
    • 기본 axis = 0 -> 행단위 병합
    • axis = 1 -> 열단위 병합
 
  • column 명이 같은 경우
In [43]:
df1 = pd.DataFrame({'key1' : np.arange(10), 'value1' : np.random.randn(10)})
In [42]:
df2 = pd.DataFrame({'key1' : np.arange(10), 'value1' : np.random.randn(10)})
In [44]:
pd.concat([df1, df2]) # default : axis = 0 : 행 기준
Out[44]:
  key1 value1
0 0 -0.614253
1 1 0.142883
2 2 -0.957883
3 3 1.095105
4 4 -0.969713
5 5 0.023303
6 6 -1.526878
7 7 -0.832049
8 8 -0.877996
9 9 1.300475
0 0 -0.319779
1 1 -0.852484
2 2 -1.356522
3 3 1.879422
4 4 -1.477988
5 5 0.502828
6 6 -0.292192
7 7 1.667929
8 8 0.509563
9 9 -1.422695
In [45]:
pd.concat([df1, df2], axis = 1) # 열 레벨 기준
Out[45]:
  key1 value1 key1 value1
0 0 -0.614253 0 -0.319779
1 1 0.142883 1 -0.852484
2 2 -0.957883 2 -1.356522
3 3 1.095105 3 1.879422
4 4 -0.969713 4 -1.477988
5 5 0.023303 5 0.502828
6 6 -1.526878 6 -0.292192
7 7 -0.832049 7 1.667929
8 8 -0.877996 8 0.509563
9 9 1.300475 9 -1.422695
 
  • column 명이 다른경우
In [46]:
df3 = pd.DataFrame({'key2' : np.arange(10), 'value2' : np.random.randn(10)})
In [47]:
pd.concat([df1, df3]) # 컬럼이 맞지 않으면 추가 데이터 생성하고, na를 생성
 
C:\Users\AgileSoda\Anaconda3\lib\site-packages\ipykernel_launcher.py:1: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version
of pandas will change to not sort by default.

To accept the future behavior, pass 'sort=False'.

To retain the current behavior and silence the warning, pass 'sort=True'.

  """Entry point for launching an IPython kernel.
Out[47]:
  key1 key2 value1 value2
0 0.0 NaN -0.614253 NaN
1 1.0 NaN 0.142883 NaN
2 2.0 NaN -0.957883 NaN
3 3.0 NaN 1.095105 NaN
4 4.0 NaN -0.969713 NaN
5 5.0 NaN 0.023303 NaN
6 6.0 NaN -1.526878 NaN
7 7.0 NaN -0.832049 NaN
8 8.0 NaN -0.877996 NaN
9 9.0 NaN 1.300475 NaN
0 NaN 0.0 NaN -1.379786
1 NaN 1.0 NaN 0.104352
2 NaN 2.0 NaN -1.074068
3 NaN 3.0 NaN -0.467306
4 NaN 4.0 NaN -1.128717
5 NaN 5.0 NaN 0.033288
6 NaN 6.0 NaN -0.160514
7 NaN 7.0 NaN 0.654068
8 NaN 8.0 NaN 0.021267
9 NaN 9.0 NaN 0.237304
 

Merge & join 함수로 데이터 프레임 병합하기¶

 

dataframe merge¶

  • SQL의 join처럼 특정한 column을 기준으로 병합

    • join 방식: how 파라미터를 통해 명시
      • inner: 기본값, 일치하는 값이 있는 경우
      • left: left outer join
      • right: right outer join
      • outer: full outer join
  • pandas.merge 함수가 사용됨

In [48]:
customer = pd.DataFrame({'customer_id' : np.arange(6), 
                    'name' : ['철수'"", '영희', '길동', '영수', '수민', '동건'], 
                    '나이' : [40, 20, 21, 30, 31, 18]})

customer
Out[48]:
  customer_id name 나이
0 0 철수 40
1 1 영희 20
2 2 길동 21
3 3 영수 30
4 4 수민 31
5 5 동건 18
In [49]:
orders = pd.DataFrame({'customer_id' : [1, 1, 2, 2, 2, 3, 3, 1, 4, 9], 
                    'item' : ['치약', '칫솔', '이어폰', '헤드셋', '수건', '생수', '수건', '치약', '생수', '케이스'], 
                    'quantity' : [1, 2, 1, 1, 3, 2, 2, 3, 2, 1]})
orders.head()
Out[49]:
  customer_id item quantity
0 1 치약 1
1 1 칫솔 2
2 2 이어폰 1
3 2 헤드셋 1
4 2 수건 3
 
  • on
    • join 대상이 되는 column 명시
In [50]:
pd.merge(customer, orders,
         on = 'customer_id', # 무엇을 기준으로 merge할 것인지
         how = 'inner'  # 어떻게 조인할 것인지 (inner, left, outer, right)
        )
Out[50]:
  customer_id name 나이 item quantity
0 1 영희 20 치약 1
1 1 영희 20 칫솔 2
2 1 영희 20 치약 3
3 2 길동 21 이어폰 1
4 2 길동 21 헤드셋 1
5 2 길동 21 수건 3
6 3 영수 30 생수 2
7 3 영수 30 수건 2
8 4 수민 31 생수 2
In [51]:
pd.merge(customer, orders,
         on = 'customer_id', # 무엇을 기준으로 merge할 것인지
         how = 'left'  # 왼쪽을 기준으로 merge. 값이 없으면 NA
        )b
Out[51]:
  customer_id name 나이 item quantity
0 0 철수 40 NaN NaN
1 1 영희 20 치약 1.0
2 1 영희 20 칫솔 2.0
3 1 영희 20 치약 3.0
4 2 길동 21 이어폰 1.0
5 2 길동 21 헤드셋 1.0
6 2 길동 21 수건 3.0
7 3 영수 30 생수 2.0
8 3 영수 30 수건 2.0
9 4 수민 31 생수 2.0
10 5 동건 18 NaN NaN
 
  • index 기준으로 join하기
In [52]:
cust1 = customer.set_index('customer_id')
order1 = orders.set_index('customer_id')
In [53]:
cust1
Out[53]:
  name 나이
customer_id    
0 철수 40
1 영희 20
2 길동 21
3 영수 30
4 수민 31
5 동건 18
In [54]:
order1
Out[54]:
  item quantity
customer_id    
1 치약 1
1 칫솔 2
2 이어폰 1
2 헤드셋 1
2 수건 3
3 생수 2
3 수건 2
1 치약 3
4 생수 2
9 케이스 1
In [55]:
pd.merge(cust1, order1, left_index = True, right_index = True)
Out[55]:
  name 나이 item quantity
customer_id        
1 영희 20 치약 1
1 영희 20 칫솔 2
1 영희 20 치약 3
2 길동 21 이어폰 1
2 길동 21 헤드셋 1
2 길동 21 수건 3
3 영수 30 생수 2
3 영수 30 수건 2
4 수민 31 생수 2
 

연습문제¶

  1. 가장 많이 팔린 아이템은?
  2. 영희가 가장 많이 구매한 아이템은?
In [61]:
# 1. 가장 많이 팔린 아이템은? -> 수건
pd.merge(customer, orders, on = 'customer_id').groupby('item').sum().sort_values(by = 'quantity', ascending = False)
Out[61]:
  customer_id 나이 quantity
item      
수건 5 51 5
생수 7 61 4
치약 2 40 4
칫솔 1 20 2
이어폰 2 21 1
헤드셋 2 21 1
In [65]:
# 2. 영희가 가장 많이 구매한 아이템은? -> 치약
pd.merge(customer, orders, on = 'customer_id').groupby(['name', 'item']).sum().loc['영희', 'quantity']
Out[65]:
item
치약    4
칫솔    2
Name: quantity, dtype: int64
 

join 함수¶

  • 내부적으로 pandas.merge 함수 사용
  • 기본적으로 index를 사용하여 left join
In [68]:
cust1.join(order1, how = 'inner') ## merge와 동일
Out[68]:
  name 나이 item quantity
customer_id        
1 영희 20 치약 1
1 영희 20 칫솔 2
1 영희 20 치약 3
2 길동 21 이어폰 1
2 길동 21 헤드셋 1
2 길동 21 수건 3
3 영수 30 생수 2
3 영수 30 수건 2
4 수민 31 생수 2
반응형

'AI Study > ML_Basic' 카테고리의 다른 글

머신러닝과 데이터 분석 A-Z 올인원 패키지 - 회귀분석_수학적 개념 이해(2) - 통계적 추론과 검정통계  (0) 2020.12.08
머신러닝과 데이터 분석 A-Z 올인원 패키지 - 회귀분석_수학적 개념 이해(1) - 확률과 통계  (0) 2020.12.03
머신러닝과 데이터 분석 A-Z 올인원 패키지 - 데이터 분석을 위한 Python(Pandas) – (2)  (0) 2020.09.30
머신러닝과 데이터 분석 A-Z 올인원 패키지 - 데이터 분석을 위한 Python(Pandas) – (1)  (0) 2020.09.30
머신러닝과 데이터 분석 A-Z 올인원 패키지 - 데이터 처리를 위한 Python(Numpy)(2)  (0) 2020.09.30
'AI Study/ML_Basic' 카테고리의 다른 글
  • 머신러닝과 데이터 분석 A-Z 올인원 패키지 - 회귀분석_수학적 개념 이해(2) - 통계적 추론과 검정통계
  • 머신러닝과 데이터 분석 A-Z 올인원 패키지 - 회귀분석_수학적 개념 이해(1) - 확률과 통계
  • 머신러닝과 데이터 분석 A-Z 올인원 패키지 - 데이터 분석을 위한 Python(Pandas) – (2)
  • 머신러닝과 데이터 분석 A-Z 올인원 패키지 - 데이터 분석을 위한 Python(Pandas) – (1)
자동화먹
자동화먹
많은 사람들에게 도움이 되는 생산적인 기록하기
    반응형
  • 자동화먹
    자동화먹의 생산적인 기록
    자동화먹
  • 전체
    오늘
    어제
    • 분류 전체보기 (144)
      • 생산성 & 자동화 툴 (30)
        • Notion (24)
        • Obsidian (0)
        • Make.com (1)
        • tips (5)
      • Programming (37)
        • Python (18)
        • Oracle (6)
        • Git (13)
      • AI Study (65)
        • DL_Basic (14)
        • ML_Basic (14)
        • NLP (21)
        • Marketing&Recommend (4)
        • chatGPT (0)
        • etc (12)
      • 주인장의 생각서랍 (10)
        • 생각정리 (4)
        • 독서기록 (6)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    nlp
    Google Cloud Platform
    딥러닝
    gcp
    머신러닝
    LSTM
    cnn
    파이토치로 시작하는 딥러닝 기초
    Github
    데이터분석
    notion
    빅데이터분석
    ML
    노션첫걸음
    데이터베이스
    pytorch
    GPT
    기초
    자연어처리
    Transformer
    빅데이터
    파이토치
    Python
    git commit
    python기초
    dl
    노션
    git
    seq2seq
    Jupyter notebook
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
자동화먹
머신러닝과 데이터 분석 A-Z 올인원 패키지 - 데이터 분석을 위한 Python(Pandas) – (3)
상단으로

티스토리툴바