Pandas 소개 3

GonsSu24 내용에 이어서 Pandas 라이브러리를 소개한다.

먼저 GongSu24를 임포트 한다.


In [1]:
from GongSu24_Pandas_Introduction_1 import *


C:\ProgramData\Anaconda2\lib\site-packages\pandas\core\indexing.py:179: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
  self._setitem_with_indexer(indexer, value)

5.2.2 하나의 로우 또는 칼럼 제외하기: drop 메소드

drop 메서드를 사용하여 지정된 행 또는 열을 제외하여 새로운 Series나 DataFrame을 생성할 수 있다.


In [33]:
obj = Series(np.arange(5.), index=['a', 'b', 'c', 'd', 'e'])
obj


Out[33]:
a    0.0
b    1.0
c    2.0
d    3.0
e    4.0
dtype: float64

In [34]:
new_obj = obj.drop('c')
new_obj


Out[34]:
a    0.0
b    1.0
d    3.0
e    4.0
dtype: float64

In [35]:
obj.drop(['d', 'c'])


Out[35]:
a    0.0
b    1.0
e    4.0
dtype: float64

DataFrame에서는 로우와 칼럼 모두에서 값을 삭제할 수 있다.


In [36]:
df7


Out[36]:
Ohio Texas California
a 0.0 1.0 2.0
b 3.0 4.0 5.0
c NaN NaN NaN
d 6.0 7.0 8.0
  • 행 삭제

In [37]:
df7.drop('a', axis=0)


Out[37]:
Ohio Texas California
b 3.0 4.0 5.0
c NaN NaN NaN
d 6.0 7.0 8.0

In [38]:
df7.drop('Ohio', axis=1)


Out[38]:
Texas California
a 1.0 2.0
b 4.0 5.0
c NaN NaN
d 7.0 8.0

drop() 메소드는 기존의 자료를 건드리지 않는다.


In [39]:
df7


Out[39]:
Ohio Texas California
a 0.0 1.0 2.0
b 3.0 4.0 5.0
c NaN NaN NaN
d 6.0 7.0 8.0

In [40]:
data.drop('two', axis=1)


---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-40-6d23fc01e172> in <module>()
----> 1 data.drop('two', axis=1)

AttributeError: 'numpy.ndarray' object has no attribute 'drop'

In [ ]:
data.drop(['two', 'four'], axis=1)

5.2.2 하나의 로우 또는 칼럼 삭제하기: del 메소드

del 메서드를 사용하여 지정된 행 또는 열을 삭제할 수 있다.


In [ ]:


In [ ]:


In [ ]:

5.2.3 색인하기, 선택하기, 거르기

Series의 색인 (obj[...])은 NumPy 배열의 색인과 유사하게 동작하는데, Series의 색인은 정수가 아니어도 된다는 점이 다르다.

라벨 이름으로 슬라이싱하는 것은 시작점과 끝점을 포함한다는 점이 일반 파이선에서 슬라이싱과 다른 점이다.


In [ ]:
obj = Series(np.arange(4.), index=['a', 'b', 'c', 'd'])
obj['b':'c']

슬라이싱 문법으로 선택된 영역에 값을 대입하는 것은 예상한 대로 동작한다.


In [ ]:
obj['b':'c'] = 5
obj

앞에서 확인한대로 색인으로 DataFrame에서 칼럼의 값을 하나 이상 가져올 수 있다.


In [ ]:
data = DataFrame(np.arange(16).reshape((4, 4)),
                 index=['Ohio', 'Colorado', 'Utah', 'New York'],
                 columns = ['one', 'two', 'three', 'four'])
data

In [ ]:
data['two']

In [ ]:
data[['three', 'one']]

슬라이싱으로 로우를 선택하거나 불리언 배열로 칼럼을 선택할 수 있다.


In [ ]:
data[:2]

In [ ]:
data[data['three'] > 5]

이 문법에 모순이 있다고 생각할 수 있지만, 실용성에 기인한 것일 뿐이다.

또 다른 사례는 스칼라 비교를 통해 생성된 불리언 DataFrame을 사용해서 값을 선택하는 것이다.


In [ ]:
data < 5

In [ ]:
data[data < 5] = 0
data

이 예제는 DataFrame을 ndarray와 문법적으로 비슷하게 보이도록 의도한 것이다.

DataFrame의 칼럼에 대해 라벨로 색인하는 방법으로, 특수한 색인 필드인 ix를 소개한다. ix는 NumPy와 비슷한 방식에 추가적으로 축의 라벨을 사용하여 DataFrame의 로우와 칼럼을 선택할 수 있도록 한다. 앞에서 언급했듯이 이 방법은 재색인을 좀 더 간단하게 할 수 있는 방법이다.


In [ ]:
data.ix['Colorado', ['two', 'three']]

In [ ]:
data.ix[['Colorado', 'Utah'], [3,0,1]]

In [ ]:
data.ix[2]

In [ ]:
data.ix[:'Utah', 'two']

In [ ]:
data.ix[data.three > 5, :3]

지금까지 살펴봤듯이 pandas 객체에서 데이터를 선택하고 재배열하는 방법은 여러 가지가 있다. [표 5-6]에 다양한 방법을 정리해두었다. 나중에 살펴볼 계층적 색인을 이용하면 좀 더 다양한 방법을 사용할 수 있다.

5.2.4 산술연산과 데이터 정렬

pandas에서 중요한 기능은 색인이 다른 객체 간의 산술연산이다. 객체를 더할 때 짝이 맞지 않는 색인이 있다면 결과에 두 색인이 통합된다.


In [ ]:
s1 = Series([7.3, -2.5, 3.4, 1.5], index=['a', 'c', 'd','e'])
s2 = Series([-2.1, 3.6, -1.5, 4, 3.1], index=['a', 'c', 'e', 'f', 'g'])
s1 + s2

서로 겹치는 색인이 없다면 데이터는 NA 값이 된다. 산술연산 시 누락된 값은 전파되며, DataFrame에서는 로우와 칼럼 모두에 적용된다.


In [ ]:
df1 = DataFrame(np.arange(9.).reshape((3, 3)), columns=list('bcd'),
                index=['Ohio', 'Texas', 'Colorado'])
df2 = DataFrame(np.arange(12.).reshape((4,3)), columns=list('bde'),
                         index=['Utah', 'Ohio', 'Texas', 'Oregon'])

In [ ]:
df1 + df2

산술연산 메서드에 채워 넣을 값 지정하기

서로 다른 색인을 가지는 객체 간의 산술연산에서 존재하지 않는 축의 값을 특수한 값( 0 같은)으로 지정하고 싶을 때는 다음과 같이 할 수 있다.


In [ ]:
df1 = DataFrame(np.arange(12.).reshape((3,4)), columns=list('abcd'))
df2 = DataFrame(np.arange(20.).reshape((4,5)), columns=list('abcde'))

In [ ]:
df1

In [ ]:
df2

In [ ]:
df1 + df2

이 둘을 더했을 때 겹치지 않는 부분의 값이 NA값이 된 것을 알 수 있다.

df1의 add메서드로 df2와 fill_value 값을 인자로 전달한다.


In [ ]:
df1.add(df2, fill_value=0)

In [ ]:
df1.reindex(columns=df2.columns, fill_value=0)

Series나 DataFrame을 재색인할 때 역시 fill_value를 지정할 수 있다.

DataFrame과 Series 간의 연산

NumPy 배열의 연산처럼 DataFrame과 Series 간의 연산도 잘 정의되어 있다. 먼저 2차원 배열과 그 배열 중 한 칼럼의 차이에 대해서 생각할 수 있는 예제를 살펴보자.


In [ ]:
arr = np.arange(12).reshape(3, 4)

In [ ]:
arr

In [ ]:
arr[0]

In [ ]:
arr - arr[0]

이 예제는 브로드캐스팅에 대한 예제로 자세한 내용은 12장에서 살펴볼 것이다. DataFrame과 Series간의 연산은 이와 유사하다.


In [ ]:
frame = DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'),
                  index=['Utah', 'Ohio', 'Texas', 'Oregon'])
series = frame.ix[0]
frame

In [ ]:
series

기본적으로 DataFrame과 Series 간의 산술 연산은 Series의 색인을 DataFrame의 칼럼에 맞추고 아래 로우로 전파한다.


In [ ]:
frame - series

만약 색인 값을 DataFrame의 칼럼이나 Series의 색인에서 찾을 수 없다면 그 객체는 형식을 맞추기 위해 재색인된다.


In [ ]:
series2 = Series(range(3), index = list('bef'))
frame + series2

만약 각 로우에 대해 연산을 수행하고 싶다면 산술연산 메서드를 사용하면 된다.


In [ ]:
series3 = frame['d']

In [ ]:
frame

In [ ]:
series3

In [ ]:
frame.sub(series3, axis=0)

5.2.5 함수 적용과 매핑

pandas 객체에도 NumPy의 유니버설 함수( 배열의 각 원소에 적용되는 메서드)를 적용할 수 있다.


In [ ]:
frame = DataFrame(np.random.randn(4,3), columns=list('bde'),
                  index=['Utah', 'Ohio', 'Texas', 'Oregon'])
frame

In [ ]:
np.abs(frame) #절대값

자주 사용되는 또 다른 연산은 각 로우나 칼럼의 1차원 배열에 함수를 적용하는 것이다. DataFrame의 apply 메서드를 통해 수행할 수 있다.


In [ ]:
f = lambda x: x.max() - x.min()
frame.apply(f)

In [ ]:
frame.apply(f, axis=1)

배열의 합계나 평균 같은 일반적인 통계는 DataFrame의 메서드로 있으므로 apply 메서드를 사용해야만 하는 것은 아니다.

apply 메서드에 전달된 함수는 스칼라 값을 반환할 필요가 없으며, Series 또는 여러 값을 반환해도 된다.


In [ ]:
def f(x):
    return Series([x.min(), x.max()], index=['min', 'max'])

In [ ]:
frame.apply(f)

배열의 각 원소에 적용되는 파이썬의 함수를 사용할 수도 있다. frame 객체에서 실수 값을 문자열 포맷으로 변환하고 싶다면 applymap을 이용해서 다음과 같이 해도 된다.


In [ ]:
format = lambda x: '%.2f' % x
frame.applymap(format)

이 메서드의 이름이 applymap인 이유는 Series가 각 원소에 적용할 함수를 지정하기 위한 map 메서드를 가지고 있기 때문이다.


In [ ]:
frame['e'].map(format)

5.2.6 정렬과 순위

어떤 기준에 근거해서 데이터를 정렬하는 것 역시 중요한 명령이다. 로우나 칼럼의 색인을 알파벳 순으로 정렬하려면 정렬된 새로운 객체를 반화하는 sort_index 메서드를 사용하면 된다.


In [ ]:
frame['e'].map(format)

5.2.6

어떤 기준에 근거해서 데이터를 정렬하는 것 역시 중요한 명령이다. 로우나 칼럼의 색인을 알파벳 순으로 정렬하려면 정렬된 새로운 객체를 반환하는 sort_index 메서드를 사용하면 된다.


In [ ]:
obj = Series(range(4), index=['d', 'a', 'b', 'c'])
obj.sort_index()

DataFrame은 로우나 칼럼 중 하나의 축을 기준으로 정렬할 수 있다.


In [ ]:
frame = DataFrame(np.arange(8).reshape((2,4)), index = ['three', 'one'], columns = ['d', 'a', 'b', 'c'])

In [ ]:
frame.sort_index()

In [ ]:
frame.sort_index(axis=1)

데이터는 기본적으로 오름차순으로 정렬되지만 내림차순으로 정렬할 수도 있다.


In [ ]:
frame.sort_index(axis=1, ascending=False)

Series 객체를 값에 따라 정렬하고 싶다면 sort_values 메서드를 사용한다.


In [ ]:
obj.sort_values()

In [ ]:
obj = Series([4, 7, -3, 2])
obj.sort_values()

정렬할 때 비어있는 값은 기본적으로 Series 객체에서 가장 마지막에 위치한다.

obj = Series([4, np.nan, 7, np.nan, -3, 2]) obj.sort_values()

DataFrame에서는 하나 이상의 칼럼에 있는 값으로 정렬이 필요할 수 있다. 이럴 때는 by 옵션에 필요한 칼럼의 이름을 넘기면 된다.


In [ ]:
frame = DataFrame({'b': [4, 7, -3, 2], 'a': [0, 1, 0, 1]})
frame

In [ ]:
frame.sort_values(by='b')

여러 개의 칼럼을 정렬하려면 칼럼의 이름이 담긴 리스트를 전달하면 된다.


In [ ]:
frame.sort_values(by=['a','b'])

순위는 정렬과 거의 흡사하며, 1부터 배열의 유효한 데이터 개수까지 순위를 매긴다. 또한 순위는 numpy.argsort에서 반환하는 간접 정렬 색인과 유사한데, 동률인 순위를 처리하는 방식이 다르다. 기본적으로 Series와 DataFrame의 rank 메서드는 동점인 항목에 대해서는 평균 순위를 매긴다.


In [ ]:
obj = Series([7, -5, 7, 4, 2, 0 ,4])
obj.rank()

데이터 상에서 나타나는 순서에 따라 순위를 매길 수도 있다.


In [ ]:
obj.rank(method='first')

내림차순으로 순위를 매길 수도 있다.


In [ ]:
# 'max' 는 같은 값을 가지는 그룹을 높은 순위로 매긴다.
obj.rank(ascending=False, method='max')

5.2.7 중복 색인

지금까지 살펴본 모든 예제는 모두 축의 이름(색인 값)이 유일했다. pandas의 많은 함수(reindex 같은) 에서 색인 값은 유일해야 하지만 강제 사항은 아니다. 이제 색인 값이 중복된 Series객체를 살펴보자.


In [ ]:
obj = Series(range(5), index=['a', 'a', 'b', 'b', 'c'])
obj

색인의 is_unique 속성은 해당 값이 유일한지 아닌지 알려준다.


In [ ]:
obj.index.is_unique

중복되는 색인 값이 있으면 색인을 이용한 데이터 선택은 다르게 동작하고 하나의 Series 객체를 반환한다. 하지만 중복되는 색인 값이 없으면 색인을 이용한 데이터 선택은 스칼라 값을 반환한다.


In [ ]:
obj['a']

In [ ]:
obj['c']

DataFrame에서 로우를 선택하는 것도 동일하다.


In [ ]:
df = DataFrame(np.random.randn(4, 3), index=['a', 'a', 'b','b'])
df

In [ ]:
df.ix['b']