我正在尝试为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']
但是,事实证明,这些元素中的值保持为零!以上效果为零。
这是怎么回事?
答案 0 :(得分:2)
下面的原始答案适用于某些输入,但并不完全正确。我用问题中的数据帧测试您的代码,我发现它可以工作,但不能保证它可以与所有数据帧一起工作。这是一个不起作用的示例:
df = pd.DataFrame(np.random.randn(6,4), index=list(range(0,12,2)), columns=['A', 'B', 'C', 'D'])
此数据帧将导致您的代码失败,因为索引不像算法期望的那样为0、1、2 ...,而是index=list(range(0,12,2))
定义的0、2、4,...
这意味着迭代器返回的i
的值也将是0、2、4 ...,因此,当您尝试使用i-1
作为参数时,将会得到意外的结果到iloc
。
简而言之,当您使用for i, row in df.iterrows():
遍历数据帧时,i
会采用您遍历的维度的索引值,因为它们是在数据帧中定义的< / em>。确保您知道在循环内将其与偏移量一起使用时这些值是什么。
原始答案:
我无法弄清楚为什么您的代码不起作用,但是我可以验证一下它不起作用。这可能与在迭代数据帧时修改数据帧有关,因为您可以使用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时。
答案 1 :(得分:1)
那又怎么样:
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
.....
//other codes here
}
NaN在那里,因为第一个元素之前没有元素
答案 2 :(得分:1)
您正在使用chained indexing
,它与著名的SettingWithCopy警告有关。检查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所指出的,您需要一个访问器。但是,请注意,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']
假定索引在后一种情况下是唯一的。 请注意,设置值时会发生链接索引。
尽管这种方法行得通,但是-上面的引言-不鼓励!