데이터 재구조화(reshaping data)를 위해 사용할 수 있는 Python pandas의 함수들에 대해서 아래의 순서대로 나누어서 소개해보겠습니다.

 

 - (1) pivot(), pd.pivot_table()

 - (2) stack(), unstack()

 - (3) melt()

 - (4) wide_to_long()

 - (4) pd.crosstab() 

 

 

이번 포스팅에서는 두번째로 pd.DataFrame.stack(), pd.DataFrame.unstack()에 대해서 알아보겠습니다.

 

 

 

stack을 영어사전에서 찾아보면 뜻이

stack[stӕk]

~ (sth) (up) (깔끔하게 정돈하여) 쌓다[포개다]; 쌓이다, 포개지다
~ sth (with sth) (어떤 곳에 물건을 쌓아서) 채우다

 

라는 뜻입니다.

 

stack이 (위에서 아래로 길게, 높게) 쌓는 것이면, unstack은 쌓은 것을 옆으로 늘어놓는것(왼쪽에서 오른쪽으로 넓게) 라고 연상이 될 것입니다.

 

Python pandas의 stack(), unstack() 실습에 필요한 모듈을 불러오고, 예제로 사용할 hierarchical index를 가진 DataFrame을 만들어보겠습니다.  

 

 

 

In [1]: import numpy as np


In [2]: import pandas as pd


In [3]: from pandas import DataFrame


In [4]: mul_index = pd.MultiIndex.from_tuples([('cust_1', '2015'), ('cust_1', '2016'),

   ...: ('cust_2', '2015'), ('cust_2', '2016')])

   ...:


In [5]: data = DataFrame(data=np.arange(16).reshape(4, 4),

   ...: index=mul_index,

   ...: columns=['prd_1', 'prd_2', 'prd_3', 'prd_4'],

   ...: dtype='int')

   ...:


In [6]: data

Out[6]:

                 prd_1  prd_2  prd_3  prd_4
cust_1 2015      0       1      2      3
         2016      4       5      6      7
cust_2 2015      8       9     10     11
         2016     12     13     14     15


 

 

 

 

 

stack() method 를 사용해서 위의 예제 데이터셋을 위에서 아래로 길게(높게) 쌓아(stack) 보겠습니다.  칼럼의 level은 1개 밖에 없으므로 stack(level=-1) 을 별도로 명기하지 않아도 됩니다.

 

 

  (1) pd.DataFrame.stack(level=-1, dropna=True)

 

DataFrame을 stack() 후에 index를 확인해보고, indexing 해보겠습니다.

DataFrame을 stack() 하면 Series 를 반환합니다.

 

 

# stack()

In [7]: data_stacked = data.stack()

 

# DataFrame.stack() => returns Series

In [8]: data_stacked

Out[8]:

cust_1  2015  prd_1     0
                  prd_2     1
                  prd_3     2
                  prd_4     3
          2016  prd_1     4
                  prd_2     5
                  prd_3     6
                  prd_4     7
cust_2  2015  prd_1     8
                  prd_2     9
                  prd_3    10
                  prd_4    11
          2016  prd_1    12
                  prd_2    13
                  prd_3    14
                  prd_4    15

dtype: int32

 


# MultiIndex(levels) after stack()

In [9]: data_stacked.index

Out[9]:

MultiIndex(levels=[['cust_1', 'cust_2'], ['2015', '2016'], ['prd_1', 'prd_2', 'prd_3', 'prd_4']],

labels=[[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1], [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]])

 


# indexing

In [10]: data_stacked['cust_2']['2015'][['prd_1', 'prd_2']]

Out[10]:

prd_1 8

prd_2 9

dtype: int32

 

 

 

 

결측값이 있는 데이터셋을 stack() 할 때 결측값을 제거할지(dropna=True), 아니면 결측값을 NaN으로 유지할지(dropna=False) 설정할 수 있는 stack(dropna=True, False)를 예를 들어 설명해보겠습니다.

 

 

# # putting NaN to DataFrame

In [11]: data.ix['cust_2', 'prd_4'] = np.nan


In [12]: data

Out[12]:

             prd_1  prd_2  prd_3  prd_4
cust_1 2015      0      1      2    3.0
         2016      4      5      6    7.0
cust_2 2015      8      9     10    NaN
         2016     12     13     14    NaN

 


# stack with 'dropna=False' argument

In [13]: data.stack(dropna=False)

Out[13]:

cust_1  2015  prd_1     0.0
                  prd_2     1.0
                  prd_3     2.0
                  prd_4     3.0
          2016  prd_1     4.0
                  prd_2     5.0
                  prd_3     6.0
                  prd_4     7.0
cust_2  2015  prd_1     8.0
                  prd_2     9.0
                  prd_3    10.0
                  prd_4     NaN
          2016  prd_1    12.0
                  prd_2    13.0
                  prd_3    14.0
                  prd_4     NaN

dtype: float64

 


# stack with 'dropna=True' argument

In [14]: data.stack(dropna=True) # by default

Out[14]:

cust_1  2015  prd_1     0.0
                  prd_2     1.0
                  prd_3     2.0
                  prd_4     3.0
          2016  prd_1     4.0
                  prd_2     5.0
                  prd_3     6.0
                  prd_4     7.0
cust_2  2015  prd_1     8.0
                  prd_2     9.0
                  prd_3    10.0
          2016  prd_1    12.0
                  prd_2    13.0
                  prd_3    14.0

dtype: float64

 

 

 

 

 

stack()으로 위에서 아래로 길게(높게) 쌓아 올린 데이터셋을 이번에는 거꾸로 왼쪽으로 오른쪽으로 넓게 unstack()으로 풀어보겠습니다. 

 

stack() 후의 data_stacked 데이터셋이 아래에 보는 것처럼 level이 3개 있는 MultiIndex 입니다. 이럴 경우 unstack(level=-1), unstack(level=0), unstack(level=1) 별로 어떤 level이 칼럼으로 이동해서 unstack() 되는지 유심히 살펴보시기 바랍니다. 

 

  (2) pd.DataFrame.unstack(level=-1, fill_value=None)

 

 

In [15]: data_stacked

Out[15]:

cust_1  2015  prd_1     0
                  prd_2     1
                  prd_3     2
                  prd_4     3
          2016  prd_1     4
                  prd_2     5
                  prd_3     6
                  prd_4     7
cust_2  2015  prd_1     8
                  prd_2     9
                  prd_3    10
                  prd_4    11
          2016  prd_1    12
                  prd_2    13
                  prd_3    14
                  prd_4    15

dtype: int32


In [16]: data_stacked.unstack(level=-1)

Out[16]:

                 prd_1  prd_2  prd_3  prd_4
cust_1 2015      0      1      2      3
         2016      4      5      6      7
cust_2 2015      8      9     10     11
         2016     12     13     14     15


In [17]: data_stacked.unstack(level=0)

Out[17]:

                cust_1  cust_2
2015 prd_1       0       8
       prd_2       1       9
       prd_3       2      10
       prd_4       3      11
2016 prd_1       4      12
       prd_2       5      13
       prd_3       6      14
       prd_4       7      15

 

In [18]: data_stacked.unstack(level=1)

Out[18]:

                  2015  2016
cust_1 prd_1     0     4
         prd_2     1     5
         prd_3     2     6
         prd_4     3     7
cust_2 prd_1     8    12
         prd_2     9    13
         prd_3    10    14
         prd_4    11    15

 

 

 

 

unstack() 한 후의 데이터셋도 역시 Series 인데요, 이것을 DataFrame으로 변환해보겠습니다.

 

 

# converting Series to DataFrame

In [19]: data_stacked_unstacked = data_stacked.unstack(level=-1)


In [20]: data_stacked_unstacked

Out[20]:

                prd_1  prd_2  prd_3  prd_4
cust_1 2015      0      1      2      3
         2016      4      5      6      7
cust_2 2015      8      9     10     11
         2016     12     13     14     15

 

# converting index to columns

In [21]: data_stacked_unstacked_df = data_stacked_unstacked.reset_index()

 

# changing columns' name

In [22]: data_stacked_unstacked_df.rename(columns={'level_0' : 'custID',

    ...: 'level_1' : 'year'}, inplace=True)

    ...:


In [23]: data_stacked_unstacked_df

Out[23]:

    custID  year  prd_1  prd_2  prd_3  prd_4
0  cust_1  2015      0      1      2      3
1  cust_1  2016      4      5      6      7
2  cust_2  2015      8      9     10     11
3  cust_2  2016     12     13     14     15

 

 

 

 

이상으로 stack(), unstack()을 이용한 데이터 재구조화에 대해서 알아보았습니다.  

 

다음번 포스팅에서는 melt(), wide_to_long() 을 이용한 데이터 재구조화를 소개하겠습니다.

 

많은 도움 되었기를 바랍니다.

 

 

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by R Friend R_Friend

분석을 하다 보면 원본 데이터의 구조가 분석 기법에 맞지 않아서 행과 열의 위치를 바꾼다거나, 특정 요인에 따라 집계를 해서 구조를 바꿔주어야 하는 경우가 있습니다.

 

이번 포스팅부터는 이처럼 데이터 재구조화(reshaping data)를 위해 사용할 수 있는 Python pandas의 함수들에 대해서 아래의 순서대로 나누어서 소개해보겠습니다.

 

 - (1) pivot(), pd.pivot_table()

 - (2) stack(), unstack()

 - (3) melt()

 - (4) wide_to_long()

 - (5) pd.crosstab() 

 

 

이번 포스팅에서는 첫번째로 data.pivot(), pd.pivot_table(data)에 대해서 알아보겠습니다.

 

 

 

 

먼저, 필요한 모듈을 불러오고, 간단한 예제 데이터셋을 만들어보겠습니다.  고객ID(cust_id), 상품 코드(prod_cd), 등급(grade), 구매금액(pch_amt) 의 4개 변수로 이루어진 데이터 프레임입니다.

 

 

# importing libraries

 

In [1]: import numpy as np


In [2]: import pandas as pd


In [3]: from pandas import DataFrame

 

 

# making an example DataFrame

In [4]: data = DataFrame({'cust_id': ['c1', 'c1', 'c1', 'c2', 'c2', 'c2', 'c3', 'c3', 'c3'],

   ...: 'prod_cd': ['p1', 'p2', 'p3', 'p1', 'p2', 'p3', 'p1', 'p2', 'p3'],

   ...: 'grade' : ['A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B'],

   ...: 'pch_amt': [30, 10, 0, 40, 15, 30, 0, 0, 10]})

   ...:


In [5]: data

Out[5]:

  cust_id grade  pch_amt prod_cd
0      c1     A       30      p1
1      c1     A       10      p2
2      c1     A        0      p3
3      c2     A       40      p1
4      c2     A       15      p2
5      c2     A       30      p3
6      c3     B        0      p1
7      c3     B        0      p2
8      c3     B       10      p3

 

 

 

 

위의 data 예제처럼 위에서 아래로 길게 늘어서 있는 데이터셋을 행(row)에는 고객ID(cust_id), 열(column)에는 상품코드(prd_cd), 행과 열이 교차하는 칸에는 구매금액(pch_amt)이 위치하도록 데이터를 구조를 바꿔보겠습니다.  말로 설명해도 이해가 잘 안될 수 있는데요, 아래 data.pivot(index, columns, values) 예시를 보시지요.

 

 

  (1) 데이터 재구조화 : data.pivot(index, columns, values)

 

 

# reshaping DataFrame by pivoting

 

In [6]: data_pivot = data.pivot(index='cust_id', columns='prod_cd', values='pch_amt')


In [7]: data_pivot

Out[7]:

prod_cd  p1  p2  p3
cust_id           
c1       30  10   0
c2       40  15  30
c3        0   0  10

 

 

 

 

 

  (2) 데이터 재구조화 : pd.pivot_table(data, index, columns, values, aggfunc)

 

위의 data.pivot() 과 동일한 결과가 나오도록 데이터를 재구조화하는데 pd.pivot_table()을 사용할 수도 있습니다.

 

 

# pd.pivot_table(data, index, columns, values, aggfunc)

 

In [8]: pd.pivot_table(data, index='cust_id', columns='prod_cd', values='pch_amt')

Out[8]:

prod_cd  p1  p2  p3
cust_id           
c1       30  10   0
c2       40  15  30
c3        0   0  10

 

 

 

 

data.pivot() 로 하면 에러가 나서 안되고, pivot_table(data) 을 사용해야만 하는 경우가 몇 가지 있습니다.  그러므로 여러가지 외우는거 싫고, 헷갈리는거 싫어하는 분이라면 pivot_table() 사용법만 잘 숙지하는 것도 좋은 방법입니다.

 

아래에 pivot()으로는 안되고 pivot_table()은 되는 경우를 나란히 이어서 제시해보겠습니다.

 

(a) index 가 2개 이상인 경우입니다.

 

 

# pivot() with 2 indices :ValueError

 

In [9]: data.pivot(index=['cust_id', 'grade'], columns='prod_cd', values='pch_amt')

ValueError: Wrong number of items passed 9, placement implies 2

 

 

# pd.pivot_table() with 2 indices : works well!

 

In [10]: pd.pivot_table(data, index=['cust_id', 'grade'], columns='prod_cd', values='pch_amt')

Out[10]:

prod_cd        p1  p2  p3
cust_id grade           
c1      A      30  10   0
c2      A      40  15  30
c3      B       0   0  10

 

 

 

 

(b) columns 가 2개 이상인 경우 입니다.

 

 

# pivot() with 2 columns : KeyError

 

In [11]: data.pivot(index='cust_id', columns=['grade', 'prod_cd'], values='pch_amt')

KeyError: 'Level grade not found'

 

 

# pd.pivot_table() with 2 columns : works well!

 

In [12]: pd.pivot_table(data, index='cust_id', columns=['grade', 'prod_cd'], values='pch_amt')

Out[12]:

grade A B

grade       A                B          
prod_cd    p1    p2    p3   p1   p2    p3
cust_id                                 
c1       30.0  10.0   0.0  NaN  NaN   NaN
c2       40.0  15.0  30.0  NaN  NaN   NaN
c3        NaN   NaN   NaN  0.0  0.0  10.0

 

 

 

 

pivot() 함수는 중복값이 있을 경우 ValueError를 반환합니다.  반면에, pd.pivot_table()은 aggfunc=np.sum 혹은 aggfunc=np.mean 과 같이 집계(aggregation)할 수 있는 함수를 제공함에 따라 index 중복값이 있는 경우에도 문제가 없습니다.

 

 

# pivot() with index which contains duplicate entries: ValueError

In [13]: data.pivot(index='grade', columns='prod_cd', values='pch_amt')

ValueError: Index contains duplicate entries, cannot reshape

 

 

# pd.pivot_table() with aggfunc : works well!

 

In [14]: pd.pivot_table(data, index='grade', columns='prod_cd',

    ...: values='pch_amt', aggfunc=np.sum)

Out[14]:

prod_cd  p1  p2  p3
grade             
A        70  25  30
B         0   0  10

 

In [15]: pd.pivot_table(data, index='grade', columns='prod_cd',

    ...: values='pch_amt', aggfunc=np.mean)

Out[15]:

prod_cd    p1    p2    p3
grade                   
A        35.0  12.5  15.0
B         0.0   0.0  10.0


# pivot_table(aggfunc=np.mean), by default

In [16]: pd.pivot_table(data, index='grade', columns='prod_cd', values='pch_amt')

Out[16]:

prod_cd    p1    p2    p3
grade                   
A        35.0  12.5  15.0
B         0.0   0.0  10.0

 

 

 

 

pd.pivot_table()은 margins=True 옵션을 설정해주면 행과 열을 기준으로 합계(All, row sum, column sum)를 같이 제시해주기 때문에 꽤 편리합니다

 

 

# pd.pivot_table : margins=True
  # special All columns and rows will be added with partial group aggregates
  # across the categories on the rows and columns

 

In [17]: pd.pivot_table(data, index='grade', columns='prod_cd',

    ...: values='pch_amt', aggfunc=np.sum, margins=True)

Out[17]:

prod_cd    p1    p2    p3    All
grade                          
A        70.0  25.0  30.0  125.0
B         0.0   0.0  10.0   10.0
All      70.0  25.0  40.0  135.0

 

In [18]: pd.pivot_table(data, index='grade', columns='prod_cd',

    ...: values='pch_amt', aggfunc=np.mean, margins=True)

Out[18]:

prod_cd         p1         p2         p3        All
grade                                             
A        35.000000  12.500000  15.000000  20.833333
B         0.000000   0.000000  10.000000   3.333333
All      23.333333   8.333333  13.333333  15.000000

 

 

이상으로 data.pivot(), pd.povit_table(data)를 활용한 데이터 재구조화 소개를 마치겠습니다.

 

다음번 포스팅에서는 stack(), unstack()을 이용한 데이터 재구조화에 대해서 알아보겠습니다.

 

많은 도움 되었기를 바랍니다.

 

 

 

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by R Friend R_Friend

지난번 포스팅에서는

 

 - Python sklearn.preprocessing.Binarizer()를 이용한 연속형 변수의 이항변수화(binarization)

 

 - Python sklearn.preprocessing.OneHotEncoder()를 이용한 범주형 변수의 이항변수화

 

 - Python np.digitize(), np.where() 를 이용한 연속형 변수의 이산형화(discretization)

 

 

에 대해서 알아보겠습니다.

 

 

이번 포스팅에서는 sklearn.preprocessing.PolynomialFeatures() 를 이용한 다항차수 변환, 교호작용 변수 생성에 대해서 소개하겠습니다.

 

회귀분석할 때 다항 차수를 이용해서 비선형 패턴, 관계(non-linear relation)를 나타내거나, 변수 간 곱을 사용해서 교호작용 효과(interaction effects)을 나타낼 수 있는 변수를 만듭니다.

 

 

 

 

 

 

먼저 필요한 모듈을 불러오고, 예제 Arrary Dataset을 만들어보겠습니다.

 

 

 

In [1]: import numpy as np


In [2]: import pandas as pd


In [3]: from sklearn.preprocessing import PolynomialFeatures


In [4]: X = np.arange(6).reshape(3, 2)


In [5]: X

Out[5]:

array([[0, 1],
       [2, 3],
       [4, 5]])

 

 

 

 

 

  (1) sklearn.preprocessing.PolynomialFeatures()를 사용해 2차항 변수 만들기

 

 

 

# making 2-order polynomial features

 

In [6]: poly = PolynomialFeatures(degree=2)

 

 

# transform from (x1, x2) to (1, x1, x2, x1^2, x1*x2, x2^2)

In [7]: poly.fit_transform(X)

Out[7]:

array([[  1.,   0.,   1.,   0.,   0.,   1.],
       [  1.,   2.,   3.,   4.,   6.,   9.],
       [  1.,   4.,   5.,  16.,  20.,  25.]])

 

 

 

 

변수가 3개인 경우에는 다차항 변수와 교호작용 변수의 조합이 더 많아집니다(아래 예는 degree=2 로서 2차항 변수 & 교호작용 변수 생성 예시)변수가 추가 될 때마다 조합의 경우의 수가 기하급수적으로 늘어나게 되므로 유의할 필요가 있습니다.

 

 

In [8]: X2 = np.arange(9).reshape(3, 3)


In [9]: X2

Out[9]:

array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

 

 

# transform from (x1, x2, x3) to (1, x1, x2, x3, x1^2, x1*x2, x1*x3, x2^2, x2*x3, x3^2)

In [10]: poly.fit_transform(X2)

Out[10]:

array([[  1.,   0.,   1.,   2.,   0.,   0.,   0.,   1.,   2.,   4.],
       [  1.,   3.,   4.,   5.,   9.,  12.,  15.,  16.,  20.,  25.],
       [  1.,   6.,   7.,   8.,  36.,  42.,  48.,  49.,  56.,  64.]])

 

 

 

 

 

  (2) 교호작용 변수만을 만들기 : interaction_only=True

 

다항차수는 적용하지 않고, 오직 호작용 효과만을 분석하려면 interaction_only=True 옵션을 설정해주면 됩니다. degree를 가지고 교호작용을 몇 개 수준까지 볼 지 설정해줄 수 있습니다.

 

 

In [11]: X2

Out[11]:

array([[0, 1, 2],

[3, 4, 5],

[6, 7, 8]])

 

 

# transform from (x1, x2, x3) to (1, x1, x2, x3, x1*x2, x1*x3, x2*x3)

 

In [12]: poly_d2 = PolynomialFeatures(degree=2, interaction_only=True)


In [13]: poly_d2.fit_transform(X2)

Out[13]:

array([[  1.,   0.,   1.,   2.,   0.,   0.,   2.],
       [  1.,   3.,   4.,   5.,  12.,  15.,  20.],
       [  1.,   6.,   7.,   8.,  42.,  48.,  56.]])

 

 

# transform from (x1, x2, x3) to (1, x1, x2, x3, x1*x2, x1*x3, x2*x3, x1*x2*x3)

 

In [14]: poly_d3 = PolynomialFeatures(degree=3, interaction_only=True)

 

In [15]: poly_d3.fit_transform(X2)

Out[15]:

array([[   1.,    0.,    1.,    2.,    0.,    0.,    2.,    0.],
       [   1.,    3.,    4.,    5.,   12.,   15.,   20.,   60.],
       [   1.,    6.,    7.,    8.,   42.,   48.,   56.,  336.]])

 

 

 

 

이상으로 sklearn.preprocessing.PolynomialFeatures()를 이용한 다항차수 변환, 교호작용 변수 생성 방법 소개를 마치겠습니다.

 

 

다음번 포스팅에서는 데이터셋 재구조화(pivot, reshape)에 대해서 알아보겠습니다.

 

 

많은 도움 되었기를 바랍니다.

 

 

 

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by R Friend R_Friend


티스토리 툴바