GonsSu24 내용에 이어서 Pandas 라이브러리를 소개한다.
먼저 GongSu24를 임포트 한다.
In [1]:
from GongSu24_Pandas_Introduction_1 import *
아래와 같이 Series 객체를 생성한 후에 index를 확인해보자.
In [2]:
s6 = Series(range(3), index=['a', 'b', 'c'])
s6
Out[2]:
index의 자료형이 Index 클래스의 객체임을 확인할 수 있다.
In [3]:
s6_index = s6.index
s6_index
Out[3]:
Index 객체에 대해 인덱싱과 슬라이싱을 리스트의 경우처럼 활용할 수 있다.
In [4]:
s6_index[2]
Out[4]:
In [5]:
s6_index[1:]
Out[5]:
Index 객체는 불변(immutable) 자료형이다.
In [6]:
s6_index[1] = 'd'
색인 객체는 변경될 수 없기에 자료 구조 사이에서 안전하게 공유될 수 있다.
In [7]:
an_index = pd.Index(np.arange(3))
an_index
Out[7]:
앞서 선언된 an_index를 새로운 Series 나 DataFrame 을 생성하는 데에 사용할 수 있으며, 사용된 index가 무엇인지를 확인할 수도 있다.
In [8]:
s7= Series([1.5, -2.5, 0], index=an_index)
s7.index is an_index
Out[8]:
In [9]:
df3
Out[9]:
columns와 index 속성 모두 Index 객체이다.
In [10]:
df3.columns
Out[10]:
In [11]:
df3.index
Out[11]:
In [12]:
df3.columns[:2]
Out[12]:
In [13]:
'debt' in df3.columns
Out[13]:
In [14]:
'four' in df3.index
Out[14]:
각각의 색인은 담고 있는 데이터에 대한 정보를 취급하는 여러 가지 메서드와 속성을 가지고 있다. [표 5-3]을 참고하자.
In [15]:
s8 = Series([4.3, 9.2, 8.1, 3.9], index= ['b', 'c', 'a', 'd'])
s8
Out[15]:
reindex()
메소드를 이용하여 인덱스를 새로 지정할 수 있다.
주의: 새로 사용되는 항목이 index에 추가되면 NaN이 값으로 사용된다.
In [16]:
s9 = s8.reindex(['a', 'b', 'c', 'd', 'e', 'f'])
s9
Out[16]:
누락된 값을 지정된 값으로 채울 수도 있다.
In [17]:
s8.reindex(['a','b','c','d','e', 'f'], fill_value=0.0)
Out[17]:
In [18]:
s9 = Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
s9
Out[18]:
In [19]:
s9.reindex(range(6))
Out[19]:
In [20]:
s9.reindex(range(6), method='ffill')
Out[20]:
In [21]:
s9.reindex(range(6), method='bfill')
Out[21]:
In [22]:
data = np.arange(9).reshape(3, 3)
data
Out[22]:
In [23]:
df6 = DataFrame(data, index=['a', 'b', 'd'], columns= ['Ohio', 'Texas', 'California'])
df6
Out[23]:
In [24]:
df7 = df6.reindex(['a', 'b', 'c', 'd'])
df7
Out[24]:
In [25]:
states = ['Texas', 'Utah', 'California']
df6.reindex(columns=states)
Out[25]:
method
옵션을 이용한 보간은 행 대해서만 이루어진다.
In [26]:
df6.reindex(index=['a', 'b', 'c', 'd'], method='ffill')
Out[26]:
In [27]:
df6.reindex(index=['a', 'b', 'c', 'd'], method='bfill')
Out[27]:
In [28]:
df6.reindex(index=['a', 2, 3, 4])
Out[28]:
method='nearest'
는 인덱스가 모두 숫자인 경우에만 적용할 수 있다.
In [29]:
df6.reindex(index=['a', 'b', 'c', 'd'], method='nearest')
In [30]:
df6
Out[30]:
In [31]:
states
Out[31]:
In [32]:
df6.loc[['a', 'b', 'c', 'd'], states]
Out[32]:
In [33]:
obj = Series(np.arange(5.), index=['a', 'b', 'c', 'd', 'e'])
obj
Out[33]:
In [34]:
new_obj = obj.drop('c')
new_obj
Out[34]:
In [35]:
obj.drop(['d', 'c'])
Out[35]:
DataFrame에서는 로우와 칼럼 모두에서 값을 삭제할 수 있다.
In [36]:
df7
Out[36]:
In [37]:
df7.drop('a', axis=0)
Out[37]:
In [38]:
df7.drop('Ohio', axis=1)
Out[38]:
drop()
메소드는 기존의 자료를 건드리지 않는다.
In [39]:
df7
Out[39]:
In [40]:
data.drop('two', axis=1)
In [ ]:
data.drop(['two', 'four'], axis=1)
In [ ]:
In [ ]:
In [ ]:
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]에 다양한 방법을 정리해두었다. 나중에 살펴볼 계층적 색인을 이용하면 좀 더 다양한 방법을 사용할 수 있다.
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)
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)
In [ ]:
frame['e'].map(format)
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')
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']