작성자: admin 작성일시: 2016-07-08 22:27:40 조회수: 2955 다운로드: 123
카테고리: Python 태그목록:

Pandas 데이터 입출력

Pandas는 CSV(Comman Separated Value)를 포함한 다양한 포맷의 데이터 파일을 읽어 직접 데이터프레임을 만들 수 있다. pandas 입출력 가능한 포맷의 종류는 다음과 같다.

  • CSV
  • Clipboard
  • Excel
  • JSON
  • HTML
  • Python Pickling
  • Feather
  • Msgpack
  • HDF5
  • SAS
  • STATA
  • SQL
  • Google BigQuery

여기에서는 가장 단순하지만 널리 사용되는 CSV 포맷 입출력에 대해 살펴본다. CSV 파일 포맷은 값들이 comma로 구분되는 텍스트 파일이다.

%%writefile 매직 명령

여기에서는 샘플로 사용할 CSV 파일을 %%writefile 매직 명령으로 만든다.

In:
%%writefile ~/data/sample1.csv
c1, c2, c3
1, 1.11, one
2, 2.22, two
3, 3.33, three
Overwriting /home/dockeruser/data/sample1.csv

CSV 파일 입력

CSV 파일로부터 데이터를 읽어 데이터프레임을 만들때는 pandas.from_csv() 명령을 사용한다.

In:
pd.read_csv('~/data/sample1.csv')
Out:
c1 c2 c3
0 1 1.11 one
1 2 2.22 two
2 3 3.33 three

위에서 읽은 데이터에는 컬럼 라벨은 있지만 인덱스 정보가 없으므로 0부터 시작하는 정수 인덱스가 자동으로 추가되었다.

컬럼 라벨이 없는 경우에는 names 인수로 설정할 수 있다.

In:
%%writefile ~/data/sample2.csv
1, 1.11, one
2, 2.22, two
3, 3.33, three
Overwriting /home/dockeruser/data/sample2.csv
In:
pd.read_csv('~/data/sample2.csv', names=['c1', 'c2', 'c3'])
Out:
c1 c2 c3
0 1 1.11 one
1 2 2.22 two
2 3 3.33 three

만약 테이블 내의 특정한 컬럼을 인덱스로 지정하고 싶으면 index_col 인수를 사용한다.

In:
pd.read_csv('~/data/sample1.csv', index_col='c1')
Out:
c2 c3
c1
1 1.11 one
2 2.22 two
3 3.33 three

확장자가 CSV가 아닌 파일 즉, 구분자가 comma가 아닌 경우에도 sep 인수를 써서 구분자를 지정하면 읽을 수 있다. 만약 구분자가 길이가 정해지지 않은 공백인 경우에는 \s+라는 정규식(regular expression) 문자열을 사용한다.

In:
%%writefile ~/data/sample3.txt
c1        c2        c3        c4 
0.179181 -1.538472  1.347553  0.43381
1.024209  0.087307 -1.281997  0.49265
0.417899 -2.002308  0.255245 -1.10515
Overwriting /home/dockeruser/data/sample3.txt
In:
pd.read_table('~/data/sample3.txt', sep='\s+')
Out:
c1 c2 c3 c4
0 0.179181 -1.538472 1.347553 0.43381
1 1.024209 0.087307 -1.281997 0.49265
2 0.417899 -2.002308 0.255245 -1.10515

만약 자료 파일 중에 건너 뛰어야 할 행이 있으면 skiprows 인수를 사용

In:
%%writefile ~/data/sample4.txt
파일 제목: sample4.txt
데이터 포맷의 설명: 
c1, c2, c3
1, 1.11, one
2, 2.22, two
3, 3.33, three
Overwriting /home/dockeruser/data/sample4.txt
In:
pd.read_csv('~/data/sample4.txt', skiprows=[0, 1])
Out:
c1 c2 c3
0 1 1.11 one
1 2 2.22 two
2 3 3.33 three

특정한 값을 NaN으로 취급하고 싶으면 na_values 인수에 NaN 값으로 취급할 값을 넣는다.

In:
%%writefile ~/data/sample5.csv
c1, c2, c3
1, 1.11, one
2,, two
누락, 3.33, three
Overwriting /home/dockeruser/data/sample5.csv
In:
df = pd.read_csv('~/data/sample5.csv', na_values=['누락'])
df
Out:
c1 c2 c3
0 1.0 1.11 one
1 2.0 NaN two
2 NaN 3.33 three

CSV 파일 출력

반대로 데이터프레임 값을 CSV 파일로 출력하고 싶으면 to_csv() 메서드를 사용한다.

In:
df.to_csv('~/data/sample6.csv')
In:
!cat ~/data/sample6.csv
,c1, c2, c3
0,1.0,1.11, one
1,2.0,, two
2,,3.33, three

읽을 때와 마찬가지로 sep 인수로 구분자를 변경할 수도 있다.

In:
df.to_csv('~/data/sample7.txt', sep='|')
In:
!cat ~/data/sample7.txt
|c1| c2| c3
0|1.0|1.11| one
1|2.0|| two
2||3.33| three

na_rep 인수로 NA 표시값을 바꿀 수도 있다.

In:
df.to_csv('~/data/sample8.csv', na_rep='누락')
In:
!cat ~/data/sample8.csv
,c1, c2, c3
0,1.0,1.11, one
1,2.0,누락, two
2,누락,3.33, three

마지막으로 index, header 인수를 지정하여 인덱스 및 헤더 출력 여부를 지정한다.

In:
df.index = ["a", "b", "c"]
df
Out:
c1 c2 c3
a 1.0 1.11 one
b 2.0 NaN two
c NaN 3.33 three
In:
df.to_csv('~/data/sample9.csv', index=False, header=False)
In:
!cat ~/data/sample9.csv
1.0,1.11, one
2.0,, two
,3.33, three

인터넷 상의 CSV 파일 입력

웹상에는 다양한 데이터 파일이 CSV 파일 형태로 제공된다. read_csv 명령 사용시 파일 패스 대신 URL을 지정하면 Pandas가 직접 해당 파일을 다운로드하여 읽어들인다. 다음은 구글 파이낸스에서 제공하는 애플의 주가 데이터를 담은 csv 파일을 읽는 법이다.

In:
df = pd.read_csv('http://www.google.com/finance/historical?q=NASDAQ%3AAAPL&output=csv')

이 데이터프레임은 실제로 데이터 갯수, 즉 행(row)의 수가 200개가 넘는 대량의 데이터이다. 이렇게 데이터의 수가 많을 경우, 데이터프레임의 표현(representation)은 데이터 앞, 뒤의 일부분만 보여준다.

In:
df
Out:
Date Open High Low Close Volume
0 24-May-17 153.84 154.17 152.67 153.34 19219154
1 23-May-17 154.90 154.90 153.31 153.80 19918871
2 22-May-17 154.00 154.58 152.91 153.99 22966437
3 19-May-17 153.38 153.98 152.63 153.06 26960788
4 18-May-17 151.27 153.34 151.13 152.54 33568215
5 17-May-17 153.60 154.57 149.71 150.25 50767678
6 16-May-17 155.94 156.06 154.72 155.47 20048478
7 15-May-17 156.01 156.65 155.05 155.70 26009719
8 12-May-17 154.70 156.42 154.67 156.10 32527017
9 11-May-17 152.45 154.07 152.31 153.95 27255058
10 10-May-17 153.63 153.94 152.11 153.26 25805692
11 9-May-17 153.87 154.88 153.45 153.99 39130363
12 8-May-17 149.03 153.70 149.03 153.01 48752413
13 5-May-17 146.76 148.98 146.76 148.96 27327725
14 4-May-17 146.52 147.14 145.81 146.53 23371872
15 3-May-17 145.59 147.49 144.27 147.06 45697034
16 2-May-17 147.54 148.09 146.84 147.51 45352194
17 1-May-17 145.10 147.20 144.96 146.58 33602943
18 28-Apr-17 144.09 144.30 143.27 143.65 20860358
19 27-Apr-17 143.92 144.16 143.31 143.79 14246347
20 26-Apr-17 144.47 144.60 143.38 143.68 20041241
21 25-Apr-17 143.91 144.90 143.87 144.53 18871501
22 24-Apr-17 143.50 143.95 143.18 143.64 17134333
23 21-Apr-17 142.44 142.68 141.85 142.27 17320928
24 20-Apr-17 141.22 142.92 141.16 142.44 23319562
25 19-Apr-17 141.88 142.00 140.45 140.68 17328375
26 18-Apr-17 141.41 142.04 141.11 141.20 14697544
27 17-Apr-17 141.48 141.88 140.87 141.83 16582094
28 13-Apr-17 141.91 142.38 141.05 141.05 17822880
29 12-Apr-17 141.60 142.15 141.01 141.80 20350000
... ... ... ... ... ... ...
221 8-Jul-16 96.49 96.89 96.05 96.68 28912103
222 7-Jul-16 95.70 96.50 95.62 95.94 25139558
223 6-Jul-16 94.60 95.66 94.37 95.53 30949090
224 5-Jul-16 95.39 95.40 94.46 94.99 27705210
225 1-Jul-16 95.49 96.46 95.33 95.89 26026540
226 30-Jun-16 94.44 95.77 94.30 95.60 35836356
227 29-Jun-16 93.97 94.55 93.63 94.40 36531006
228 28-Jun-16 92.90 93.66 92.14 93.59 40444914
229 27-Jun-16 93.00 93.05 91.50 92.04 46622188
230 24-Jun-16 92.91 94.66 92.65 93.40 75311356
231 23-Jun-16 95.94 96.29 95.25 96.10 32240187
232 22-Jun-16 96.25 96.89 95.35 95.55 29219122
233 21-Jun-16 94.94 96.35 94.68 95.91 35546358
234 20-Jun-16 96.00 96.57 95.03 95.10 34411901
235 17-Jun-16 96.62 96.65 95.30 95.33 61008219
236 16-Jun-16 96.45 97.75 96.07 97.55 31326815
237 15-Jun-16 97.82 98.41 97.03 97.14 29445227
238 14-Jun-16 97.32 98.48 96.75 97.46 31931944
239 13-Jun-16 98.69 99.12 97.10 97.34 38020494
240 10-Jun-16 98.53 99.35 98.48 98.83 31712936
241 9-Jun-16 98.50 99.99 98.46 99.65 26601354
242 8-Jun-16 99.02 99.56 98.68 98.94 20848131
243 7-Jun-16 99.25 99.87 98.96 99.03 22409450
244 6-Jun-16 97.99 101.89 97.55 98.63 23292504
245 3-Jun-16 97.79 98.27 97.45 97.92 28504888
246 2-Jun-16 97.60 97.84 96.63 97.72 40191600
247 1-Jun-16 99.02 99.54 98.33 98.46 29173285
248 31-May-16 99.60 100.40 98.82 99.86 42307212
249 27-May-16 99.44 100.47 99.24 100.35 36229530
250 26-May-16 99.68 100.73 98.64 100.41 56093437

251 rows × 6 columns

만약 앞이나 뒤의 특정 갯수만 보고 싶다면 head 메서드나 tail 메서드를 이용한다. 메서드 인수로 출력할 행의 수를 넣을 수도 있다.

In:
df.head()
Out:
Date Open High Low Close Volume
0 24-May-17 153.84 154.17 152.67 153.34 19219154
1 23-May-17 154.90 154.90 153.31 153.80 19918871
2 22-May-17 154.00 154.58 152.91 153.99 22966437
3 19-May-17 153.38 153.98 152.63 153.06 26960788
4 18-May-17 151.27 153.34 151.13 152.54 33568215
In:
df.tail(10)
Out:
Date Open High Low Close Volume
241 9-Jun-16 98.50 99.99 98.46 99.65 26601354
242 8-Jun-16 99.02 99.56 98.68 98.94 20848131
243 7-Jun-16 99.25 99.87 98.96 99.03 22409450
244 6-Jun-16 97.99 101.89 97.55 98.63 23292504
245 3-Jun-16 97.79 98.27 97.45 97.92 28504888
246 2-Jun-16 97.60 97.84 96.63 97.72 40191600
247 1-Jun-16 99.02 99.54 98.33 98.46 29173285
248 31-May-16 99.60 100.40 98.82 99.86 42307212
249 27-May-16 99.44 100.47 99.24 100.35 36229530
250 26-May-16 99.68 100.73 98.64 100.41 56093437

인터넷 상의 데이터 베이스 자료 입력

다음과 같은 인터넷 상의 자료는 pandas_datareader 패키지의 DataReader 을 써서 바로 pandas로 입력할 수도 있다.

  • Yahoo! Finance
  • Google Finance
  • Enigma
  • FRED
  • Fama/French
  • World Bank
  • OECD
  • Eurostat
  • EDGAR Index
  • TSP Fund Data
  • Oanda currency historical rate
  • Nasdaq Trader Symbol Definitions

자세한 내용은 다음 웹사이트를 참조한다.

In:
from pandas_datareader.data import DataReader

날짜는 datetime 패키지를 사용하여 지정해도 되고 문자열을 바로 사용해도 된다. (이때는 내부적으로 dateutil 패키지를 사용한다.

In:
import datetime
dt_start = datetime.datetime(2015, 1, 1)
dt_end = "2016, 6, 30"

data_source 인수로 데이터를 읽어올 웹사이트를 지정할 수 있다. 이 때 데이터의 이름을 지정하는 코드는 웹사이트마다 다르므로 주의한다. 예를 들어 삼성전자 주가는 yahoo에서는 005930.KS로 지정하지만 google에서는 KRX:005930이다.

In:
df = DataReader("KRX:005930", 'google', dt_start, dt_end)
df.tail()
Out:
Open High Low Close Volume
Date
2016-06-24 1445000.0 1445000.0 1360000.0 1400000.0 408920
2016-06-27 1400000.0 1405000.0 1385000.0 1398000.0 236573
2016-06-28 1390000.0 1404000.0 1379000.0 1399000.0 213829
2016-06-29 1408000.0 1412000.0 1391000.0 1396000.0 208090
2016-06-30 1408000.0 1445000.0 1397000.0 1425000.0 272883

다음은 FRED 데이터베이스에서 미국 국가총생산(GDP), 모든 항목을 포함한 소비자 가격 지수(CPIAUCSL), 식료품 및 연로를 제외한 소비자 가격 지수(CPILFESL)를 가져오는 예이다.

In:
gdp = DataReader("GDP", "fred", dt_start, dt_end)
gdp
Out:
GDP
DATE
2015-01-01 17783.6
2015-04-01 17998.3
2015-07-01 18141.9
2015-10-01 18222.8
2016-01-01 18281.6
2016-04-01 18450.1

종목 코드에 리스트를 넣으면 복수 종목에 대한 데이터를 가져온다.

In:
inflation = DataReader(["CPIAUCSL", "CPILFESL"], "fred", dt_start, dt_end)
inflation
Out:
CPIAUCSL CPILFESL
DATE
2015-01-01 234.913 239.910
2015-02-01 235.489 240.236
2015-03-01 235.989 240.783
2015-04-01 236.201 241.366
2015-05-01 236.891 241.662
2015-06-01 237.419 242.021
2015-07-01 237.876 242.480
2015-08-01 237.811 242.754
2015-09-01 237.467 243.249
2015-10-01 237.792 243.719
2015-11-01 238.153 244.221
2015-12-01 237.846 244.581
2016-01-01 238.106 245.232
2016-02-01 237.808 245.845
2016-03-01 238.078 246.062
2016-04-01 238.908 246.517
2016-05-01 239.362 247.026
2016-06-01 239.842 247.389

질문/덧글

오타수정 531c*** 2016년 7월 10일 5:00 오후

pandas.from_csv(): csv file -> DataFrame

이 부분에서
from_csv()가 아니라 read_csv()인 것 같습니다.

답변: 오타수정 관리자 2016년 7월 10일 7:01 오후

오타가 아니고 `from_csv` 와 `read_csv` 명령 두 개 모두 존재합니다.

감사합니다. 531c*** 2016년 7월 12일 2:44 오후

감사합니다.

pandas / zipline /pipeline park*** 2016년 8월 10일 11:01 오전

pandas datareader 로 자료 받기
zipline을 받기
또 quantopian 의 다른 pipeline으로 받기를 하면

뭐가 다른가요 ?

quantopian package는 데이터 클리닝을 알아서 해 주나요 ?

답변: pandas / zipline /pipeline 관리자 2016년 8월 10일 7:25 오후

zipline의 load_xxx 명령어 들은 내부적으로 pandas를 이용합니다.
다만 timezone 정보를 추가하거나 adj.close가 없는 경우 생성합니다.
https://github.com/quantopian/zipline/blob/master/zipline/data/loader.py
pipeline API는 아직 사용해보지 않았습니다.