逐行迭代时更新pandas中的数据框架

我有一个熊猫数据帧,看起来像这样(它非常大)

           date      exer exp     ifor         mat
1092  2014-03-17  American   M  528.205  2014-04-19
1093  2014-03-17  American   M  528.205  2014-04-19
1094  2014-03-17  American   M  528.205  2014-04-19
1095  2014-03-17  American   M  528.205  2014-04-19
1096  2014-03-17  American   M  528.205  2014-05-17

现在我想逐行迭代,当我遍历每一行时,ifor的值 在每一行中可以根据某些条件而改变,我需要查找另一个数据帧 现在,我如何在迭代时更新它。

for i, row in df.iterrows():
if <something>:
row['ifor'] = x
else:
row['ifor'] = y


df.ix[i]['ifor'] = x

这些方法似乎都不起作用。我没有在数据框架中看到更新的值。

450454 次浏览

你应该通过df.ix[i, 'exp']=Xdf.loc[i, 'exp']=X来赋值,而不是df.ix[i]['ifor'] = x

否则,你正在处理一个视图,并且应该得到一个温暖:

-c:1: SettingWithCopyWarning:一个值正在试图从一个数据帧(DataFrame)中设置一个切片的副本。 尝试使用.loc[row_index,col_indexer] = value来代替

但可以肯定的是,循环可能最好被一些向量化算法所取代,以充分利用@Phillip Cloud所建议的DataFrame

你可以使用df.at:

for i, row in df.iterrows():
ifor_val = something
if <condition>:
ifor_val = something_else
df.at[i,'ifor'] = ifor_val

对于0.21.0之前的版本,使用df.set_value:

for i, row in df.iterrows():
ifor_val = something
if <condition>:
ifor_val = something_else
df.set_value(i,'ifor',ifor_val)

如果你不需要行值,你可以简单地遍历df的索引,但我保留了原始的for循环,以防你需要在这里没有显示的行值。

你可以使用itertuples()方法,它迭代DataFrame行作为命名元组,索引值作为元组的第一个元素。与iterrows()相比,它要快得多。对于itertuples(),每个row在数据帧中包含它的Index,你可以使用loc来设置这个值。

for row in df.itertuples():
if <something>:
df.at[row.Index, 'ifor'] = x
else:
df.at[row.Index, 'ifor'] = x


df.loc[row.Index, 'ifor'] = x

在大多数情况下,itertuples()iatat快。

谢谢@SantiStSupery, 使用__ABC0比loc快得多

Pandas DataFrame对象应该被认为是一个系列的系列。换句话说,你应该从列的角度来考虑它。这一点很重要的原因是,当你使用pd.DataFrame.iterrows时,你是在作为Series遍历行。但是这些是数据帧存储的Series,所以它们是迭代时为你创建的新Series。这意味着当您尝试分配它们时,这些编辑最终不会反映在原始数据帧中。

好了,现在问题已经解决了:我们该怎么做?

在这篇文章之前的建议包括:

  1. pd.DataFrame.set_value在Pandas 0.21版已弃用
  2. pd.DataFrame.ix弃用
  3. pd.DataFrame.loc很好,但是能工作在数组索引器你可以做得更好
< p > 我的建议 < br > 使用pd.DataFrame.at < / p >
for i in df.index:
if <something>:
df.at[i, 'ifor'] = x
else:
df.at[i, 'ifor'] = y

你甚至可以把它改为:

for i in df.index:
df.at[i, 'ifor'] = x if <something> else y

回应评论

如果我需要使用前一行的值if条件?

for i in range(1, len(df) + 1):
j = df.columns.get_loc('ifor')
if <something>:
df.iat[i - 1, j] = x
else:
df.iat[i - 1, j] = y
for i, row in df.iterrows():
if <something>:
df.at[i, 'ifor'] = x
else:
df.at[i, 'ifor'] = y

好吧,如果你无论如何都要迭代,为什么不使用最简单的方法df['Column'].values[i]

df['Column'] = ''


for i in range(len(df)):
df['Column'].values[i] = something/update/new_value

或者如果你想比较新值和旧值或者类似的东西,为什么不把它存储在一个列表中,然后在最后追加。

mylist, df['Column'] = [], ''


for <condition>:
mylist.append(something/update/new_value)


df['Column'] = mylist

从列中增加MAX数。例如:

df1 = [sort_ID, Column1,Column2]
print(df1)

我的输出:

Sort_ID Column1 Column2
12         a    e
45         b    f
65         c    g
78         d    h

MAX = df1['Sort_ID'].max() #This returns my Max Number

现在,我需要在df2中创建一个列,并填充使MAX增加的列值。

Sort_ID Column1 Column2
79      a1       e1
80      b1       f1
81      c1       g1
82      d1       h1

注意:df2最初只包含columnn1和Column2。我们需要创建Sortid列,并从df1增加MAX。

最好使用df.apply() -来使用lambda函数

df["ifor"] = df.apply(lambda x: {value} if {condition} else x["ifor"], axis=1)

列表理解可以是一个选项。

df['new_column'] = [your_func(x) for x in df['column']]

这将遍历列df['column'],使用来自df['column']的值调用函数your_func,并为新列df['new_column']中的行赋值。

请不要忘记创建一个函数。