了解Pandas 0.8.1(和0.11)中的索引问题

时间:2013-07-23 20:26:40

标签: python indexing pandas

以下是来自IPython会话的示例,其中对Pandas DataFrame进行了一些简单的索引和分配,有些在看起来很简单时无效:

In [652]: dfrm = pandas.DataFrame(np.random.rand(10,3), columns=['A', 'B', 'C'])

In [653]: dfrm
Out[653]:
          A         B         C
0  0.777147  0.558404  0.424222
1  0.906354  0.111197  0.492625
2  0.011354  0.468661  0.056303
3  0.118818  0.117526  0.649210
4  0.746045  0.583369  0.962173
5  0.374871  0.285712  0.868599
6  0.223596  0.963223  0.012154
7  0.969879  0.043160  0.891143
8  0.527701  0.992965  0.073797
9  0.553854  0.969303  0.523098

In [654]: dfrm['A'][dfrm.A > 0.5] = [1,2,3,4,5,6]

In [655]: dfrm
Out[655]:
          A         B         C
0  1.000000  0.558404  0.424222
1  2.000000  0.111197  0.492625
2  0.011354  0.468661  0.056303
3  0.118818  0.117526  0.649210
4  3.000000  0.583369  0.962173
5  0.374871  0.285712  0.868599
6  0.223596  0.963223  0.012154
7  4.000000  0.043160  0.891143
8  5.000000  0.992965  0.073797
9  6.000000  0.969303  0.523098

In [656]: dfrm[['B','C']][dfrm.A > 0.5] = 100*np.random.rand(6,2)

In [657]: dfrm
Out[657]:
          A         B         C
0  1.000000  0.558404  0.424222
1  2.000000  0.111197  0.492625
2  0.011354  0.468661  0.056303
3  0.118818  0.117526  0.649210
4  3.000000  0.583369  0.962173
5  0.374871  0.285712  0.868599
6  0.223596  0.963223  0.012154
7  4.000000  0.043160  0.891143
8  5.000000  0.992965  0.073797
9  6.000000  0.969303  0.523098

In [658]: dfrm[dfrm.A > 0.5] = 100*np.random.rand(6,3)

In [659]: dfrm
Out[659]:
           A          B          C
0  27.738118  18.812116  46.369840
1  35.335223  58.365611   7.773464
2   0.011354   0.468661   0.056303
3   0.118818   0.117526   0.649210
4  97.439481  98.621074  69.816171
5   0.374871   0.285712   0.868599
6   0.223596   0.963223   0.012154
7  53.609637  30.952762  81.379502
8  68.473117  16.261694  91.092718
9  82.253724  94.979991  72.571951

In [660]: dfrm[dfrm.A > 0.5] = 0.5*dfrm[dfrm.A > 0.5]
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-660-35fb8e212806> in <module>()
----> 1 dfrm[dfrm.A > 0.5] = 0.5*dfrm[dfrm.A > 0.5]

/opt/epd/7.3-2_pandas0.8.1/lib/python2.7/site-packages/pandas/core/frame.pyc in __setitem__(self, key, value)
   1707             self._boolean_set(key, value)
   1708         elif isinstance(key, (np.ndarray, list)):
-> 1709             return self._set_item_multiple(key, value)
   1710         else:
   1711             # set column

/opt/epd/7.3-2_pandas0.8.1/lib/python2.7/site-packages/pandas/core/frame.pyc in _set_item_multiple(self, keys, value)
   1728     def _set_item_multiple(self, keys, value):
   1729         if isinstance(value, DataFrame):
-> 1730             assert(len(value.columns) == len(keys))
   1731             for k1, k2 in zip(keys, value.columns):
   1732                 self[k1] = value[k2]

AssertionError:

有人可以解释为什么有些(但不是全部)这些工作,以及为什么最后一个实际上会导致错误?

更新

我们已经安装了Pandas 0.11,但它不是开发的默认版本,所以它现在对我来说只是一个沙盒类的东西。但即使我在0.11中重复这个例子,我看到相同的赋值问题,除了最后一个例子现在正常工作没有错误。但是关于如何调用原始DataFrame的__setitem__的约定的混乱仍然存在:

Python 2.7.3 |EPD 7.3-2 (64-bit)| (default, Apr 11 2012, 17:52:16)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-44)] on linux2
Type "credits", "demo" or "enthought" for more information.
Hello
>>> import pandas
>>> pandas.__version__
'0.11.0'
>>> dfrm = pandas.DataFrame(np.random.rand(10,3), columns=['A', 'B', 'C'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'np' is not defined
>>> import numpy as np
>>> dfrm = pandas.DataFrame(np.random.rand(10,3), columns=['A', 'B', 'C'])
>>> dfrm
          A         B         C
0  0.745516  0.062613  0.147684
1  0.369141  0.447022  0.114963
2  0.820178  0.946806  0.687971
3  0.771971  0.934799  0.633633
4  0.828249  0.065587  0.848788
5  0.433796  0.740885  0.160140
6  0.663891  0.753134  0.849269
7  0.647054  0.962267  0.453865
8  0.345706  0.030634  0.058697
9  0.994135  0.990536  0.436903
>>> dfrm[dfrm.A > 0.5]
          A         B         C
0  0.745516  0.062613  0.147684
2  0.820178  0.946806  0.687971
3  0.771971  0.934799  0.633633
4  0.828249  0.065587  0.848788
6  0.663891  0.753134  0.849269
7  0.647054  0.962267  0.453865
9  0.994135  0.990536  0.436903
>>> len(dfrm[dfrm.A > 0.5])
7
>>> dfrm['A'][dfrm.A > 0.5] = [1,2,3,4,5,6,7]
>>> dfrm
          A         B         C
0  1.000000  0.062613  0.147684
1  0.369141  0.447022  0.114963
2  2.000000  0.946806  0.687971
3  3.000000  0.934799  0.633633
4  4.000000  0.065587  0.848788
5  0.433796  0.740885  0.160140
6  5.000000  0.753134  0.849269
7  6.000000  0.962267  0.453865
8  0.345706  0.030634  0.058697
9  7.000000  0.990536  0.436903
>>> dfrm[['B','C']][dfrm.A > 0.5] = 100*np.random.rand(7,2)
>>> dfrm
          A         B         C
0  1.000000  0.062613  0.147684
1  0.369141  0.447022  0.114963
2  2.000000  0.946806  0.687971
3  3.000000  0.934799  0.633633
4  4.000000  0.065587  0.848788
5  0.433796  0.740885  0.160140
6  5.000000  0.753134  0.849269
7  6.000000  0.962267  0.453865
8  0.345706  0.030634  0.058697
9  7.000000  0.990536  0.436903
>>> dfrm[dfrm.A > 0.5] = 0.5*dfrm[dfrm.A > 0.5]
>>> dfrm
          A         B         C
0  0.500000  0.031306  0.073842
1  0.369141  0.447022  0.114963
2  1.000000  0.473403  0.343985
3  1.500000  0.467400  0.316816
4  2.000000  0.032794  0.424394
5  0.433796  0.740885  0.160140
6  2.500000  0.376567  0.424635
7  3.000000  0.481133  0.226933
8  0.345706  0.030634  0.058697
9  3.500000  0.495268  0.218452
>>>

第二次更新:

这是另一个超级意想不到的行为:

In [681]: id(dfrm.A)
Out[681]: 298480536

In [682]: id(dfrm.A)
Out[682]: 298480536

In [683]: id(dfrm.A)
Out[683]: 298480536

In [684]: id(dfrm['A'])
Out[684]: 298480536

In [685]: id(dfrm['A'])
Out[685]: 298480536

In [686]: id(dfrm['A'])
Out[686]: 298480536

In [687]: id(dfrm[['A']])
Out[687]: 281536912

In [688]: id(dfrm[['A']])
Out[688]: 281535824

In [689]: id(dfrm[['A']])
Out[689]: 281536336

1 个答案:

答案 0 :(得分:1)

根据具体情况分配两个或多个getitems / slices(链接)可能会也可能不会... 所以你应该避免这样做!!你应该重写一次通过。

在0.11(可能在此之前)中有相当多的工作来清除这种行为......现在pandas重载了这些分配,如果它是view or a copy if 你是在一次通过这样做的,一般来说你应该这样做 例如:

dfrm.loc[dfrm.A > 0.5, 'A'] = [1, 2, 3, 4, 5, 6]

dfrm.loc[[dfrm.A > 0.5], ['B','C']] = 100 * np.random.rand(6, 2)

另外,通常的好做法是指定您按标签索引(使用loc):

dfrm.loc[dfrm.A > 0.5] = 100 * np.random.rand(6, 3)

你也可以考虑重写:

dfrm.loc[dfrm.A > 0.5] = 0.5 * dfrm.loc[dfrm.A > 0.5]

dfrm.loc[dfrm.A > 0.5] *= 0.5

这是0.8.1中的一个令人惊讶的错误(但似乎在以后的版本中得到修复),也许一个解决方法(如果以上不起作用)是首先设置花式索引({{1} })然后使用它进行分配...并被迫使用df_A_gt_half = dfrm.A > 0.5而不是ix