4.2 데이터 입출력

Pandas는 데이터 파일을 읽어 데이터프레임을 만들 수 있다. 다음처럼 여러가지 포맷을 지원한다.

  • CSV

  • Excel

  • HTML

  • JSON

  • HDF5

  • SAS

  • STATA

  • SQL

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

%%writefile 명령

샘플 데이터로 사용할 CSV 파일을 %%writefile 매직(magic) 명령으로 만들어보자. 이 명령은 셀에 서술한 내용대로 텍스트 파일을 만드는 명령이다.

%%writefile sample1.csv
c1, c2, c3
1, 1.11, one
2, 2.22, two
3, 3.33, three
Writing sample1.csv

CSV 파일 입력

CSV 파일로부터 데이터를 읽어 데이터프레임을 만들 때는 pandas.read_csv 함수를 사용한다. 함수의 입력값으로 파일 이름을 넣는다.

pd.read_csv('sample1.csv')
c1 c2 c3
0 1 1.11 one
1 2 2.22 two
2 3 3.33 three

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

만약 데이터 파일에 열 인덱스 정보가 없는 경우에는 read_csv 명령의 names 인수로 설정할 수 있다.

%%writefile sample2.csv
1, 1.11, one
2, 2.22, two
3, 3.33, three
Writing sample2.csv
pd.read_csv('sample2.csv', names=['c1', 'c2', 'c3'])
c1 c2 c3
0 1 1.11 one
1 2 2.22 two
2 3 3.33 three

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

pd.read_csv('sample1.csv', index_col='c1')
c2 c3
c1
1 1.11 one
2 2.22 two
3 3.33 three

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

%%writefile 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
Writing sample3.txt
pd.read_table('sample3.txt', sep='\s+')
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 인수를 사용한다.

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

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

%%writefile sample5.csv
c1, c2, c3
1, 1.11, one
2, , two
누락, 3.33, three
Writing sample5.csv
df = pd.read_csv('sample5.csv', na_values=['누락'])
df
c1 c2 c3
0 1.0 1.11 one
1 2.0 two
2 NaN 3.33 three

CSV 파일 출력

지금까지와 반대로 파이썬의 데이터프레임 값을 CSV 파일로 출력하고 싶으면 to_csv 메서드를 사용한다.

df.to_csv('sample6.csv')

리눅스나 맥에서는 cat 셸 명령으로 파일의 내용을 확인할 수 있다. 윈도우에서는 type 함수를 사용한다. 느낌표(!)는 셸 함수를 사용하기 위한 아이파이썬(IPython) 매직 명령이다.

!cat sample6.csv  # 윈도우에서는 !type sample6.csv 함수를 사용
,c1, c2, c3
0,1.0, 1.11, one
1,2.0, , two
2,, 3.33, three

파일을 읽을 때와 마찬가지로 출력할 때도 sep 인수로 구분자를 바꿀 수 있다.

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

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

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

index, header 인수를 지정하여 인덱스 및 헤더 출력 여부를 지정하는 것도 가능하다.

df.index = ["a", "b", "c"]
df
c1 c2 c3
a 1.0 1.11 one
b 2.0 two
c NaN 3.33 three
df.to_csv('sample9.csv', index=False, header=False)
!cat sample9.csv  # 윈도우에서는 !type sample6.csv 함수를 사용
1.0, 1.11, one
2.0, , two
, 3.33, three

인터넷 상의 CSV 파일 입력

웹상에는 다양한 데이터 파일이 CSV 파일 형태로 제공된다. read_csv 명령 사용시 파일 패스 대신 URL을 지정하면 Pandas가 직접 해당 파일을 다운로드하여 읽어들인다. 다음은 저자의 github 웹사이트에 저장되어 있는 데이터 파일을 원격으로 읽는 명령이다.

df = pd.read_csv("https://raw.githubusercontent.com/datascienceschool/docker_rpython/master/data/titanic.csv")

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

pd.set_option("display.max_rows", 20)  # 앞뒤로 모두 20행만 보여준다.
df
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
... ... ... ... ... ... ... ... ... ... ... ... ...
886 887 0 2 Montvila, Rev. Juozas male 27.0 0 0 211536 13.0000 NaN S
887 888 1 1 Graham, Miss. Margaret Edith female 19.0 0 0 112053 30.0000 B42 S
888 889 0 3 Johnston, Miss. Catherine Helen "Carrie" female NaN 1 2 W./C. 6607 23.4500 NaN S
889 890 1 1 Behr, Mr. Karl Howell male 26.0 0 0 111369 30.0000 C148 C
890 891 0 3 Dooley, Mr. Patrick male 32.0 0 0 370376 7.7500 NaN Q

891 rows × 12 columns

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

df.head()
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
df.tail(2)
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
889 890 1 1 Behr, Mr. Karl Howell male 26.0 0 0 111369 30.00 C148 C
890 891 0 3 Dooley, Mr. Patrick male 32.0 0 0 370376 7.75 NaN Q

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

pandas_datareader 패키지의 DataReader 을 사용하면 일부 인터넷 사이트의 자료를 바로 pandas로 읽어들일 수 있다. pandas_datareader 패키지는 판다스와 별도로 설치해야 한다. 다음은 pandas_datareader 패키지가 제공하는 인터넷 사이트의 예이다. 일부 인터넷 사이트는 유료이므로 별도의 가입절차를 거쳐야 한다.

  • FRED

  • Fama/French

  • World Bank

  • OECD

  • Eurostat

  • EDGAR Index

  • TSP Fund Data

  • Oanda currency historical rate

  • Nasdaq Trader Symbol Definitions

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

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

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

data_source 인수로 데이터를 읽어올 웹 사이트를 지정한다. 데이터의 코드는 웹 사이트에서 검색하여 알아내야 한다. 다음은 FRED 데이터베이스에서 미국 국가총생산(GDP), 모든 항목을 포함한 소비자 가격 지수(CPIAUCSL), 식료품 및 연로를 제외한 소비자 가격 지수(CPILFESL)를 가져오는 예이다. 웹사이트에서 자세한 데이터에 대한 세부적인 사항이나 값을 확인할 수 있다.

import pandas_datareader as pdr

gdp = pdr.get_data_fred('GDP', dt_start, dt_end)
gdp.tail()
GDP
DATE
2015-04-01 18223.577
2015-07-01 18347.425
2015-10-01 18378.803
2016-01-01 18470.156
2016-04-01 18656.207

데이터 코드에 리스트를 넣으면 여러개의 데이터를 동시에 가져온다.

inflation = pdr.get_data_fred(["CPIAUCSL", "CPILFESL"], dt_start, dt_end)
inflation.tail()
CPIAUCSL CPILFESL
DATE
2016-02-01 237.514 245.644
2016-03-01 237.990 245.964
2016-04-01 238.835 246.467
2016-05-01 239.440 247.036
2016-06-01 240.144 247.435