0

我正在尝试为 pandas dataFrame 对象中的列分配替代值。分配替代值的条件是元素现在的值为零。

这是我的代码片段:

df = pd.DataFrame({'A': [0, 1, 2, 0, 0, 1, 1 ,0], 'B': [1, 2, 3, 4, 1, 2, 3, 4]})

for i, row in df.iterrows():
    if row['A'] == 0.0:
        df.iloc[i]['A'] = df.iloc[i-1]['A'] + df.iloc[i]['B'] - df.iloc[i-1]['B']

然而,事实证明,这些元素中的值仍然为零!以上效果为零。

这是怎么回事?

4

3 回答 3

2

下面的原始答案适用于某些输入,但并不完全正确。使用问题中的数据框测试您的代码,我发现它有效,但不能保证适用于所有数据框。这是一个不起作用的示例:

df = pd.DataFrame(np.random.randn(6,4), index=list(range(0,12,2)), columns=['A', 'B', 'C', 'D'])

此数据框将导致您的代码失败,因为索引不是您的算法所期望的 0、1、2...,而是 0、2、4、...,如index=list(range(0,12,2)).

这意味着i迭代器返回的值也将是 0, 2, 4,...,因此当您尝试将其i-1用作iloc.

简而言之,当您使用for i, row in df.iterrows():迭代数据框时,i采用您正在迭代的维度的索引值,因为它们在 dataframe 中定义。确保在循环内将它们与偏移一起使用时知道这些值是什么。


原答案:

我无法弄清楚为什么您的代码不起作用,但我可以验证它不起作用。它可能与在迭代数据帧时修改数据帧有关,因为您可以使用df.iloc[1]['A'] = 0.0在循环外部设置值而没有问题。

尝试DataFrame.at改用:

for i, row in df.iterrows():
    if row['A'] == 0.0:
        df.at[i, 'A'] = df.iloc[i-1]['A'] + df.iloc[i]['B'] - df.iloc[i-1]['B']

这对返回数据框中的最后一行没有任何作用df.iloc[i-1],因此请注意,当 A 列中的第一个值为 0.0 时。

于 2018-08-02T19:34:04.913 回答
1

关于什么:

df = pd.DataFrame({'A': [0, 1, 2, 0, 0, 1, 1 ,0], 'B': [1, 2, 3, 4, 1, 2, 3, 4]})
df['A'] = df.where(df[['A']] != 0, 
                   df['A'].shift() + df['B'] - df['B'].shift(),
                   axis=0)['A']
print(df)

     A  B
0  NaN  1
1  1.0  2
2  2.0  3
3  3.0  4
4 -3.0  1
5  1.0  2
6  1.0  3
7  2.0  4

NaN 在那里,因为在第一个元素之前没有元素

于 2018-08-02T19:07:42.353 回答
1

您正在使用chained indexing与著名的 SettingWithCopy 警告相关的内容。检查 Tom Augspurger 在现代熊猫中的 SettingWithCopy 设置。

一般来说,这意味着df['A']['B']= ...不鼓励分配表格。如果你在那里使用 loc 存取器并不重要。

如果您在代码中添加打印语句:

for i, row in df.iterrows():
    print(df)
    if row['A'] == 0.0:
        df.iloc[i]['A'] = df.iloc[i-1]['A'] + df.iloc[i]['B'] - df.iloc[i-1]['B']

你会看到奇怪的事情发生。df当且仅当列“A”的第一行为 0 时,才会修改数据框。

正如蜥蜴比尔指出的那样,您需要一个访问器。但是,请注意,Bill 的方法具有提供基于标签的访问的缺点。当拥有不同索引的数据框时,这可能不是您想要的。那么更好的解决方案是使用 loc

for i, row in df.iterrows():
    if row['A'] == 0.0:
        df.loc[df.index[i], 'A'] = df.iloc[i-1]['A'] + df.iloc[i]['B'] - df.iloc[i-1]['B']

或 iloc

    for i, row in df.iterrows():
        if row['A'] == 0.0:
            df.iloc[i, df.columns.get_loc('A')] = df.iloc[i-1]['A'] + df.iloc[i]['B'] - df.iloc[i-1]['B']

假设索引在最后一种情况下是唯一的。请注意,在设置值时会发生链式索引。

虽然这种方法有效,但它 - 通过上面的引用 - 不被鼓励!

于 2018-08-02T20:46:04.767 回答