将替代值分配给 pandas dataFrame 以其值为条件
assigning an alternative value to pandas dataFrame conditional on its value
我正在尝试为 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']
然而,事实证明,这些元素中的值仍然为零!以上的效果为零。
怎么回事?
怎么样:
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 在那里,因为第一个元素之前没有元素
下面的原始答案适用于某些输入,但并不完全正确。使用您问题中的数据框测试您的代码,我发现它可以工作,但不能保证它适用于所有数据框。这是一个不起作用的示例:
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...,如 [=12] 所定义=].
这意味着迭代器返回的 i
的值也将是 0, 2, 4,..., 所以当您尝试将 i-1
用作iloc
.
的参数
简而言之,当您使用 for i, row in df.iterrows():
遍历数据框时,i
会采用您正在遍历的维度的索引值 正如它们的定义在数据框中。在循环内使用带有偏移量的值时,请确保您知道这些值是什么。
原回答:
我无法弄清楚为什么您的代码不起作用,但我可以验证它是否不起作用。它可能与在迭代数据帧时修改数据帧有关,因为您可以使用 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 时。
您正在使用与著名的 SettingWithCopy 警告相关的 chained indexing
。检查 Tom Augspurger modern pandas 中的 SettingWithCopy 设置。
一般来说,这意味着不鼓励使用 df['A']['B']= ...
形式的赋值。在那里使用 loc acessor 并不重要。
如果您在代码中添加打印语句:
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']
你看到奇怪的事情发生了。当且仅当第一行 'A' 列为 0 时,数据帧 df
才会被修改。
正如 Bill the Lizard 所指出的,您需要一个访问器。但是,请注意 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']
假设索引在最后一种情况下是唯一的。
请注意,链接索引发生在设置值时。
虽然这种方法有效,但根据上面的引述,不鼓励这样做!
我正在尝试为 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']
然而,事实证明,这些元素中的值仍然为零!以上的效果为零。
怎么回事?
怎么样:
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 在那里,因为第一个元素之前没有元素
下面的原始答案适用于某些输入,但并不完全正确。使用您问题中的数据框测试您的代码,我发现它可以工作,但不能保证它适用于所有数据框。这是一个不起作用的示例:
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...,如 [=12] 所定义=].
这意味着迭代器返回的 i
的值也将是 0, 2, 4,..., 所以当您尝试将 i-1
用作iloc
.
简而言之,当您使用 for i, row in df.iterrows():
遍历数据框时,i
会采用您正在遍历的维度的索引值 正如它们的定义在数据框中。在循环内使用带有偏移量的值时,请确保您知道这些值是什么。
原回答:
我无法弄清楚为什么您的代码不起作用,但我可以验证它是否不起作用。它可能与在迭代数据帧时修改数据帧有关,因为您可以使用 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 时。
您正在使用与著名的 SettingWithCopy 警告相关的 chained indexing
。检查 Tom Augspurger modern pandas 中的 SettingWithCopy 设置。
一般来说,这意味着不鼓励使用 df['A']['B']= ...
形式的赋值。在那里使用 loc acessor 并不重要。
如果您在代码中添加打印语句:
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']
你看到奇怪的事情发生了。当且仅当第一行 'A' 列为 0 时,数据帧 df
才会被修改。
正如 Bill the Lizard 所指出的,您需要一个访问器。但是,请注意 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']
假设索引在最后一种情况下是唯一的。 请注意,链接索引发生在设置值时。
虽然这种方法有效,但根据上面的引述,不鼓励这样做!