在逐行迭代时更新pandas中的数据帧

时间:2014-04-28 00:19:50

标签: python pandas updates dataframe

我有一个看起来像这样的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

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

8 个答案:

答案 0 :(得分:145)

您可以使用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循环,以防你需要这里未显示的行的值。

<强>更新

df.set_value()自版本0.21.0起已弃用 你可以改用df.at():

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

答案 1 :(得分:42)

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

好的,现在已经不在了:我们做了什么?

此帖之前的建议包括:

  1. pd.DataFrame.set_valuedeprecated as of Pandas version 0.21
  2. pd.DataFrame.ixdeprecated
  3. pd.DataFrame.loc很好但是can work on array indexers你可以做得更好
  4. 我的推荐
    使用pd.DataFrame.at

    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
    

答案 2 :(得分:19)

您可以使用的方法是itertuples(),它将DataFrame行作为namedpuples迭代,索引值作为元组的第一个元素。与iterrows()相比,它要快得多。对于itertuples(),每个row在DataFrame中包含其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

感谢@SantiStSupery,using .at is much faster

答案 3 :(得分:17)

您应该按df.ix[i, 'exp']=Xdf.loc[i, 'exp']=X而不是df.ix[i]['ifor'] = x分配值。

否则你正在制作一个视图,应该变暖:

-c:1: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_index,col_indexer] = value instead

但当然,循环可能应该更好地被一些矢量化算法取代,以充分利用DataFrame作为@Phillip Cloud建议。

答案 4 :(得分:7)

好吧,如果你打算无论如何迭代,为什么不使用最简单的方法,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

答案 5 :(得分:5)

// Get a reference to the config
var config = ConfigManager.Instance.GetProperties();

// Use OAuthTokenCredential to request an access token from PayPal
var accessToken = new OAuthTokenCredential(config).GetAccessToken();

答案 6 :(得分:5)

最好通过lambda-

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

答案 7 :(得分:-1)

从一列增加最大数。例如:

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最初仅包含Column1和Column2。我们需要创建Sortid列,并从df1开始增加MAX。