pandas 번역: 10분만에 판다스 보기 (pandas User guide 번역/pandas 기초 입문/Pandas 간단 요약)
주니어로서 어떤 능력을 갖추는게 좋을까요?
라고 과장님께 질문을 했더니
pandas cookbook을 빌려주시며, 나즈막하게 '이 책을 뜯어드시면 됩니다..'라고 말씀하시고 떠났다.
그래서 pandas User guide를 번역해보기로 했다. 덩달아 영어 실력도 좋아질 것 같다. 오늘이 그 시작!
10 minutes to pandas
해당 문서는 새로운 유저에게 맞춰진 짧은 pandas 소개입니다. 좀 더 복잡한 부분은 cookbook에서 확인해볼 수 있습니다. 보통 아래와 같이 import 하여 사용합니다.
import numpy as np
import pandas as pd
Object creation(객체 생성)
자세한 내용은 Data Structure Intro section 을 참고하세요.
list를 통하여, 인덱스의 초기 설정이 정수인 Series 를 만들 수 있습니다.
seires = pd.Series([1, 3, 5, np.nan, 6, 8])
#result
0 1.0
1 3.0
2 5.0
3 NaN
4 6.0
5 8.0
dtype: float64
Numpy array(2D array)를 통해 인덱스가 날짜거나, 열의 이름이 설정되어 있는 DataFrame을 만들 수 있습니다.
In [5]: dates = pd.date_range('20130101', periods=6)
In [6]: dates
Out[6]:
DatetimeIndex(['2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04',
'2013-01-05', '2013-01-06'],
dtype='datetime64[ns]', freq='D')
In [7]: df = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=list('ABCD'))
In [8]: df
Out[8]:
A B C D
2013-01-01 0.469112 -0.282863 -1.509059 -1.135632
2013-01-02 1.212112 -0.173215 0.119209 -1.044236
2013-01-03 -0.861849 -2.104569 -0.494929 1.071804
2013-01-04 0.721555 -0.706771 -1.039575 0.271860
2013-01-05 -0.424972 0.567020 0.276232 -1.087401
2013-01-06 -0.673690 0.113648 -1.478427 0.524988
Series 처럼 표현될 수 있는 dict 객체를 통해 DataFrame을 만들 수 있습니다.( 각 key에 있는 value들이 Series를 만들 수 있는 형태라는 점에 집중하시면 좋을 것 같습니다. )
In [9]: df2 = pd.DataFrame({'A': 1.,
...: 'B': pd.Timestamp('20130102'),
...: 'C': pd.Series(1, index=list(range(4)), dtype='float32'),
...: 'D': np.array([3] * 4, dtype='int32'),
...: 'E': pd.Categorical(["test", "train", "test", "train"]),
...: 'F': 'foo'})
...:
In [10]: df2
Out[10]:
A B C D E F
0 1.0 2013-01-02 1.0 3 test foo
1 1.0 2013-01-02 1.0 3 train foo
2 1.0 2013-01-02 1.0 3 test foo
3 1.0 2013-01-02 1.0 3 train foo
DataFrame의 각 열도 각자 다른 dtype(데이터타입)을 가지고 있습니다.
In [11]: df2.dtypes
Out[11]:
A float64
B datetime64[ns]
C float32
D int32
E category
F object
dtype: object
만일 IPython을 사용하고 있다면, Tab 키를 통해 attribute의 이름을 작성하는 것 뿐만 아니라 열의 이름도 자동완성으로 작성하는 것이 가능합니다.
In [12]: df2.<TAB> # noqa: E225, E999
df2.A df2.bool
df2.abs df2.boxplot
df2.add df2.C
df2.add_prefix df2.clip
df2.add_suffix df2.columns
df2.align df2.copy
df2.all df2.count
df2.any df2.combine
df2.append df2.D
df2.apply df2.describe
df2.applymap df2.diff
df2.B df2.duplicated
위의 예시에서 보신 것처럼, 열의 이름에 해당되는 A,B,C,D가 포함되어 있는 것을 볼 수 있습니다. 예시로 나온 df2에는 E와 F도 있지만, 글의 간결성을 위해 d이후의 내용은 삭제했습니다.
Viewing data
Basics section. 을 참고하세요
데이터프레임의 상단과 하단을 보는 방법입니다!
In [13]: df.head()
Out[13]:
A B C D
2013-01-01 0.469112 -0.282863 -1.509059 -1.135632
2013-01-02 1.212112 -0.173215 0.119209 -1.044236
2013-01-03 -0.861849 -2.104569 -0.494929 1.071804
2013-01-04 0.721555 -0.706771 -1.039575 0.271860
2013-01-05 -0.424972 0.567020 0.276232 -1.087401
In [14]: df.tail(3)
Out[14]:
A B C D
2013-01-04 0.721555 -0.706771 -1.039575 0.271860
2013-01-05 -0.424972 0.567020 0.276232 -1.087401
2013-01-06 -0.673690 0.113648 -1.478427 0.524988
인덱스와 열을 보는 방법입니다.
In [15]: df.index
Out[15]:
DatetimeIndex(['2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04',
'2013-01-05', '2013-01-06'],
dtype='datetime64[ns]', freq='D')
In [16]: df.columns
Out[16]: Index(['A', 'B', 'C', 'D'], dtype='object')
DataFrame.to_numpy()는 가지고 있는 데이터를 numpy의 형태로 보여줍니다(array). Pandas와 Numpy에는 근본적인 차이가 하나 있습니다. pandas는 각 열마다 각기 다른 데이터 타입을 가질 수 있지만, numpy의 경우 전체 array 내의 데ㅣ터가 모두 동일한 데이터 타입을 가져야 합니다. 이렇기 때문에, pandas의 dataframe을 단순히 numpy형태로 변경하는거는 expensive operation(제가 이해하기로는 메모리가 많이 드는 연산)이 될 수 있습니다. DataFrame.to_numpy() 를 호출할 때 pandas 는 모든 데이터타입을 저장할 수 있는 numpy datatype을 찾으려고 할 것입니다. 결국에는 파이썬 객체의 모든 데이터타입을 casting하는 object 타입으로 귀결될 가능성이 높습니다.
앞의 예시에서 나왔던 df의 경우, 모든 값이 float 형태이기 때문에, DataFrame.to_numpy()는 빠르고, 데이터를 복사할 필요도 없습니다.
In [17]: df.to_numpy()
Out[17]:
array([[ 0.4691, -0.2829, -1.5091, -1.1356],
[ 1.2121, -0.1732, 0.1192, -1.0442],
[-0.8618, -2.1046, -0.4949, 1.0718],
[ 0.7216, -0.7068, -1.0396, 0.2719],
[-0.425 , 0.567 , 0.2762, -1.0874],
[-0.6737, 0.1136, -1.4784, 0.525 ]])
그러나 각 열마다 데이터 타입이 달랐던 df2의 경우에는, DataFrame.to_numpy()는 상대적으로 비쌉니다.(expensive, 들어가는 작업이 많다, 무겁다라는 의미로 이해했습니다.)
In [18]: df2.to_numpy()
Out[18]:
array([[1.0, Timestamp('2013-01-02 00:00:00'), 1.0, 3, 'test', 'foo'],
[1.0, Timestamp('2013-01-02 00:00:00'), 1.0, 3, 'train', 'foo'],
[1.0, Timestamp('2013-01-02 00:00:00'), 1.0, 3, 'test', 'foo'],
[1.0, Timestamp('2013-01-02 00:00:00'), 1.0, 3, 'train', 'foo']],
dtype=object)
주의! DataFrame.to_numpy()는, output에 index와 columns을 포함하지 않습니다! |
describe() 는 여러분의 데이터에 대해 간결한 통계 요약을 보여줍니다.
In [19]: df.describe()
Out[19]:
A B C D
count 6.000000 6.000000 6.000000 6.000000
mean 0.073711 -0.431125 -0.687758 -0.233103
std 0.843157 0.922818 0.779887 0.973118
min -0.861849 -2.104569 -1.509059 -1.135632
25% -0.611510 -0.600794 -1.368714 -1.076610
50% 0.022070 -0.228039 -0.767252 -0.386188
75% 0.658444 0.041933 -0.034326 0.461706
max 1.212112 0.567020 0.276232 1.071804
Transposing your data:
아래는 여러분의 데이터를 역치하여 보여주는 방식입니다.(행과 열을 전환하여 보여줌, 역치행렬의 개념)
In [20]: df.T
Out[20]:
2013-01-01 2013-01-02 2013-01-03 2013-01-04 2013-01-05 2013-01-06
A 0.469112 1.212112 -0.861849 0.721555 -0.424972 -0.673690
B -0.282863 -0.173215 -2.104569 -0.706771 0.567020 0.113648
C -1.509059 0.119209 -0.494929 -1.039575 0.276232 -1.478427
D -1.135632 -1.044236 1.071804 0.271860 -1.087401 0.524988
축에 따라 정렬하는 방식입니다.
In [21]: df.sort_index(axis=1, ascending=False)
Out[21]:
D C B A
2013-01-01 -1.135632 -1.509059 -0.282863 0.469112
2013-01-02 -1.044236 0.119209 -0.173215 1.212112
2013-01-03 1.071804 -0.494929 -2.104569 -0.861849
2013-01-04 0.271860 -1.039575 -0.706771 0.721555
2013-01-05 -1.087401 0.276232 0.567020 -0.424972
2013-01-06 0.524988 -1.478427 0.113648 -0.673690
값에 따라 정렬하는 방식입니다.
In [22]: df.sort_values(by='B') # B는 기준이 되는 열의 이름
Out[22]:
A B C D
2013-01-03 -0.861849 -2.104569 -0.494929 1.071804
2013-01-04 0.721555 -0.706771 -1.039575 0.271860
2013-01-01 0.469112 -0.282863 -1.509059 -1.135632
2013-01-02 1.212112 -0.173215 0.119209 -1.044236
2013-01-06 -0.673690 0.113648 -1.478427 0.524988
2013-01-05 -0.424972 0.567020 0.276232 -1.087401
Selection(Indexing, 인덱싱)
Python과 numpy가 직관적이고 interactive work에 단순한 방법을 제공하지만, pandas에서는 실제 코딩 진행시 pandas 데이터에 최적화 된 .at, .iat, .loc .iloc. 메서드를 추천합니다.(0.23 버전 아래의 경우 .ix 메서드도 있습니다) |
인덱싱과 관련된 부분은 Indexing and Selecting Data and MultiIndex / Advanced Indexing. 를 참고하세용
Getting
df.A는, 데이터 프레임 내의 하나의 열을 선택한 것이며, series(시리즈) 객체를 반환합니다:
In [23]: df['A']
Out[23]:
2013-01-01 0.469112
2013-01-02 1.212112
2013-01-03 -0.861849
2013-01-04 0.721555
2013-01-05 -0.424972
2013-01-06 -0.673690
Freq: D, Name: A, dtype: float64
대괄호 [ ] 를 통해 행 또한 슬라이싱할 수 있습니다.
In [24]: df[0:3]
Out[24]:
A B C D
2013-01-01 0.469112 -0.282863 -1.509059 -1.135632
2013-01-02 1.212112 -0.173215 0.119209 -1.044236
2013-01-03 -0.861849 -2.104569 -0.494929 1.071804
In [25]: df['20130102':'20130104']
Out[25]:
A B C D
2013-01-02 1.212112 -0.173215 0.119209 -1.044236
2013-01-03 -0.861849 -2.104569 -0.494929 1.071804
2013-01-04 0.721555 -0.706771 -1.039575 0.271860
Selection by label
자세한 내용은 Selection by Label. 참조
라벨을 이용하여 횡단면으로 보고 싶은 경우:
In [26]: df.loc[dates[0]]
Out[26]:
A 0.469112
B -0.282863
C -1.509059
D -1.135632
Name: 2013-01-01 00:00:00, dtype: float64
축들을 교차로 하여 보고 싶을 경우:
In [27]: df.loc[:, ['A', 'B']]
Out[27]:
A B
2013-01-01 0.469112 -0.282863
2013-01-02 1.212112 -0.173215
2013-01-03 -0.861849 -2.104569
2013-01-04 0.721555 -0.706771
2013-01-05 -0.424972 0.567020
2013-01-06 -0.673690 0.113648
위의 예시에서 특정 행만 인덱싱하는것도 가능합니다
In [28]: df.loc['20130102':'20130104', ['A', 'B']]
Out[28]:
A B
2013-01-02 1.212112 -0.173215
2013-01-03 -0.861849 -2.104569
2013-01-04 0.721555 -0.706771
스칼라 값을 얻고 싶으시다면:
In [30]: df.loc[dates[0], 'A']
Out[30]: 0.4691122999071863
스칼라 값에 빠르게 접근하고 싶다면(이전과 동일하게):
In [31]: df.at[dates[0], 'A']
Out[31]: 0.4691122999071863
Selection by position(데이터의 위치)
자세한 내용은 Selection by Position.
위치를 정수형으로 표현하여 접근하는 방법
In [32]: df.iloc[3]
Out[32]:
A 0.721555
B -0.706771
C -1.039575
D 0.271860
Name: 2013-01-04 00:00:00, dtype: float64
numpy/python의 스타일처럼 정수(위치)의 리스트로 접근하는 법:
In [34]: df.iloc[[1, 2, 4], [0, 2]]
Out[34]:
A C
2013-01-02 1.212112 0.119209
2013-01-03 -0.861849 -0.494929
2013-01-05 -0.424972 0.276232
행만 단독으로 슬라이싱하기:
In [35]: df.iloc[1:3, :]
Out[35]:
A B C D
2013-01-02 1.212112 -0.173215 0.119209 -1.044236
2013-01-03 -0.861849 -2.104569 -0.494929 1.071804
열만 단독으로 슬라이싱하기:
In [36]: df.iloc[:, 1:3]
Out[36]:
B C
2013-01-01 -0.282863 -1.509059
2013-01-02 -0.173215 0.119209
2013-01-03 -2.104569 -0.494929
2013-01-04 -0.706771 -1.039575
2013-01-05 0.567020 0.276232
2013-01-06 0.113648 -1.478427
값(하나의 cell)만 단독으로 슬라이싱하기(스칼라값으로 접근):
In [37]: df.iloc[1, 1]
Out[37]: -0.17321464905330858
스칼라 값에 정수형 인덱스를 가지고 접근하는 빠른 방법:
In [38]: df.iat[1, 1]
Out[38]: -0.17321464905330858
Boolean indexing
데이터를 선택하기 위해, 하나의 열의 값을 이용합니다.
# A 열에서 0보다 큰 값을 인덱싱하면, 해당 행이 출력됩니다
In [39]: df[df['A'] > 0]
Out[39]:
A B C D
2013-01-01 0.469112 -0.282863 -1.509059 -1.135632
2013-01-02 1.212112 -0.173215 0.119209 -1.044236
2013-01-04 0.721555 -0.706771 -1.039575 0.271860
해당 조건이 충족되는 값'만' 선택하기
In [40]: df[df > 0]
Out[40]:
A B C D
2013-01-01 0.469112 NaN NaN NaN
2013-01-02 1.212112 NaN 0.119209 NaN
2013-01-03 NaN NaN NaN 1.071804
2013-01-04 0.721555 NaN NaN 0.271860
2013-01-05 NaN 0.567020 0.276232 NaN
2013-01-06 NaN 0.113648 NaN 0.524988
데이터프레임을 필터링하기 위해서는 isin() 메서드를 사용합니다.
In [41]: df2 = df.copy()
In [42]: df2['E'] = ['one', 'one', 'two', 'three', 'four', 'three']
In [43]: df2
Out[43]:
A B C D E
2013-01-01 0.469112 -0.282863 -1.509059 -1.135632 one
2013-01-02 1.212112 -0.173215 0.119209 -1.044236 one
2013-01-03 -0.861849 -2.104569 -0.494929 1.071804 two
2013-01-04 0.721555 -0.706771 -1.039575 0.271860 three
2013-01-05 -0.424972 0.567020 0.276232 -1.087401 four
2013-01-06 -0.673690 0.113648 -1.478427 0.524988 three
In [44]: df2[df2['E'].isin(['two', 'four'])]
Out[44]:
A B C D E
2013-01-03 -0.861849 -2.104569 -0.494929 1.071804 two
2013-01-05 -0.424972 0.567020 0.276232 -1.087401 four
Setting
기존 데이터 프레임에 새로운 열을 기존 인덱스에 정렬되도록 추가하는 법
In [45]: s1 = pd.Series([1, 2, 3, 4, 5, 6], index=pd.date_range('20130102', periods=6))
In [46]: s1
Out[46]:
2013-01-02 1
2013-01-03 2
2013-01-04 3
2013-01-05 4
2013-01-06 5
2013-01-07 6
Freq: D, dtype: int64
열과 행의 이름(label)으로 한 칸의 값을 설정하는 법:
In [48]: df.at[dates[0], 'A'] = 0
특정 위치의 값을 설정하는 법:
In [49]: df.iat[0, 1] = 0
Numpy 배열을 할당하여 설정하는 법;
df.loc[:, 'D'] = np.array([5] * len(df))
이전 연산들의 결과를 모으면 다음과 같습니다!
In [51]: df
Out[51]:
A B C D F
2013-01-01 0.000000 0.000000 -1.509059 5 NaN
2013-01-02 1.212112 -0.173215 0.119209 5 1.0
2013-01-03 -0.861849 -2.104569 -0.494929 5 2.0
2013-01-04 0.721555 -0.706771 -1.039575 5 3.0
2013-01-05 -0.424972 0.567020 0.276232 5 4.0
2013-01-06 -0.673690 0.113648 -1.478427 5 5.0
where 연산을 setting에 사용하는 경우
In [52]: df2 = df.copy()
In [53]: df2[df2 > 0] = -df2
In [54]: df2
Out[54]:
A B C D F
2013-01-01 0.000000 0.000000 -1.509059 -5 NaN
2013-01-02 -1.212112 -0.173215 -0.119209 -5 -1.0
2013-01-03 -0.861849 -2.104569 -0.494929 -5 -2.0
2013-01-04 -0.721555 -0.706771 -1.039575 -5 -3.0
2013-01-05 -0.424972 -0.567020 -0.276232 -5 -4.0
2013-01-06 -0.673690 -0.113648 -1.478427 -5 -5.0
Missing data
pandas에서는 결측치를 np.nan을 이용하여 나타냅니다. 기본적으로 연산에 포함되지 않습니다. 자세한 내용은 Missing Data section 를 읽어보세요
reindex(데이터프레임의 인덱스를 다시 지정하는 것)는 특정 축의 인덱스를 바꾸고/더하고/삭제할 수 있도록 합니다. 데이터의 원본이 변하는 것이 아니라, 데이터의 복사본을 반환합니다.
In [55]: df1 = df.reindex(index=dates[0:4], columns=list(df.columns) + ['E'])
In [56]: df1.loc[dates[0]:dates[1], 'E'] = 1
In [57]: df1
Out[57]:
A B C D F E
2013-01-01 0.000000 0.000000 -1.509059 5 NaN 1.0
2013-01-02 1.212112 -0.173215 0.119209 5 1.0 1.0
2013-01-03 -0.861849 -2.104569 -0.494929 5 2.0 NaN
2013-01-04 0.721555 -0.706771 -1.039575 5 3.0 NaN
결측치가 있는 행을 삭제하는 방법:
In [58]: df1.dropna(how='any')
Out[58]:
A B C D F E
2013-01-02 1.212112 -0.173215 0.119209 5 1.0 1.0
결측치를 채우는 방법:
In [59]: df1.fillna(value=5)
Out[59]:
A B C D F E
2013-01-01 0.000000 0.000000 -1.509059 5 5.0 1.0
2013-01-02 1.212112 -0.173215 0.119209 5 1.0 1.0
2013-01-03 -0.861849 -2.104569 -0.494929 5 2.0 5.0
2013-01-04 0.721555 -0.706771 -1.039575 5 3.0 5.0
np.nan인 곳의 위치를 True, 아닌 곳을 False로 출력하는 방법:
In [60]: pd.isna(df1)
Out[60]:
A B C D F E
2013-01-01 False False False False True False
2013-01-02 False False False False False False
2013-01-03 False False False False False True
2013-01-04 False False False False False True
Operations
자세한 내용은 Basic section on Binary Ops.
Stats
보통 결측치를 제외하고 연산합니다.
기술통계량 보여주기:
In [61]: df.mean() # 열 기준
Out[61]:
A -0.004474
B -0.383981
C -0.687758
D 5.000000
F 3.000000
dtype: float64
#축을 다르게, 행 기준
In [62]: df.mean(1)
Out[62]:
2013-01-01 0.872735
2013-01-02 1.431621
2013-01-03 0.707731
2013-01-04 1.395042
2013-01-05 1.883656
2013-01-06 1.592306
Freq: D, dtype: float64
Operating with objects that have different dimensionality and need alignment. In addition, pandas automatically broadcasts along the specified dimension.(다른 차원을 가진 객체들을 가지고 연산을 할 때에는 정렬이 필요합니다. 또한 pandas는 자동으로 특정 차원에 대해 알려줍니다, series와 dataframe은 사실상 다른 차원이지만 연산을 가능하게 해준다는 의미 같네요!)
In [63]: s = pd.Series([1, 3, 5, np.nan, 6, 8], index=dates).shift(2)
In [64]: s
Out[64]:
2013-01-01 NaN
2013-01-02 NaN
2013-01-03 1.0
2013-01-04 3.0
2013-01-05 5.0
2013-01-06 NaN
Freq: D, dtype: float64
In [65]: df.sub(s, axis='index')
Out[65]:
A B C D F
2013-01-01 NaN NaN NaN NaN NaN
2013-01-02 NaN NaN NaN NaN NaN
2013-01-03 -1.861849 -3.104569 -1.494929 4.0 1.0
2013-01-04 -2.278445 -3.706771 -4.039575 2.0 0.0
2013-01-05 -5.424972 -4.432980 -4.723768 0.0 -1.0
2013-01-06 NaN NaN NaN NaN NaN
Apply
함수를 데이터에 적용하기:
In [66]: df.apply(np.cumsum)
Out[66]:
A B C D F
2013-01-01 0.000000 0.000000 -1.509059 5 NaN
2013-01-02 1.212112 -0.173215 -1.389850 10 1.0
2013-01-03 0.350263 -2.277784 -1.884779 15 3.0
2013-01-04 1.071818 -2.984555 -2.924354 20 6.0
2013-01-05 0.646846 -2.417535 -2.648122 25 10.0
2013-01-06 -0.026844 -2.303886 -4.126549 30 15.0
In [67]: df.apply(lambda x: x.max() - x.min())
Out[67]:
A 2.073961
B 2.671590
C 1.785291
D 0.000000
F 4.000000
dtype: float64
Histogramming
자세한 내용은 Histogramming and Discretization.
# 0~6까지에서 랜덤한 정수를 10개 뽑아 시리즈로 생성
In [68]: s = pd.Series(np.random.randint(0, 7, size=10))
In [69]: s
Out[69]:
0 4
1 2
2 1
3 2
4 6
5 4
6 4
7 6
8 4
9 4
dtype: int64
# 각 정수가 몇개가 있는지 value_counts
In [70]: s.value_counts()
Out[70]:
4 5
6 2
2 2
1 1
dtype: int64
String Methods
아래 코드 예시처럼, Series 객체는 배열 내의 문자에 대해 더욱 쉽게 연산할 수 있도록 하는 처리 메서드를 갖추고 있습니다. str에서 문자열의 패턴을 매칭하는 경우, 일반적으로 regular expressions 을 디폴트로 사용한다는 걸 기억하세요!(일부는 항상 정규표현식을 써야할 때가 있습니다. ) 자세한 내용은 Vectorized String Methods.
In [71]: s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan, 'CABA', 'dog', 'cat'])
In [72]: s.str.lower()
Out[72]:
0 a
1 b
2 c
3 aaba
4 baca
5 NaN
6 caba
7 dog
8 cat
dtype: object
Merge
Concat
pandas provides various facilities for easily combining together Series and DataFrame objects with various kinds of set logic for the indexes and relational algebra functionality in the case of join / merge-type operations.See the Merging section.
(pandas는 Series와 Dataframe 객체를 다양한 방식으로 결합하기 쉽도록 메서드를 제공합니다!)
pandas 객체들을 concat()으로 합치기:
In [73]: df = pd.DataFrame(np.random.randn(10, 4))
In [74]: df
Out[74]:
0 1 2 3
0 -0.548702 1.467327 -1.015962 -0.483075
1 1.637550 -1.217659 -0.291519 -1.745505
2 -0.263952 0.991460 -0.919069 0.266046
3 -0.709661 1.669052 1.037882 -1.705775
4 -0.919854 -0.042379 1.247642 -0.009920
5 0.290213 0.495767 0.362949 1.548106
6 -1.131345 -0.089329 0.337863 -0.945867
7 -0.932132 1.956030 0.017587 -0.016692
8 -0.575247 0.254161 -1.143704 0.215897
9 1.193555 -0.077118 -0.408530 -0.862495
# break it into pieces
In [75]: pieces = [df[:3], df[3:7], df[7:]]
In [76]: pd.concat(pieces)
Out[76]:
0 1 2 3
0 -0.548702 1.467327 -1.015962 -0.483075
1 1.637550 -1.217659 -0.291519 -1.745505
2 -0.263952 0.991460 -0.919069 0.266046
3 -0.709661 1.669052 1.037882 -1.705775
4 -0.919854 -0.042379 1.247642 -0.009920
5 0.290213 0.495767 0.362949 1.548106
6 -1.131345 -0.089329 0.337863 -0.945867
7 -0.932132 1.956030 0.017587 -0.016692
8 -0.575247 0.254161 -1.143704 0.215897
9 1.193555 -0.077118 -0.408530 -0.862495
위의 방식보다, Dataframe에 열을 붙이는 방식이 상대적으로 더 빠릅니다. 하지만, 행을 합치는 경우에는 데이터의 복사가 요구되거나 더 expensive 할 수 있습니다. Dataframe에 반복적인 작업으로 열을 추가하는 것보다, 사전에 합칠 내용들을 리스트로 만들어 놓고 위와 같은 방식을 사용하는 것을 추천합니다. 자세한 부분은 Appending to dataframe 참조 |
Join
join는 SQL 스타일의 병합입니다. 자세한 내용은 Database style joining을 참고하세요
In [77]: left = pd.DataFrame({'key': ['foo', 'foo'], 'lval': [1, 2]})
In [78]: right = pd.DataFrame({'key': ['foo', 'foo'], 'rval': [4, 5]})
In [79]: left
Out[79]:
key lval
0 foo 1
1 foo 2
In [80]: right
Out[80]:
key rval
0 foo 4
1 foo 5
In [81]: pd.merge(left, right, on='key')
Out[81]:
key lval rval
0 foo 1 4
1 foo 1 5
2 foo 2 4
3 foo 2 5
Grouping
"group by"를 통하여 우리는 아래와 같은 것들을 추가적으로 진행할 수 있습니다. 자세한 내용은 Grouping section.
- Splitting 데이터를 특정 기준으로 나눠진 그룹단위로 쪼개기
- Applying 하나의 그룹에 독립적으로 함수 적용하기
- Combining 결과를 데이터 구조 안으로 결합하기
In [87]: df = pd.DataFrame({'A': ['foo', 'bar', 'foo', 'bar',
....: 'foo', 'bar', 'foo', 'foo'],
....: 'B': ['one', 'one', 'two', 'three',
....: 'two', 'two', 'one', 'three'],
....: 'C': np.random.randn(8),
....: 'D': np.random.randn(8)})
....:
In [88]: df
Out[88]:
A B C D
0 foo one 1.346061 -1.577585
1 bar one 1.511763 0.396823
2 foo two 1.627081 -0.105381
3 bar three -0.990582 -0.532532
4 foo two -0.441652 1.453749
5 bar two 1.211526 1.208843
6 foo one 0.268520 -0.080952
7 foo three 0.024580 -0.264610
그룹핑한 결과에 대해 sum() 함수를 적용하기:
In [89]: df.groupby('A').sum()
Out[89]:
C D
A
bar 1.732707 1.073134
foo 2.824590 -0.574779
계층에 따라 그룹핑 한 후에도 함수 적용이 가능합니다:
In [90]: df.groupby(['A', 'B']).sum()
Out[90]:
C D
A B
bar one 1.511763 0.396823
three -0.990582 -0.532532
two 1.211526 1.208843
foo one 1.614581 -1.658537
three 0.024580 -0.264610
two 1.185429 1.348368
Reshaping
자세한 내용은 Hierarchical Indexing and Reshaping.
Stack
In [91]: tuples = list(zip(*[['bar', 'bar', 'baz', 'baz',
....: 'foo', 'foo', 'qux', 'qux'],
....: ['one', 'two', 'one', 'two',
....: 'one', 'two', 'one', 'two']]))
....:
In [92]: index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
In [93]: df = pd.DataFrame(np.random.randn(8, 2), index=index, columns=['A', 'B'])
In [94]: df2 = df[:4]
In [95]: df2
Out[95]:
A B
first second
bar one -0.727965 -0.589346
two 0.339969 -0.693205
baz one -0.339355 0.593616
two 0.884345 1.591431
stack()메서드는 데이터프레임 열의 계층을 "압축" 하기도 합니다.
In [96]: stacked = df2.stack()
In [97]: stacked
Out[97]:
first second
bar one A -0.727965
B -0.589346
two A 0.339969
B -0.693205
baz one A -0.339355
B 0.593616
two A 0.884345
B 1.591431
dtype: float64
이미 한번 "stacked"된 Dataframe이나 Series(인덱스가 multi index인 경우), 반대의 연산은 unstack()으로, 가장 마지막 계층을 unstack 해줍니다.:
In [98]: stacked.unstack()
Out[98]:
A B
first second
bar one -0.727965 -0.589346
two 0.339969 -0.693205
baz one -0.339355 0.593616
two 0.884345 1.591431
In [99]: stacked.unstack(1)
Out[99]:
second one two
first
bar A -0.727965 0.339969
B -0.589346 -0.693205
baz A -0.339355 0.884345
B 0.593616 1.591431
In [100]: stacked.unstack(0)
Out[100]:
first bar baz
second
one A -0.727965 -0.339355
B -0.589346 0.593616
two A 0.339969 0.884345
B -0.693205 1.591431
Pivot tables
자세한 내용은 Pivot Tables. 참조
In [101]: df = pd.DataFrame({'A': ['one', 'one', 'two', 'three'] * 3,
.....: 'B': ['A', 'B', 'C'] * 4,
.....: 'C': ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'] * 2,
.....: 'D': np.random.randn(12),
.....: 'E': np.random.randn(12)})
.....:
In [102]: df
Out[102]:
A B C D E
0 one A foo -1.202872 0.047609
1 one B foo -1.814470 -0.136473
2 two C foo 1.018601 -0.561757
3 three A bar -0.595447 -1.623033
4 one B bar 1.395433 0.029399
5 one C bar -0.392670 -0.542108
6 two A foo 0.007207 0.282696
7 three B foo 1.928123 -0.087302
8 one C foo -0.055224 -1.575170
9 one A bar 2.395985 1.771208
10 two B bar 1.552825 0.816482
11 three C bar 0.166599 1.100230
위의 데이터들을 아주 간단!하게 피봇테이블로 만들 수 있습니다.
In [103]: pd.pivot_table(df, values='D', index=['A', 'B'], columns=['C'])
Out[103]:
C bar foo
A B
one A 2.395985 -1.202872
B 1.395433 -1.814470
C -0.392670 -0.055224
three A -0.595447 NaN
B NaN 1.928123
C 0.166599 NaN
two A NaN 0.007207
B 1.552825 NaN
C NaN 1.018601
Time series
pandas 에는 freq를 변환하기 위한 간단하고, 강력하고 효율적인 resample 연산 메서드들이 있습니다. 금융 분야에서 주로 사용되고 있습니다. 자세한 내용은 Time Series section.
In [104]: rng = pd.date_range('1/1/2012', periods=100, freq='S')
In [105]: ts = pd.Series(np.random.randint(0, 500, len(rng)), index=rng)
In [106]: ts.resample('5Min').sum()
Out[106]:
2012-01-01 24182
Freq: 5T, dtype: int64
타임존도 표현할 수 있다.
In [107]: rng = pd.date_range('3/6/2012 00:00', periods=5, freq='D')
In [108]: ts = pd.Series(np.random.randn(len(rng)), rng)
In [109]: ts
Out[109]:
2012-03-06 1.857704
2012-03-07 -1.193545
2012-03-08 0.677510
2012-03-09 -0.153931
2012-03-10 0.520091
Freq: D, dtype: float64
In [110]: ts_utc = ts.tz_localize('UTC')
In [111]: ts_utc
Out[111]:
2012-03-06 00:00:00+00:00 1.857704
2012-03-07 00:00:00+00:00 -1.193545
2012-03-08 00:00:00+00:00 0.677510
2012-03-09 00:00:00+00:00 -0.153931
2012-03-10 00:00:00+00:00 0.520091
Freq: D, dtype: float64
다른 타임존으로 변경하기:
In [112]: ts_utc.tz_convert('US/Eastern')
Out[112]:
2012-03-05 19:00:00-05:00 1.857704
2012-03-06 19:00:00-05:00 -1.193545
2012-03-07 19:00:00-05:00 0.677510
2012-03-08 19:00:00-05:00 -0.153931
2012-03-09 19:00:00-05:00 0.520091
Freq: D, dtype: float64
표현되는 기간 단위 : (%y%m , %y%m%d 등)
In [113]: rng = pd.date_range('1/1/2012', periods=5, freq='M')
In [114]: ts = pd.Series(np.random.randn(len(rng)), index=rng)
In [115]: ts
Out[115]:
2012-01-31 -1.475051
2012-02-29 0.722570
2012-03-31 -0.322646
2012-04-30 -1.601631
2012-05-31 0.778033
Freq: M, dtype: float64
In [116]: ps = ts.to_period()
In [117]: ps
Out[117]:
2012-01 -1.475051
2012-02 0.722570
2012-03 -0.322646
2012-04 -1.601631
2012-05 0.778033
Freq: M, dtype: float64
In [118]: ps.to_timestamp()
Out[118]:
2012-01-01 -1.475051
2012-02-01 0.722570
2012-03-01 -0.322646
2012-04-01 -1.601631
2012-05-01 0.778033
Freq: MS, dtype: float64
이렇게 period와 timestamp 단위를 변환해주는 것은 몇몇 수학적 연산을 가능하게 해줍니다.
In [119]: prng = pd.period_range('1990Q1', '2000Q4', freq='Q-NOV')
In [120]: ts = pd.Series(np.random.randn(len(prng)), prng)
In [121]: ts.index = (prng.asfreq('M', 'e') + 1).asfreq('H', 's') + 9
In [122]: ts.head()
Out[122]:
1990-03-01 09:00 -0.289342
1990-06-01 09:00 0.233141
1990-09-01 09:00 -0.223540
1990-12-01 09:00 0.542054
1991-03-01 09:00 -0.688585
Freq: H, dtype: float64
Categoricals
pandas에는 범주형 데이터 또한 사용이 가능합니다. 자세한 내용은 categorical introduction and the API documentation. 를 참고하세요
In [123]: df = pd.DataFrame({"id": [1, 2, 3, 4, 5, 6],
.....: "raw_grade": ['a', 'b', 'b', 'a', 'a', 'e']})
.....:
위의 raw_grade를 범주형 타입으로 바꿔줍니다:
In [124]: df["grade"] = df["raw_grade"].astype("category")
In [125]: df["grade"]
Out[125]:
0 a
1 b
2 b
3 a
4 a
5 e
Name: grade, dtype: category
Categories (3, object): ['a', 'b', 'e']
범주형 데이터의 명칭을 좀 더 실용적으로 쓰일 수 있도록 바꿔줄 수 있습니다.
In [126]: df["grade"].cat.categories = ["very good", "good", "very bad"]
카테고리를 지정합과 동시에 기존에 포함되어 있지 않은 카테고리를 새롭게 지정할 수 있습니다. (Series.cat()과 관련된 메서드들은 기본적으로 series 형태를 반환합니다)
In [127]: df["grade"] = df["grade"].cat.set_categories(["very bad", "bad", "medium",
.....: "good", "very good"])
.....:
In [128]: df["grade"]
Out[128]:
0 very good
1 good
2 good
3 very good
4 very good
5 very bad
Name: grade, dtype: category
Categories (5, object): ['very bad', 'bad', 'medium', 'good', 'very good']
문자열 순서대로가 아니라, 카테고리 내의 순서대로 정렬이 가능합니다
In [129]: df.sort_values(by="grade")
Out[129]:
id raw_grade grade
5 6 e very bad
1 2 b good
2 3 b good
0 1 a very good
3 4 a very good
4 5 a very good
카테고리끼리 그룹으로 묶었을 때, 데이터가 없는 명목형 변수 또한 표시해줍니다.
In [130]: df.groupby("grade").size()
Out[130]:
grade
very bad 1
bad 0 # 데이터가 없는 명목형 변수
medium 0 # 데이터가 없는 명목형 변수
good 2
very good 3
dtype: int64
Plotting
자세한 내용은 Plotting 을 참조
아래 예시에는, 일반적으로 사용되는 matplotlib api 를 사용했습니다.
In [131]: import matplotlib.pyplot as plt
In [132]: plt.close('all')
In [133]: ts = pd.Series(np.random.randn(1000),
.....: index=pd.date_range('1/1/2000', periods=1000))
.....:
In [134]: ts = ts.cumsum()
In [135]: ts.plot()
Out[135]: <matplotlib.axes._subplots.AxesSubplot at 0x7fe295d72160>
DataFrame에서, plot() 메서드는 모든 라벨의 columns를 편하게 그래프로 표현할 수 있습니다.
In [136]: df = pd.DataFrame(np.random.randn(1000, 4), index=ts.index,
.....: columns=['A', 'B', 'C', 'D'])
.....:
In [137]: df = df.cumsum()
In [138]: plt.figure()
Out[138]: <Figure size 640x480 with 0 Axes>
In [139]: df.plot()
Out[139]: <matplotlib.axes._subplots.AxesSubplot at 0x7fe295d17c10>
In [140]: plt.legend(loc='best')
Out[140]: <matplotlib.legend.Legend at 0x7fe295c94fd0>
Getting data in/out
Writing to a csv file.csv 파일을 만드는 방법
In [141]: df.to_csv('foo.csv')
Reading from a csv file. csv 파일 읽어오는 방법
In [142]: pd.read_csv('foo.csv')
Out[142]:
Unnamed: 0 A B C D
0 2000-01-01 0.350262 0.843315 1.798556 0.782234
1 2000-01-02 -0.586873 0.034907 1.923792 -0.562651
2 2000-01-03 -1.245477 -0.963406 2.269575 -1.612566
3 2000-01-04 -0.252830 -0.498066 3.176886 -1.275581
4 2000-01-05 -1.044057 0.118042 2.768571 0.386039
.. ... ... ... ... ...
995 2002-09-22 -48.017654 31.474551 69.146374 -47.541670
996 2002-09-23 -47.207912 32.627390 68.505254 -48.828331
997 2002-09-24 -48.907133 31.990402 67.310924 -49.391051
998 2002-09-25 -50.146062 33.716770 67.717434 -49.037577
999 2002-09-26 -49.724318 33.479952 68.108014 -48.822030
[1000 rows x 5 columns]
HDF5
hdf5를 쓰는 방법 HDFStores.
In [143]: df.to_hdf('foo.h5', 'df')
hdf5를 읽는 방법:
In [144]: pd.read_hdf('foo.h5', 'df')
Out[144]:
A B C D
2000-01-01 0.350262 0.843315 1.798556 0.782234
2000-01-02 -0.586873 0.034907 1.923792 -0.562651
2000-01-03 -1.245477 -0.963406 2.269575 -1.612566
2000-01-04 -0.252830 -0.498066 3.176886 -1.275581
2000-01-05 -1.044057 0.118042 2.768571 0.386039
... ... ... ... ...
2002-09-22 -48.017654 31.474551 69.146374 -47.541670
2002-09-23 -47.207912 32.627390 68.505254 -48.828331
2002-09-24 -48.907133 31.990402 67.310924 -49.391051
2002-09-25 -50.146062 33.716770 67.717434 -49.037577
2002-09-26 -49.724318 33.479952 68.108014 -48.822030
[1000 rows x 4 columns]
Excel
엑셀 파일을 작성하는 방법
In [145]: df.to_excel('foo.xlsx', sheet_name='Sheet1')
엑셀 파일을 읽는 방법
In [146]: pd.read_excel('foo.xlsx', 'Sheet1', index_col=None, na_values=['NA'])
Out[146]:
Unnamed: 0 A B C D
0 2000-01-01 0.350262 0.843315 1.798556 0.782234
1 2000-01-02 -0.586873 0.034907 1.923792 -0.562651
2 2000-01-03 -1.245477 -0.963406 2.269575 -1.612566
3 2000-01-04 -0.252830 -0.498066 3.176886 -1.275581
4 2000-01-05 -1.044057 0.118042 2.768571 0.386039
.. ... ... ... ... ...
995 2002-09-22 -48.017654 31.474551 69.146374 -47.541670
996 2002-09-23 -47.207912 32.627390 68.505254 -48.828331
997 2002-09-24 -48.907133 31.990402 67.310924 -49.391051
998 2002-09-25 -50.146062 33.716770 67.717434 -49.037577
999 2002-09-26 -49.724318 33.479952 68.108014 -48.822030
[1000 rows x 5 columns]
Gotchas
간혹 작업을 진행하다 보면 아래와 같은 exception이 나올 수 있습니다.
>>> if pd.Series([False, True, False]):
... print("I was true")
Traceback
...
ValueError: The truth value of an array is ambiguous. Use a.empty, a.any() or a.all().
그런 경우, Comparisons , Gotchas를 보시고 해결방법을 찾아보세요!
저도 pandas 를 다룬지 몇 개월 되어가지만, 제가 얼마나 부족했는지 깨닫게 되는 번역작업이었네요!
화이팅 주니어 호승
참고문헌