4.4.2 Pandas 활용하기

이 내용은 10 Minutes to pandas을 기초로 작성되었습니다.

1) 데이터 조작하기

다음 소스코드를 실습하면서 Pandas 데이터를 조작하는 법을 실습하겠습니다.

import pandas as pd  
import numpy as np  
     
dates = pd.date_range('20190101', periods=6)  
    
df = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=list('ABCD'))  
   
print(df)  
print(df.head())  
print(df.tail(3))  
print(df.index)  
print(df.columns)  
print(df.values)  
print(df.describe())  
print(df.T)  
print(df.sort_index(axis=1, ascending=False))  
print(df.sort_values(by='B'))  
print(df['A'])  
print(df[0:3])  
print(df.loc[dates[0]])  
print(df.iloc[3:5, 0:2])  
print(df[df.A > 0])  
print(df.mean())  
print(df.apply(np.cumsum))  

4행,5행에서 pandas 데이터 구조인 DataFrame은 numpy array를 받아 생성이 가능합니다. 여기에서는 인덱스로 날짜 값을 주었고, 컬럼의 이름도 같이 넣어보았습니다. 만들어진 DataFrame df를 출력한 8행의 결과는 다음과 같습니다.

                 A         B         C         D
2019-01-01  0.663299  0.151818 -1.061050 -0.371212
2019-01-02 -1.366572  2.444417  0.127165 -0.705624
2019-01-03 -1.106557  0.761649 -1.945276  1.031035
2019-01-04  0.614764 -0.806967 -0.317243  0.934984
2019-01-05 -0.413898 -0.480331 -0.255014  0.871850
2019-01-06 -1.069069  0.499700 -0.213767  0.424256

DataFrame에 들어있는 맨 앞이나 맨 뒤의 자료들 몇 개를 알아보고 싶다면 9행, 10행과 같이 .head()와 .tail() 메소드를 사용하면 됩니다. 기본적으로 5개의 자료를 보여주고, 더 적게 혹은 많이 보고 싶다면 메소드의 인자로 보고싶은 데이터의 개수를 숫자를 넣어주면 됩니다.

                A        B         C        D
2019-01-01  0.663299  0.151818 -1.061050 -0.371212
2019-01-02 -1.366572  2.444417  0.127165 -0.705624
2019-01-03 -1.106557  0.761649 -1.945276  1.031035
2019-01-04  0.614764 -0.806967 -0.317243  0.934984
2019-01-05 -0.413898 -0.480331 -0.255014  0.871850
                   A         B         C         D
2019-01-04  0.614764 -0.806967 -0.317243  0.934984
2019-01-05 -0.413898 -0.480331 -0.255014  0.871850
2019-01-06 -1.069069  0.499700 -0.213767  0.424256

DataFrame의 인덱스를 보려면 .index 속성을, 컬럼을 보려면 .columns 속성을, 안에 들어있는 numpy 데이터를 보려면 .values 속성을 통해 확인하면 됩니다.

11행~13행의 출력 결과는 다음과 같습니다.

DatetimeIndex(['2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04',
               '2019-01-05', '2019-01-06'],
              dtype='datetime64[ns]', freq='D')
Index(['A', 'B', 'C', 'D'], dtype='object')
[[-0.56423413 -0.85399409 -0.31727827 -0.2457619 ]
 [ 1.87094766  0.53596149 -0.13952464 -0.83790642]
 [ 0.11521253  0.84948792 -0.75322771 -0.00697268]
 [ 1.57108028 -1.54736629 -0.51947482  3.2743979 ]
 [ 0.7834223  -0.02797148  0.87140932 -1.08610556]
 [ 0.49678189  0.94142238  0.58725135  0.82629978]]

14행 .describe() 메소드는 생성했던 DataFrame의 간단한 통계 정보를 보여줍니다. 컬럼별로 데이터의 개수(count), 데이터의 평균 값(mean), 표준 편차(std), 최솟값(min), 4분위수(25%, 50%, 75%), 그리고 최댓값(max)들의 정보를 알 수 있습니다.

        A         B         C         D
count  6.000000  6.000000  6.000000  6.000000
mean   0.712202 -0.017077 -0.045141  0.320659
std    0.907472  1.001783  0.640208  1.595599
min   -0.564234 -1.547366 -0.753228 -1.086106
25%    0.210605 -0.647488 -0.468926 -0.689870
50%    0.640102  0.253995 -0.228401 -0.126367
75%    1.374166  0.771106  0.405557  0.617982
max    1.870948  0.941422  0.871409  3.274398

15행 .T 속성은 DataFrame에서 index와 column을 바꾼 형태의 DataFrame 입니다.

2019-01-01  2019-01-02     ...      2019-01-05  2019-01-06
A   -0.564234    1.870948     ...        0.783422    0.496782
B   -0.853994    0.535961     ...       -0.027971    0.941422
C   -0.317278   -0.139525     ...        0.871409    0.587251
D   -0.245762   -0.837906     ...       -1.086106    0.826300

16행, 17행은 정렬의 예입니다. .sort_index()라는 메소드로 행과 열 이름을 정렬하여 나타낼 수도 있습니다. 정렬할 대상 축을 결정할 때에는 axis를 이용합니다. axis=0라고 써주면 인덱스를 기준으로 정렬하겠다는 것이고(기본값), axis=1라고 써주면 컬럼을 기준으로 정렬하겠다는 것입니다. 정렬의 방향은 ascending을 이용합니다. ascending=True는 오름차순 정렬을 하겠다는 것이고(기본값), ascending=False는 내림차순 정렬을 하겠다는 의미입니다.

                   D         C         B         A
2019-01-01  0.196948 -1.255738  0.997678 -1.104337
2019-01-02 -0.764140  0.189092 -0.298177 -1.510107
2019-01-03 -0.721188  0.043075  1.385104 -0.732341
2019-01-04  0.488364  0.876822  1.368371  0.310627
2019-01-05  1.628589 -0.195919  2.233960  1.708188
2019-01-06  0.328141  1.125429  1.750625 -0.845495
                   A         B         C         D
2019-01-02 -1.510107 -0.298177  0.189092 -0.764140
2019-01-01 -1.104337  0.997678 -1.255738  0.196948
2019-01-04  0.310627  1.368371  0.876822  0.488364
2019-01-03 -0.732341  1.385104  0.043075 -0.721188
2019-01-06 -0.845495  1.750625  1.125429  0.328141
2019-01-05  1.708188  2.233960 -0.195919  1.628589

18행은 데이터프레임 자체가 갖고 있는 [] 슬라이싱 기능을 이용하는 방법입니다. 특정 ‘컬럼’의 값들만 가져오고 싶다면 df['A']와 같은 형태로 입력합니다. 이는 df.A와 동일합니다. 리턴되는 값은 Series의 자료구조를 갖고 있습니다.

2019-01-01   -1.104337
2019-01-02   -1.510107
2019-01-03   -0.732341
2019-01-04    0.310627
2019-01-05    1.708188
2019-01-06   -0.845495

특정 ‘행 범위’를 가져오고 싶다면 19행과 같이 리스트를 슬라이싱 할 때와 같이 []를 이용할 수 있습니다. df[0:3]라고 하면 0, 1, 2번째 행을 가져옵니다

                  A         B         C         D
2019-01-01 -1.104337  0.997678 -1.255738  0.196948
2019-01-02 -1.510107 -0.298177  0.189092 -0.764140
2019-01-03 -0.732341  1.385104  0.043075 -0.721188

라벨의 이름을 이용하여 선택할 수 있는 .loc를 이용할 수도 있습니다. 20행은 첫 번째 인덱스의 값인 ‘2013-01-01’에 해당하는 모든 컬럼의 값 가져오기 예제입니다.

A   -1.104337
B    0.997678
C   -1.255738
D    0.196948
Name: 2019-01-01 00:00:00, dtype: float64

위치를 나타내는 인덱스 번호를 이용하여 데이터를 선택할 수 있습니다. 여기서 인덱스 번호는 python에서 사용하는 인덱스와 같은 개념으로 이해하시면 됩니다. 인덱스 번호는 0 부터 시작하므로, 첫 번째 데이터는 인덱스 번호가 0 이고, 두 번째 데이터는 인덱스 번호가 1 이라는 뜻입니다. 인덱스 번호로 행뿐만 아니라 열도 선택할 수 있습니다. 또한 numpy나 python의 슬라이싱 기능과 비슷하게 사용할 수 있습니다. 21행은 행과 열의 인덱스를 기준으로 이용하여 데이터를 선택하는 예제입니다. 행의 인덱스는 3:5로 네 번째 행과 다섯 번째 행을 선택하며, 열의 인덱스는 0:2로 첫 번째 열과 두 번째 열을 선택합니다.

                A         B
2019-01-04  0.310627  1.368371
2019-01-05  1.708188  2.233960

특정한 열의 값들을 기준으로 조건을 만들어 해당 조건에 만족하는 행들만 선택할 수 있는 방법이 있습니다. 22행은 A라는 열에 들어있는 값이 양수인 경우에 해당하는 행들을 선택하는 예제입니다.

            A         B         C         D
2019-01-04  0.310627  1.368371  0.876822  0.488364
2019-01-05  1.708188  2.233960 -0.195919  1.628589
23행은 평균 구하기입니다.
A   -0.362244
B    1.239594
C    0.130460
D    0.192786
dtype: float64

데이터프레임에 함수를 적용할 수 있습니다. 기존에 존재하는 함수를 사용하거나 사용자가 정의한 람다 함수를 사용할 수도 있습니다. 24행은 np.cumsum 함수를 적용한 예제입니다.

                A         B         C         D
2019-01-01 -1.104337  0.997678 -1.255738  0.196948
2019-01-02 -2.614444  0.699501 -1.066646 -0.567192
2019-01-03 -3.346785  2.084605 -1.023571 -1.288379
2019-01-04 -3.036158  3.452976 -0.146749 -0.800015
2019-01-05 -1.327970  5.686936 -0.342667  0.828574
2019-01-06 -2.173466  7.437561  0.782761  1.156714

2) Time Series 데이터 다루기

시계열 데이터에서 1초 마다 측정된 데이터를 5분 마다 측정된 데이터의 형태로 바꾸고 싶을 땐 어떻게 할까요? Pandas는 이렇게 시계열 단위인 주기(frequency)를 다시 샘플링 할 수 있는 단순하고, 강력하며, 효과적인 기능을 가지고 있습니다. 이는 특히 금융 데이터를 다룰 때 매우 흔히 하는 연산입니다.

import pandas as pd  
import numpy as np  
    
rng = pd.date_range('3/6/2019 00:00', periods=5, freq='D')  
ts = pd.Series(np.random.randn(len(rng)), rng)  
    
print(ts)  
ts_utc = ts.tz_localize('UTC')  
print('===Universal Time Code===')  
print(ts_utc)  
2019-03-06   -0.759081
2019-03-07   -0.141358
2019-03-08   -0.522444
2019-03-09    0.073374
2019-03-10    0.601500
Freq: D, dtype: float64
===Universal Time Code===
2019-03-06 00:00:00+00:00   -0.759081
2019-03-07 00:00:00+00:00   -0.141358
2019-03-08 00:00:00+00:00   -0.522444
2019-03-09 00:00:00+00:00    0.073374
2019-03-10 00:00:00+00:00    0.601500
Freq: D, dtype: float64

기간과 특정시간 사이의 변환에 편리한 산술적 기능들을 사용할 수 있습니다. 뒤이어 나오는 예제는 11월을 끝으로 하는 4분기 체계에서 각 분기의 마지막 달에 9시간을 더한 시각을 시작으로 하는 체계로 바꾸는 것을 보여줍니다.

import pandas as pd  
 import numpy as np  
   
 prng = pd.period_range('1990Q1', '2000Q4', freq='Q-NOV')  
   
 ts = pd.Series(np.random.randn(len(prng)), prng)  
   
 ts.index = (prng.asfreq('M', 'e') + 1).asfreq('H', 's') + 9  
   
 print(ts.head())  
1990-03-01 09:00   -0.562671
1990-06-01 09:00    0.704668
1990-09-01 09:00   -0.976534
1990-12-01 09:00   -0.182832
1991-03-01 09:00   -0.978586
Freq: H, dtype: float64

3) 그래프로 표현하기 (Plotting)

다음과 같은 시계열 데이터가 있을 때, pandas에서 그래프 그리기는 다음과 같이 plot() 메소드 하나만으로 완성할 수 있습니다.

import pandas as pd  
import numpy as np  
import matplotlib.pyplot as plt  
   
ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000))  
ts = ts.cumsum()  
ts.plot()  
plt.show()  

plot() 메소드는 여러 개의 열을 한 번에 그릴 수 있는 편리함도 제공하고 있습니다. 다음과 같이 A, B, C, D의 4개의 열에 해당하는 데이터를 legend 와 함께 표시할 수 있습니다.

import pandas as pd  
import numpy as np  
import matplotlib.pyplot as plt  
    
ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000))  
ts = ts.cumsum()  
df = pd.DataFrame(np.random.randn(1000, 4), index=ts.index, columns=['A', 'B', 'C', 'D'])  
df = df.cumsum()  
df.plot()  
plt.show() 

4) 데이터 입/출력 (Getting Data In/Out)

데이터를 다양한 형식의 파일에 읽고 쓰는 방법을 알아봅니다.

Pandas에서 Excel 파일을 다루기 위해서는 tables, xlrd, openpyxl 모듈의 설치가 필요 합니다.

(onebook)>pip install xlrd
(onebook)>pip install tables
(onebook)>pip install openpyxl

아래의 코드는 데이터 프레임을 CSV 형식으로 저장하기, HDF5 형식으로 저장하기, 엑셀 파일로 저장하기의 예제 입니다.

import pandas as pd
import numpy as np

ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000))
ts = ts.cumsum()
df = pd.DataFrame(np.random.randn(1000, 4), index=ts.index, columns=['A', 'B', 'C', 'D'])
df = df.cumsum()
df.to_csv('pandas.csv')
df.to_hdf('pandas.h5', 'df')
df.to_excel('pandas.xlsx', sheet_name='Sheet1')

print(pd.read_csv('pandas.csv'))

위의 코드를 실행하면 다음과 같이 프로젝트 디렉토리에 3개의 파일이 생성 되는 것을 확인 할 수 잇습니다.

파일의 내용을 읽으려면 다음과 같이 사용하면 됩니다.

import pandas as pd  
….
….
pd.read_csv('pandas.csv')
pd.read_hdf('foo.h5', 'df')
pd.read_excel('foo.xlsx', 'Sheet1', index_col=None, na_values=['NA'])

Last updated