web-dev-qa-db-fra.com

Mettre à jour une trame de données dans des pandas en itérant ligne par ligne

J'ai un cadre de données de pandas qui ressemble à ceci (c'est un assez gros)

           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 

maintenant, je voudrais parcourir ligne par ligne et au fur et à mesure que je parcourais chaque ligne, la valeur de iforin dans chaque ligne peut changer en fonction de certaines conditions et j'ai besoin de rechercher un autre cadre de données.

Maintenant, comment puis-je mettre à jour ceci pendant que j'itère .. Essayé quelques choses qu'aucune d'entre elles n'a fonctionné.

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

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

Aucune de ces approches ne semble fonctionner. Je ne vois pas les valeurs mises à jour dans le cadre de données.

121
AMM

Vous pouvez affecter des valeurs à la boucle en utilisant 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)

si vous n'avez pas besoin des valeurs de ligne, vous pouvez simplement parcourir les indices de df, mais j'ai conservé la boucle for originale au cas où vous auriez besoin de la valeur de la ligne pour quelque chose qui ne figure pas ici. 

mettre à jour

df.set_value () est obsolète depuis la version 0.21.0Vous pouvez utiliser df.at () à la place:

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

L'objet Pandas DataFrame doit être considéré comme une série de séries. En d'autres termes, vous devriez y penser en termes de colonnes. Cela est important parce que, lorsque vous utilisez pd.DataFrame.iterrows, vous parcourez les lignes en tant que série. Mais il s’agit de non la série que le bloc de données est en train de stocker. Il s’agit donc de nouvelles séries créées pour vous pendant l’itération. Cela implique que lorsque vous tentez de les affecter, ces modifications ne seront pas répercutées dans le bloc de données d'origine.

Ok, maintenant que c'est hors de propos: que faisons-nous?

Les suggestions antérieures à ce poste incluent:

  1. pd.DataFrame.set_value est obsolète à partir de Pandas version 0.21
  2. pd.DataFrame.ix est obsolète
  3. pd.DataFrame.loc c'est bien mais peut fonctionner sur les indexeurs de tableaux et vous pouvez faire mieux

Ma recommandation
Utilisez pd.DataFrame.at

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

Vous pouvez même changer ceci en:

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

Réponse au commentaire

et si je dois utiliser la valeur de la ligne précédente pour la condition 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
38
piRSquared

Vous devez attribuer une valeur par df.ix[i, 'exp']=X ou df.loc[i, 'exp']=X au lieu de df.ix[i]['ifor'] = x

Sinon, vous travaillez sur une vue et vous devriez obtenir un réchauffement:

-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

Mais il est certain que la boucle devrait probablement être mieux remplacée par un algorithme vectorisé pour tirer le meilleur parti de DataFrame comme l'a suggéré @Phillip Cloud.

17
CT Zhu

Une méthode que vous pouvez utiliser est itertuples() , qui effectue une itération sur les lignes DataFrame en tant qu'attributs nommés, avec la valeur d'index comme premier élément du Tuple. Et c'est beaucoup plus rapide que iterrows(). Pour itertuples(), chaque row contient sa Index dans le DataFrame, et vous pouvez utiliser loc pour définir la valeur. 

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

Merci @SantiStSupery, utiliser .at est beaucoup plus rapide .

16
GoingMyWay

Eh bien, si vous voulez de toute façon itérer, pourquoi ne pas utiliser la méthode la plus simple, df['Column'].values[i]

df['Column'] = ''

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

Ou si vous souhaitez comparer les nouvelles valeurs avec les anciennes ou quelque chose du genre, pourquoi ne pas les stocker dans une liste et les ajouter à la fin.

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

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

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

Incrémente le nombre MAX d'une colonne. Par exemple :

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

Ma sortie:

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 

Maintenant, je dois créer une colonne dans df2 et remplir les valeurs de colonne qui incrémentent le MAX.

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

Remarque: df2 ne contiendra initialement que Column1 et Column2. nous avons besoin de la colonne Sortid pour être créée et incrémentielle du MAX de df1. 

0
Shazir Jabbar