Pandas 소개 2

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

먼저 GongSu24를 임포트 한다.


In [1]:
from GongSu24_Pandas_Introduction_1 import *


/Users/gslee/anaconda/lib/python2.7/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)

색인(Index) 클래스

Pandas에 정의된 색인(Index) 클래스는 Series와 DataFrame 자료형의 행과 열을 구분하는 이름들의 목록을 저장하는 데에 사용된다.

Series 객체에서 사용되는 Index 객체

  • index 속성

아래와 같이 Series 객체를 생성한 후에 index를 확인해보자.


In [2]:
s6 = Series(range(3), index=['a', 'b', 'c'])
s6


Out[2]:
a    0
b    1
c    2
dtype: int64

index의 자료형이 Index 클래스의 객체임을 확인할 수 있다.


In [3]:
s6_index = s6.index
s6_index


Out[3]:
Index([u'a', u'b', u'c'], dtype='object')

Index 객체에 대해 인덱싱과 슬라이싱을 리스트의 경우처럼 활용할 수 있다.


In [4]:
s6_index[2]


Out[4]:
'c'

In [5]:
s6_index[1:]


Out[5]:
Index([u'b', u'c'], dtype='object')

Index 객체는 불변(immutable) 자료형이다.


In [6]:
s6_index[1] = 'd'


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-e3993afabe03> in <module>()
----> 1 s6_index[1] = 'd'

/Users/gslee/anaconda/lib/python2.7/site-packages/pandas/core/indexes/base.pyc in __setitem__(self, key, value)
   1618 
   1619     def __setitem__(self, key, value):
-> 1620         raise TypeError("Index does not support mutable operations")
   1621 
   1622     def __getitem__(self, key):

TypeError: Index does not support mutable operations

색인 객체는 변경될 수 없기에 자료 구조 사이에서 안전하게 공유될 수 있다.


In [7]:
an_index = pd.Index(np.arange(3))
an_index


Out[7]:
Int64Index([0, 1, 2], dtype='int64')

앞서 선언된 an_index를 새로운 Series 나 DataFrame 을 생성하는 데에 사용할 수 있으며, 사용된 index가 무엇인지를 확인할 수도 있다.


In [8]:
s7= Series([1.5, -2.5, 0], index=an_index)
s7.index is an_index


Out[8]:
True

DataFrame 객체에서 사용되는 Index 객체

  • index 속성
  • column 속성

In [9]:
df3


Out[9]:
pop state year
one 1.5 Ohio 2000
two 1.7 Ohio 2001
three 3.6 Ohio 2002
four 2.4 Nevada 2001
five 2.9 Nevada 2002

columns와 index 속성 모두 Index 객체이다.


In [10]:
df3.columns


Out[10]:
Index([u'pop', u'state', u'year'], dtype='object')

In [11]:
df3.index


Out[11]:
Index([u'one', u'two', u'three', u'four', u'five'], dtype='object')

In [12]:
df3.columns[:2]


Out[12]:
Index([u'pop', u'state'], dtype='object')

in 연산자 활용하기

in 연산자를 활용하여 index 와 columns에 사용된 행과 열의 이름의 존재여부를 확인할 수 있다.


In [13]:
'debt' in df3.columns


Out[13]:
False

In [14]:
'four' in df3.index


Out[14]:
True

각각의 색인은 담고 있는 데이터에 대한 정보를 취급하는 여러 가지 메서드와 속성을 가지고 있다. [표 5-3]을 참고하자.

Series와 DataFrame 관련 연산 및 주요 메소드

Series나 DataFrame 형식으로 저장된 데이터를 다루는 주요 연산 및 기능을 설명한다.

재색인(reindex) 메소드

reindex() 메소드는 지정된 색인을 사용해서 새로운 Series나 DataFrame 객체를 생성한다.

Series의 경우 재색인


In [15]:
s8 = Series([4.3, 9.2, 8.1, 3.9], index= ['b', 'c', 'a', 'd'])
s8


Out[15]:
b    4.3
c    9.2
a    8.1
d    3.9
dtype: float64

reindex() 메소드를 이용하여 인덱스를 새로 지정할 수 있다.

주의: 새로 사용되는 항목이 index에 추가되면 NaN이 값으로 사용된다.


In [16]:
s9 = s8.reindex(['a', 'b', 'c', 'd', 'e', 'f'])
s9


Out[16]:
a    8.1
b    4.3
c    9.2
d    3.9
e    NaN
f    NaN
dtype: float64

누락된 값을 지정된 값으로 채울 수도 있다.


In [17]:
s8.reindex(['a','b','c','d','e', 'f'], fill_value=0.0)


Out[17]:
a    8.1
b    4.3
c    9.2
d    3.9
e    0.0
f    0.0
dtype: float64

method 옵션

시계열(time series) 등과 데이터 처럼 어떠 순서에 따라 정렬된 데이터를 재색인할 때 보간법을 이용하여 누락된 값들을 채워 넣어야 하는 경우가 있다. 이런 경우 method 옵션을 이용하며, ffill, bfill, nearest 등을 옵션값으로 활용한다.


In [18]:
s9 = Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
s9


Out[18]:
0      blue
2    purple
4    yellow
dtype: object

In [19]:
s9.reindex(range(6))


Out[19]:
0      blue
1       NaN
2    purple
3       NaN
4    yellow
5       NaN
dtype: object

In [20]:
s9.reindex(range(6), method='ffill')


Out[20]:
0      blue
1      blue
2    purple
3    purple
4    yellow
5    yellow
dtype: object

In [21]:
s9.reindex(range(6), method='bfill')


Out[21]:
0      blue
1    purple
2    purple
3    yellow
4    yellow
5       NaN
dtype: object

DataFrame의 경우 재색인

행과 열에 대해 모두 사용이 가능하다.


In [22]:
data = np.arange(9).reshape(3, 3)
data


Out[22]:
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

In [23]:
df6 = DataFrame(data, index=['a', 'b', 'd'], columns= ['Ohio', 'Texas', 'California'])
df6


Out[23]:
Ohio Texas California
a 0 1 2
b 3 4 5
d 6 7 8
  • index 속성의 재색인은 Series의 경우와 동일하다.

In [24]:
df7 = df6.reindex(['a', 'b', 'c', 'd'])
df7


Out[24]:
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
  • columns 속성의 재색인은 키워드(예약어)를 사용한다.

In [25]:
states = ['Texas', 'Utah', 'California']
df6.reindex(columns=states)


Out[25]:
Texas Utah California
a 1 NaN 2
b 4 NaN 5
d 7 NaN 8
  • method 옵션을 이용한 보간은 행 대해서만 이루어진다.

In [26]:
df6.reindex(index=['a', 'b', 'c', 'd'], method='ffill')


Out[26]:
Ohio Texas California
a 0 1 2
b 3 4 5
c 3 4 5
d 6 7 8

In [27]:
df6.reindex(index=['a', 'b', 'c', 'd'], method='bfill')


Out[27]:
Ohio Texas California
a 0 1 2
b 3 4 5
c 6 7 8
d 6 7 8

In [28]:
df6.reindex(index=['a', 2, 3, 4])


Out[28]:
Ohio Texas California
a 0.0 1.0 2.0
2 NaN NaN NaN
3 NaN NaN NaN
4 NaN NaN NaN

method='nearest'는 인덱스가 모두 숫자인 경우에만 적용할 수 있다.


In [29]:
df6.reindex(index=['a', 'b', 'c', 'd'], method='nearest')


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-29-0da7248ac167> in <module>()
----> 1 df6.reindex(index=['a', 'b', 'c', 'd'], method='nearest')

/Users/gslee/anaconda/lib/python2.7/site-packages/pandas/core/frame.pyc in reindex(self, index, columns, **kwargs)
   2829     def reindex(self, index=None, columns=None, **kwargs):
   2830         return super(DataFrame, self).reindex(index=index, columns=columns,
-> 2831                                               **kwargs)
   2832 
   2833     @Appender(_shared_docs['reindex_axis'] % _shared_doc_kwargs)

/Users/gslee/anaconda/lib/python2.7/site-packages/pandas/core/generic.pyc in reindex(self, *args, **kwargs)
   2402         # perform the reindex on the axes
   2403         return self._reindex_axes(axes, level, limit, tolerance, method,
-> 2404                                   fill_value, copy).__finalize__(self)
   2405 
   2406     def _reindex_axes(self, axes, level, limit, tolerance, method, fill_value,

/Users/gslee/anaconda/lib/python2.7/site-packages/pandas/core/frame.pyc in _reindex_axes(self, axes, level, limit, tolerance, method, fill_value, copy)
   2775         if index is not None:
   2776             frame = frame._reindex_index(index, method, copy, level,
-> 2777                                          fill_value, limit, tolerance)
   2778 
   2779         return frame

/Users/gslee/anaconda/lib/python2.7/site-packages/pandas/core/frame.pyc in _reindex_index(self, new_index, method, copy, level, fill_value, limit, tolerance)
   2783         new_index, indexer = self.index.reindex(new_index, method=method,
   2784                                                 level=level, limit=limit,
-> 2785                                                 tolerance=tolerance)
   2786         return self._reindex_with_indexers({0: [new_index, indexer]},
   2787                                            copy=copy, fill_value=fill_value,

/Users/gslee/anaconda/lib/python2.7/site-packages/pandas/core/indexes/base.pyc in reindex(self, target, method, level, limit, tolerance)
   2831                     indexer = self.get_indexer(target, method=method,
   2832                                                limit=limit,
-> 2833                                                tolerance=tolerance)
   2834                 else:
   2835                     if method is not None or limit is not None:

/Users/gslee/anaconda/lib/python2.7/site-packages/pandas/core/indexes/base.pyc in get_indexer(self, target, method, limit, tolerance)
   2538             indexer = self._get_fill_indexer(target, method, limit, tolerance)
   2539         elif method == 'nearest':
-> 2540             indexer = self._get_nearest_indexer(target, limit, tolerance)
   2541         else:
   2542             if tolerance is not None:

/Users/gslee/anaconda/lib/python2.7/site-packages/pandas/core/indexes/base.pyc in _get_nearest_indexer(self, target, limit, tolerance)
   2608 
   2609         target = np.asarray(target)
-> 2610         left_distances = abs(self.values[left_indexer] - target)
   2611         right_distances = abs(self.values[right_indexer] - target)
   2612 

TypeError: unsupported operand type(s) for -: 'str' and 'str'

주의

reindex는 기존 자료를 변경하지 않는다.


In [30]:
df6


Out[30]:
Ohio Texas California
a 0 1 2
b 3 4 5
d 6 7 8

loc 메소드를 이용한 재색인

loc 메소드를 이용하여 재색인이 가능하다.


In [31]:
states


Out[31]:
['Texas', 'Utah', 'California']

In [32]:
df6.loc[['a', 'b', 'c', 'd'], states]


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

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']