작성자: admin 작성일시: 2016-07-08 23:58:23 조회수: 1377 다운로드: 87
카테고리: Python 태그목록:

Pandas 고급 인덱싱

pandas는 numpy 행렬과 같이 comma를 사용한 복수 인덱싱을 지원하기 위해 다음과 같은 특별한 인덱서 속성을 제공한다.

  • ix : 라벨과 숫자를 동시에 지원하는 복수 인덱싱
  • loc : 라벨 기반의 복수 인덱싱
  • iloc : 숫자 기반의 복수 인덱싱

ix 인덱서

  • 행(Row)/열(Column) 양쪽에서 라벨 인덱싱, 숫자 인덱싱, 불리언 인덱싱(행만) 동시 가능
    • ,(comma)를 사용한 복수 인덱싱
    • 열(column)도 라벨이 아닌 숫자 인덱싱 가능
    • 열(column)도 라벨 슬라이싱(label slicing) 가능
    • ,(comma)를 사용하지 않고 단일 인덱싱을 하는 경우에는 행(row) 인덱싱으로 인식
    • 인덱싱으로 행이나 열을 업데이트하거나 새로 생성 가능
In [43]:
data = {
    'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],
    'year': [2000, 2001, 2002, 2001, 2002],
    'pop': [1.5, 1.7, 3.6, 2.4, 2.9]
}
In [44]:
df = pd.DataFrame(data)
df
Out[44]:
pop state year
0 1.5 Ohio 2000
1 1.7 Ohio 2001
2 3.6 Ohio 2002
3 2.4 Nevada 2001
4 2.9 Nevada 2002
In [45]:
# 순차적 indexing 과 동일
df.ix[1:3, ["state", "pop"]]
Out[45]:
state pop
1 Ohio 1.7
2 Ohio 3.6
3 Nevada 2.4
In [46]:
df2 = pd.DataFrame(data, 
                   columns=['year', 'state', 'pop'],
                   index=['one', 'two', 'three', 'four', 'five'])
df2
Out[46]:
year state pop
one 2000 Ohio 1.5
two 2001 Ohio 1.7
three 2002 Ohio 3.6
four 2001 Nevada 2.4
five 2002 Nevada 2.9
In [47]:
# , 이용
df2.ix[["two", "three"], ["state", "pop"]]
Out[47]:
state pop
two Ohio 1.7
three Ohio 3.6
In [48]:
# column에도 integer 기반 indexing 가능
df2.ix[["two", "three"], :2]
Out[48]:
year state
two 2001 Ohio
three 2002 Ohio
In [49]:
# column에도 Label Slicing 가능
df2.ix[["two", "three"], "state":"pop"]
Out[49]:
state pop
two Ohio 1.7
three Ohio 3.6
In [50]:
# `:` 사용
df2.ix[:, ["state", "pop"]]
Out[50]:
state pop
one Ohio 1.5
two Ohio 1.7
three Ohio 3.6
four Nevada 2.4
five Nevada 2.9
In [51]:
# `:` 사용
df2.ix[["two", "three"], :]
Out[51]:
year state pop
two 2001 Ohio 1.7
three 2002 Ohio 3.6
In [52]:
# ,(comma)를 사용하지 않는 경우에는 행(row) 인덱싱
df2.ix["two"]
Out[52]:
year     2001
state    Ohio
pop       1.7
Name: two, dtype: object
In [53]:
# df2.ix["year"] 는 사용 불가
df2.ix[:, "year"]
Out[53]:
one      2000
two      2001
three    2002
four     2001
five     2002
Name: year, dtype: int64

Index Label이 없는 경우의 주의점

  • Label이 지정되지 않는 경우에는 integer slicing을 label slicing으로 간주하여 마지막 값을 포함한다
In [54]:
df = pd.DataFrame(np.random.randn(5, 3))
df
Out[54]:
0 1 2
0 -0.265145 -0.172922 -1.883501
1 1.607957 1.145302 -0.483584
2 1.019404 -0.985868 -1.244956
3 1.923862 -0.442951 1.545524
4 -1.918436 -0.994918 -0.408052
In [55]:
df.columns = ["c1", "c2", "c3"]
df.ix[0:2, 1:2]
Out[55]:
c2
0 -0.172922
1 1.145302
2 -0.985868

loc 인덱서

  • 라벨 기준 인덱싱

    • 숫자가 오더라도 라벨로 인식한다.
    • 라벨 리스트 가능
    • 라벨 슬라이싱 가능
    • 불리언 배열 가능

iloc 인덱서

  • 숫자 기준 인덱싱

    • 문자열 라벨은 불가
    • 숫자 리스트 가능
    • 숫자 슬라이싱 가능
    • 불리언 배열 가능
In [56]:
np.random.seed(1)
df = pd.DataFrame(np.random.randint(1, 11, size=(4,3)), 
                  columns=["A", "B", "C"], index=["a", "b", "c", "d"])
df
Out[56]:
A B C
a 6 9 10
b 6 1 1
c 2 8 7
d 10 3 5
In [57]:
df.ix[["a", "c"], "B":"C"]
Out[57]:
B C
a 9 10
c 8 7
In [58]:
df.ix[[0, 2], 1:3]
Out[58]:
B C
a 9 10
c 8 7
In [59]:
df.loc[["a", "c"], "B":"C"]
Out[59]:
B C
a 9 10
c 8 7
In [61]:
# ,(comma)를 사용하지 않는 경우에는 행(row) 인덱싱
df.ix["a"]
Out[61]:
A     6
B     9
C    10
Name: a, dtype: int64
In [63]:
# df.ix["B"] 는 사용 불가
df.ix[:, "B"]
Out[63]:
a    9
b    1
c    8
d    3
Name: B, dtype: int64
In [64]:
df.loc[2:4, 1:3]

TypeErrorTraceback (most recent call last)
<ipython-input-64-5f06278145c0> in <module>()
----> 1 df.loc[2:4, 1:3]

/home/dockeruser/anaconda2/lib/python2.7/site-packages/pandas/core/indexing.pyc in __getitem__(self, key)
   1307 
   1308         if type(key) is tuple:
-> 1309             return self._getitem_tuple(key)
   1310         else:
   1311             return self._getitem_axis(key, axis=0)

/home/dockeruser/anaconda2/lib/python2.7/site-packages/pandas/core/indexing.pyc in _getitem_tuple(self, tup)
    813                 continue
    814 
--> 815             retval = getattr(retval, self.name)._getitem_axis(key, axis=i)
    816 
    817         return retval

/home/dockeruser/anaconda2/lib/python2.7/site-packages/pandas/core/indexing.pyc in _getitem_axis(self, key, axis)
   1450         if isinstance(key, slice):
   1451             self._has_valid_type(key, axis)
-> 1452             return self._get_slice_axis(key, axis=axis)
   1453         elif is_bool_indexer(key):
   1454             return self._getbool_axis(key, axis=axis)

/home/dockeruser/anaconda2/lib/python2.7/site-packages/pandas/core/indexing.pyc in _get_slice_axis(self, slice_obj, axis)
   1331         labels = obj._get_axis(axis)
   1332         indexer = labels.slice_indexer(slice_obj.start, slice_obj.stop,
-> 1333                                        slice_obj.step, kind=self.name)
   1334 
   1335         if isinstance(indexer, slice):

/home/dockeruser/anaconda2/lib/python2.7/site-packages/pandas/indexes/base.pyc in slice_indexer(self, start, end, step, kind)
   2960         """
   2961         start_slice, end_slice = self.slice_locs(start, end, step=step,
-> 2962                                                  kind=kind)
   2963 
   2964         # return a slice

/home/dockeruser/anaconda2/lib/python2.7/site-packages/pandas/indexes/base.pyc in slice_locs(self, start, end, step, kind)
   3139         start_slice = None
   3140         if start is not None:
-> 3141             start_slice = self.get_slice_bound(start, 'left', kind)
   3142         if start_slice is None:
   3143             start_slice = 0

/home/dockeruser/anaconda2/lib/python2.7/site-packages/pandas/indexes/base.pyc in get_slice_bound(self, label, side, kind)
   3078         # For datetime indices label may be a string that has to be converted
   3079         # to datetime boundary according to its resolution.
-> 3080         label = self._maybe_cast_slice_bound(label, side, kind)
   3081 
   3082         # we need to look up the label

/home/dockeruser/anaconda2/lib/python2.7/site-packages/pandas/indexes/base.pyc in _maybe_cast_slice_bound(self, label, side, kind)
   3036         # this is rejected (generally .loc gets you here)
   3037         elif is_integer(label):
-> 3038             self._invalid_indexer('slice', label)
   3039 
   3040         return label

/home/dockeruser/anaconda2/lib/python2.7/site-packages/pandas/indexes/base.pyc in _invalid_indexer(self, form, key)
   1252                         "indexers [{key}] of {kind}".format(
   1253                             form=form, klass=type(self), key=key,
-> 1254                             kind=type(key)))
   1255 
   1256     def get_duplicates(self):

TypeError: cannot do slice indexing on <class 'pandas.indexes.base.Index'> with these indexers [2] of <type 'int'>
In [65]:
df.iloc[2:4, 1:3]
Out[65]:
B C
c 8 7
d 3 5
In [66]:
df.iloc[["a", "c"], "B":"C"]

TypeErrorTraceback (most recent call last)
<ipython-input-66-25cc466bce07> in <module>()
----> 1 df.iloc[["a", "c"], "B":"C"]

/home/dockeruser/anaconda2/lib/python2.7/site-packages/pandas/core/indexing.pyc in __getitem__(self, key)
   1307 
   1308         if type(key) is tuple:
-> 1309             return self._getitem_tuple(key)
   1310         else:
   1311             return self._getitem_axis(key, axis=0)

/home/dockeruser/anaconda2/lib/python2.7/site-packages/pandas/core/indexing.pyc in _getitem_tuple(self, tup)
   1557     def _getitem_tuple(self, tup):
   1558 
-> 1559         self._has_valid_tuple(tup)
   1560         try:
   1561             return self._getitem_lowerdim(tup)

/home/dockeruser/anaconda2/lib/python2.7/site-packages/pandas/core/indexing.pyc in _has_valid_tuple(self, key)
    148             if i >= self.obj.ndim:
    149                 raise IndexingError('Too many indexers')
--> 150             if not self._has_valid_type(k, i):
    151                 raise ValueError("Location based indexing can only have [%s] "
    152                                  "types" % self._valid_types)

/home/dockeruser/anaconda2/lib/python2.7/site-packages/pandas/core/indexing.pyc in _has_valid_type(self, key, axis)
   1527             return self._is_valid_integer(key, axis)
   1528         elif is_list_like_indexer(key):
-> 1529             return self._is_valid_list_like(key, axis)
   1530         return False
   1531 

/home/dockeruser/anaconda2/lib/python2.7/site-packages/pandas/core/indexing.pyc in _is_valid_list_like(self, key, axis)
   1550         ax = self.obj._get_axis(axis)
   1551         l = len(ax)
-> 1552         if len(arr) and (arr.max() >= l or arr.min() < -l):
   1553             raise IndexError("positional indexers are out-of-bounds")
   1554 

/home/dockeruser/anaconda2/lib/python2.7/site-packages/numpy/core/_methods.pyc in _amax(a, axis, out, keepdims)
     24 # small reductions
     25 def _amax(a, axis=None, out=None, keepdims=False):
---> 26     return umr_maximum(a, axis, None, out, keepdims)
     27 
     28 def _amin(a, axis=None, out=None, keepdims=False):

TypeError: cannot perform reduce with flexible type

연습 문제 1

  1. 모든 행과 열에 label을 주어 5 x 5 이상의 크기를 가지는 DataFrame을 만든다.
  2. 10가지 이상의 방법으로 특정한 행과 열을 선택한다.

데이터 프레임의 행/열 합계

열 합계

In [77]:
np.random.seed(1)
df = pd.DataFrame(np.random.randint(10, size=(4, 8)))
df
Out[77]:
0 1 2 3 4 5 6 7
0 5 8 9 5 0 0 1 7
1 6 9 2 4 5 2 4 2
2 4 7 7 9 1 7 0 6
3 9 9 7 6 9 1 0 1
In [78]:
df.sum(axis=1)
Out[78]:
0    35
1    34
2    41
3    42
dtype: int64
In [79]:
df["Sum"] = df.sum(axis=1)
df
Out[79]:
0 1 2 3 4 5 6 7 Sum
0 5 8 9 5 0 0 1 7 35
1 6 9 2 4 5 2 4 2 34
2 4 7 7 9 1 7 0 6 41
3 9 9 7 6 9 1 0 1 42

행 합계

In [80]:
df.sum()
Out[80]:
0       24
1       33
2       25
3       24
4       15
5       10
6        5
7       16
Sum    152
dtype: int64
In [81]:
df.ix['Total'] = df.sum()
df
Out[81]:
0 1 2 3 4 5 6 7 Sum
0 5 8 9 5 0 0 1 7 35
1 6 9 2 4 5 2 4 2 34
2 4 7 7 9 1 7 0 6 41
3 9 9 7 6 9 1 0 1 42
Total 24 33 25 24 15 10 5 16 152

질문/덧글

label 미지정시 than*** 2016년 7월 19일 5:40 오후

Label이 지정되지 않는 경우에는 integer slicing을 label slicing으로 간주하여 마지막 값을 포함한다

df.columns = ["c1", "c2", "c3"]
df.ix[0:2, 1:2]

이렇게 코딩을 한 경우 마지막값을 포함하려면
row는 0,1,2 <-- 이렇게 표기되고
column은 1,2 <-- 이렇게 표기되는게 맞는거같은데

column의 경우 마지막값인 2만 나오고 1은 출력되지 않는데 제가 무얼 놓치고 있는건가요?

답변: label 미지정시 관리자 2016년 7월 19일 9:38 오후

row index 의 경우에는 인덱스가 라벨인지 정수인지 알 수 없기 때문에 라벨로 가정하여 0, 1, 2 행이 표시됩니다.
column index 의 경우에는 라벨일 아니라 정수라는 것이 명확하므로 하나만 나오게 됩니다.