Подтвердить что ты не робот

Обновление фрейма данных в pandas при повторении строки за строкой

У меня есть кадр данных 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

Ни один из этих подходов, похоже, не работает. Я не вижу значения, обновленные в фрейме данных.

4b9b3361

Ответ 1

Вы можете назначить значения в цикле, используя 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 на случай, если вам понадобится значение строки для чего-то, что здесь не показано.

Обновить

Начиная с версии 0.21.0 df.set_value() устарела, вместо нее можно использовать df.at():

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

Ответ 2

Объект Pandas DataFrame следует рассматривать как серию серий. Другими словами, вы должны думать об этом в терминах столбцов. Причина, по которой это важно, заключается в том, что когда вы используете pd.DataFrame.iterrows вы перебираете строки как Series. Но это не серии, которые хранит фрейм данных, и поэтому они являются новыми сериями, которые создаются для вас во время итерации. Это означает, что когда вы пытаетесь назначить их, эти изменения не будут отражены в исходном фрейме данных.

Хорошо, теперь это не так: что мы делаем?

Предложения до этого поста включают в себя:

  1. pd.DataFrame.set_value устарела с версии pd.DataFrame.set_value 0.21
  2. pd.DataFrame.ix устарела
  3. pd.DataFrame.loc хорошо, но может работать с индексаторами массивов, и вы можете сделать лучше

Моя рекомендация
Используйте 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

Ответ 3

Вы должны назначить значение df.ix[i, 'exp']=X или df.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

Метод, который вы можете использовать, это itertuples(), он перебирает строки DataFrame в виде именованных кортежей со значением индекса в качестве первого элемента кортежа. И это намного намного быстрее по сравнению с iterrows(). Для itertuples() каждая row содержит свой Index в DataFrame, и вы можете использовать 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, использование .at намного быстрее.

Ответ 5

Что ж, если вы все равно собираетесь повторять, почему бы не использовать самый простой метод из всех, 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

Ответ 6

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