避免大熊猫链选择

时间:2015-03-29 20:24:14

标签: python-2.7 pandas

我正在尝试确定“最佳做法”,以便在不产生SettingWithCopyWarning的情况下执行以下操作。我正在使用python 2.7和pandas 15.2

我想要做的是选择一个数据帧,然后将此选择用作新的数据帧,而不必冒险修改原始数据帧。这是我正在做的一个例子:

import pandas as pd

def select_blue_cars(df):
    """Returns a new dataframe of blue cars"""
    return df[df['color'] == 'blue']

cars = pd.DataFrame({'color': ['blue', 'blue', 'red'], 'make': ['Ford', 'BMW', 'Ford']})
blue_cars = select_blue_cars(cars)
blue_cars['price'] = 10000

以上在当前的pandas中生成SettingWithCopyWarning,但其他行为与我想要的一样(即cars df尚未修改。)

  • 实施select_blue_cars的最佳方式是什么,以便后续代码不会触发此警告?

  • 我应该到处使用.copy()吗?

    return df[df['color'] == 'blue'].copy()
    
  • (旁白)copy()的表现如何?

最终我想链接简单的变换函数,如select_blue_cars

blue_fords = select_fords(select_blue_cars(cars))

编辑:考虑到这一点后,我认为我正在寻找一个从数据帧中选择副本而不显式调用.copy()的转换。这样我就可以编写函数来对df进行少量转换并将它们链接起来。

转置例如df.T会提供一个新的数据帧。无需拨打.copy()

df2 = df.T
df2 = df.T.copy()  # no need

看起来,在选择的情况下,此模式需要.copy()

2 个答案:

答案 0 :(得分:1)

我认为这仍然是大熊猫更令人困惑的部分之一。你实际上问的是2或3个问题,答案可能不如你想象的那么简单。因此,我将做出简化的假设,即您只需将所有内容保存在一个数据集中(如果不是,它虽然不是那么大),并给出一个简单的答案。

你想做什么(伪代码):

price = 10000 if color == blue

最简单的方法是使用numpy where()

cars['price'] = np.where( cars['color'] == 'blue', 10000, np.nan )

  color  make  price
0  blue  Ford  10000
1  blue   BMW  10000
2   red  Ford    NaN

你也可以嵌套where()所以这是非常强大而且简单的条件设置方法。您也可以使用ix/loc/iloc(尽管您需要先为'price'创建一个空列):

cars.ix[ cars.color == 'blue', 'price' ] = 10000

并简要说明链式索引警告,它主要说的是在设置值时不要试图在左侧做太多:

df[ df.y > 5 ]['x'] = df['z']

这是可以的:

df['x'] = df[ df.y > 5 ]['z']

因为链式索引的结果可能是复制而不是引用,这将导致前者失败而后者失败。您也可以使用ix/loc/iloc来解决这个问题。

答案 1 :(得分:1)

你如何绕过SettingWithCopyWarning取决于你计划保留子集的时间。如果您只想简单地查看特定颜色中的价格然后返回到整体数据框,JohnE给出的建议非常好。如果你真的想要保留子集并对其进行一系列单独的分析,那么我通常做的是使用.loc的子集并明确复制,例如:

subset = df.loc[df['condition'] > 5, :].copy()

在您的代码中,这将是:

import pandas as pd

def select_blue_cars(df):
    """Returns a new dataframe of blue cars"""
    return df.loc[df['color'] == 'blue', :].copy()

cars = pd.DataFrame({'color': ['blue', 'blue', 'red'], 'make': ['Ford', 'BMW', 'Ford']})
blue_cars = select_blue_cars(cars)
blue_cars['price'] = 10000