熊猫高级索引分配

时间:2012-07-13 12:00:43

标签: python pandas

Pandas中的

(v0.8.0)DataFrame我想用另一个列覆盖一片列。

以下代码会引发列出的错误。

实现这一目标的有效替代方法是什么?

df = DataFrame({'a' : range(0,7),
'b' : np.random.randn(7),
'c' : np.random.randn(7),
'd' : np.random.randn(7),
'e' : np.random.randn(7),
'f' : np.random.randn(7),
'g' : np.random.randn(7)})

# overwrite cols
df.ix[:,'b':'d'] = df.ix[:, 'e':'g']

Traceback (most recent call last):
File "C:\Python27\lib\site-packages\pandas\core\indexing.py", line 68, in __setitem__
self._setitem_with_indexer(indexer, value)
File "C:\Python27\lib\site-packages\pandas\core\indexing.py", line 98, in   _setitem_with_indexer
raise ValueError('Setting mixed-type DataFrames with '
ValueError: Setting mixed-type DataFrames with array/DataFrame pieces not yet supported

被修改

作为一种排列,我怎样才能指定要设置的行的子集

df.ix[df['a'] < 3, 'b':'d'] = df.ix[df['a'] < 3, 'e':'g']

1 个答案:

答案 0 :(得分:6)

问题是使用.ix[]会返回一个视图,指向DataFrame的该子集的实际内存对象,而不是从其内容构成的新DataFrame。

改为使用

# The left-hand-side does not use .ix, since we're assigning into it.
df[['b','c']] = df.ix[:,'e':'f'].copy()

请注意,如果您打算使用.copy()进行切片,则需要.ix,否则会将列'b'和'c'设置为内存中的相同对象作为列'e'和'f',这看起来不像你想要做的那样。

或者,为了避免担心复制你,你可以这样做:

df[['b','c']] = df[['e','f']]

如果索引的便利性对您很重要,那么模拟此效果的一种方法是编写自己的函数:

def col_range(df, col1, col2): 
    return list(dfrm.ix[dfrm.index.values[0],col1:col2].index)

现在您可以执行以下操作:

df[col_range(df,'b','d')] = df.ix[:,'e':'g'].copy()

注意:在col_range的定义中,我使用了第一个索引来选择数据帧的第一行。我这样做是因为仅仅为了选择一系列列来查看整个数据框看起来很浪费,而一行可能无关紧要。由于以这种方式切片会生成一个Series,因此提取列的方法是实际获取索引,然后将它们作为列表返回。

添加了额外的行切片请求:

要在分配中指定一组行,您可以使用.ix,但是您需要在右侧指定一个值矩阵。在右侧具有子DataFrame的结构将导致问题。

df.ix[0:4,col_range(df,'b','d')] = df.ix[0:4,'e':'g'].values

您可以将[0:4]替换为[df.index.values[i]:df.index.values[j]][df.index.values[i] for i in range(N)],或者使用[df['a']>5]等逻辑值替换为“a”列超过5的行,例。

逻辑索引示例的完整切片,您希望列'a'大于5且列'e'小于10,可能如下所示:

import numpy as np
my_rows = np.logical_and(df['a'] > 5), df['e'] < 10)
df.ix[my_rows,col_range(df,'b','d')] = df.ix[my_rows,'e':'g'].values

在许多情况下,您不需要使用左侧的.ix(我建议不要使用它,因为它仅适用于某些情况而不适用于其他情况)。例如,像:

df["A"] = np.repeat(False, len(df))
df["A"][df["B"] > 0] = True

将按原样工作,不需要特殊的.ix来识别条件为真的行。当右边的东西很复杂时,左边似乎需要.ix