본문 바로가기

Computer Science/파이썬

[데이터전처리] tidy-wide tabular data -변환-> Pivot Table, Melt

1. Wide Table (long-form형식)

이러한 데이터를 기반으로 실제로 구현, 변환을 해보겠습니다.

%matplotlib inline 
import pandas as pd 
import numpy as np 
import seaborn as sns 
wide_table1 = pd.DataFrame([[np.nan, 2], [16, 11], [3, 1]], index=['X', 'Y', 'Z'], columns=['A', 'B']) 
wide_table1
  A B
X NaN 2
Y 16.0 11
Z 3.0 1

wide_table1은 wide table의 형태 (=long-form)

테이블은 2개의 열과 3개의 행으로 구성되어 있으며 각각 라벨링 되어 있습니다.

 

2. Transpose (.T; 전치)

wide_table2는 wide_table1과 동일한 결과를 보여주지만, 행과 열이 전치 (transpose) 하여 레이아웃 변경

 

table2 = table1.T # transpose table2

 

 

  X Y Z
A NaN 16.0 3.0
B 2.0 11.0 1.0

 

3. Tidy table

tidy_table3 은 wide_table1을 값과 변수 그리고 관측을 더 명확하게 하기 위해서 다른 방식으로 재정리.

tidy_table3 은 wide_table1의 tidy 버전입니다.

각 행은 하나의 관측을 의미, 한 사람에 대해서 작업물 (column)과 그 결과 값이 포함

  • tidy 데이터의 목적

tidy 데이터는 Seaborn과 같은 시각화 라이브러리에서 유용하게 사용.

### Seaborn의 기능 중 한가지 예시입니다. 
import seaborn as sns 
sns.catplot(x = 'index', y = 'value', col = 'column', kind = 'bar', data = tidy1, height = 2);

4. Melt

### 행의 인덱스를 선택하고, 이를 행으로 새로 추가합니다. 
tidy1 = table1.reset_index() # rownames를 새로 설정 
tidy1

 

  index A B
0 X NaN 2
1 Y 16.0 11
2 Z 3.0 1
### 각 행에 대해서 (unique identifier)를 확인합니다.
### 한개의 "tidy" 한 열에 대해서 포함되어야 할 (기준이 되는) 데이터를 선택합니다.
tidy1 = tidy1.melt(id_vars = 'index', value_vars = ['A', 'B'])
tidy1
  index variable value
0 X A NaN
1 Y A 16.0
2 Z A 3.0
3 X B 2.0
4 Y B 11.0
5 Z B 1.0
  • tidy 는 한 행에, 한 observation
  • 한 observation에는 어떤 값들이 있어야 할까요?
  • 누가(id), 어떤 feature 값을 가지는지(value) Column을 지정해주면 됨
  • 이를 melt에 표현

5. Pivot table

pivot_table 함수는 melt의 반대 역할을 하는 함수입니다. tidy -> wide로 변환

 

# 파라미터에 대한 설명 
# index: unique identifier 
# columns: "wide" 데이터에서 column별로 다르게 하고자 하는 값. 
# values: 결과값이 들어가는 곳 (wide 데이터프레임의 내용에 들어갈 값) 
wide = tidy1.pivot_table(index = 'index', columns = 'column', values = 'value') wide
column A B
row    
X NaN 2.0
Y 16.0 11.0
Z 3.0 1.0

6. Pivot table - trial balance( 시산표; T/B)

피벗테이블 활용 시산표, 회계 형식의 표를 피벗테이블로 셈을 할 수 있게 바꾸는 방식.

위와 같은 장부형태의 데이터프레임을 피벗테이블(시산표)로 변경하여 진행

 

1. groupby

그룹핑을 하기 위해서는 pivot_table() 함수에서 필수적으로 다음의 파라미터가 들어가야 한다.

  • index = ['그룹핑하고 싶은 칼럼명1','그룹핑하고 싶은 칼럼명2',....]
pd.pivot_table(df, index = ['계정코드','계정과목'])
                          대변금액      전표번호      차변금액
계정코드  계정과목                                                 
10100 현금             1.947155e+06   32.096386   2.215687e+06
10300 보통예금         5.369730e+07   17.928077   5.406588e+07
10301 보통예금         0.000000e+00    7.500000   2.249914e+08
10400 제예금           2.988571e+08    37.857143  3.712944e+08
.....
[159 rows x 3 columns]

상기와 같이 df명, index만을 넣으면 데이터 타입이 숫자인 칼럼에 대해서 디폴트로 평균(averge) 값 도출

 

2. 수식 대입

평균값이 아닌 합계, 개수, 표준편차, 분산 등의 산식을 보여주려면 다음과 같이 하여야 한다.

산식을 넣는 방법은 하나의 산식을 넣는 경우는 다음과 같이 4가지 방법 중 하나를 선택할 수 있다.

  • aggfunc = 'sum'
  • aggfunc = sum
  • aggfunc = [sum]
  • aggfunc = ['sum']

두 개 이상의 산식을 넣는 경우에는 다음과 같이 3가지 방법 중 하나를 선택할 수 있다.

  • aggfunc = ['sum', 'count'...] 와 같이 리스트로 처리하면 된다.
  • aggfunc = [sum, count...] 와 같이 리스트로 처리하면 된다.
  • aggfunc = [np.sum,...]와 같이 numpy를 불러와서 처리할 수 있다.
pd.pivot_table(df, index = ['계정코드','계정과목'], aggfunc = 'sum')
                        대변금액  전표번호        차변금액
계정코드  계정과목                                    
10100 현금            27556846   735    37992648
10300 보통예금        6947416454  3350  6434956300
10800 외상매출금       2918847400  2679  2129424316
11000 받을어음          68000000    10           0
13100 선급금          219826110   485  1250406578
...

aggfunc을 리스트로 설정하는 경우 칼럼명이 상단에 나오고, 그렇지 않은 경우 칼럼명이 상단에 나오지 않는 차이가 있다.

 

3. 특정 컬럼에 대한 수식을 진행

만약 특정 칼럼(데이터 타입이 integer 또는 float인 경우의 칼럼)에 대한 산식만 구하고 싶을때는 values를 지정하여 진행

pd.pivot_table(df, index = ['계정코드','계정과목'], values = '차변금액', aggfunc = 'sum')
                       차변금액
계정코드  계정과목                  
10100 현금            37992648
10300 보통예금        6434956300
10800 외상매출금       2129424316
11000 받을어음                 0
13100 선급금         1250406578
...

여러개의 칼럼에 대해서 산식을 구하고 싶으면 values = ['칼럼명1','칼럼명2',...] 형태로 넣으면 된다.

pd.pivot_table(df, index = ['계정코드','계정과목'], values = ['차변금액','대변금액'], aggfunc = 'sum')
                        대변금액        차변금액
계정코드  계정과목                              
10100 현금            27556846    37992648
10300 보통예금        6947416454  6434956300
10800 외상매출금       2918847400  2129424316
11000 받을어음          68000000           0
13100 선급금          219826110  1250406578
13300 선급비용                 0   -76257604
...

4. values와 columns의 차이

columns는 선택적으로 적용하는 것. 이는 관심을 가지는 values를 추가로 구분하기 위해서 선택하는 옵션.
pd.pivot_table(df, index = ['계정코드','계정과목'], values = ['차변금액'], columns = ['거래처'], aggfunc = [sum], fill_value = 0)

NaN을 처리하기 위해서는 fill_value 옵션을 이용한다. 아래에서는 NaN을 0으로 처리한다고 가정한다.

                       sum                   ...                              
                       차변금액                   ...                              
거래처                            00114   00115  ...      98017    98025     98058
계정코드  계정과목                                    ...                              
10100 현금           37991928        0       0  ...          0        0         0
10300 보통예금                0        0       0  ...  166460660        0  32646738
10800 외상매출금               0        0       0  ...          0        0         0
11000 받을어음                0        0       0  ...          0        0         0
13100 선급금                 0        0       0  ...          0        0         0
13300 선급비용        -73201226        0       0  ...          0        0         0
...

5. 기타 옵션

  • pivot_table의 오른쪽 끝과 아래 끝에 총계와 같은 산식을 넣고 싶은 경우에는 margins 옵션을 True로 설정하여 추가하면 된다.
 pd.pivot_table(df, index = ['계정코드','계정과목']
                , values = ['차변금액'], columns = ['거래처']
                , aggfunc = ['sum'], fill_value = 0, margins = True)
                        sum                   ...                                
                       차변금액                   ...                                
거래처                            00114   00115  ...    98025     98058          All
계정코드  계정과목                                    ...                                
10100 현금           37991928        0       0  ...        0         0     37992648
10300 보통예금                0        0       0  ...        0  32646738   6434956300
10800 외상매출금               0        0       0  ...        0         0   2129424316
11000 받을어음                0        0       0  ...        0         0            0
13100 선급금                 0        0       0  ...        0         0   1250406578
13300 선급비용        -73201226        0       0  ...        0         0    -76257604
...
96000 잡손실              1480        0       0  ...        0         0         9180
All               786780904  9128900  110000  ...  2397820  32646738  13385094394
  • 필터링

인덱스에 대하여 필터링을 하고 싶은 경우에는 다음과 같이 인덱스 헤더와 인덱스 값을 조건식으로 설정한다.

pivot_table명.query("계정과목 == ['제품매출', '상품매출']")
query()함수는 전체를 쌍따옴표로 묶고, 필터링 하고 싶은 인덱스 값을 리스트 처리한다.
df1 = pd.pivot_table(df, index = ['계정코드','계정과목'], values = ['차변금액'], 
                     columns = ['거래처'], aggfunc = ['sum'], fill_value = 0)

df1.query("계정과목 == ['제품매출', '상품매출']")
            sum                          ...                              
           차변금액                          ...                              
거래처             00114 00115 00121 00125  ... 98015 98016 98017 98025 98058
계정코드  계정과목                               ...                              
40100 상품매출    0     0     0     0     0  ...     0     0     0     0     0
40400 제품매출    0     0     0     0     0  ...     0     0     0     0     0

values 순서가 한글 오름차순으로 대변금액이 먼저 나오는 것을 확인할 수 있다. 차변금액이 먼저 나오고 대변금액이 나중에 나오게 순서를 변경하기 위해서는 먼저 다음과 같이 칼럼 인덱스의 구조를 파악한다.

df1.columns
MultiIndex(levels=[['sum', 'count'], ['대변금액', '차변금액']],
           codes=[[0, 0, 1, 1], [0, 1, 0, 1]])

인덱스 구조를 보면 levels 옵션에서 ['대변금액', '차변금액']은 level이 두 번째라는 것을 알 수 있다. 이제 칼럼의 인덱스를 다음과 같이 수정한다.

df1.reindex_axis(['차변금액','대변금액'], level = 1, axis = 1)
                         sum                           count     
                        차변금액        대변금액  차변금액 대변금액
계정코드  계정과목                                         
10100 현금            37992648    27556846    13   13
10300 보통예금        6434956300  6947416454   151  151
10800 외상매출금       2129424316  2918847400   125  125
11000 받을어음                 0    68000000     1    1
13100 선급금         1250406578   219826110    42   42
13300 선급비용         -76257604           0     2    2
13500 부가세대급금        94558196           0   113  113
...