行ごとに繰り返しながらパンダのデータフレームを更新する


213

私はこのようなパンダデータフレームを持っています(かなり大きなものです)

           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

これらのアプローチはどれも機能していないようです。データフレームで更新された値が表示されません。


2
あなたが欲しいと思うdf.ix[i,'ifor']df.ix[i]['ifor']連鎖インデックスであるため、問題があります(パンダでは信頼できません)。
カールD.

1
他のフレームと同様に提供できますか<something>。コードをベクトル化できるかどうかは、それらに依存します。一般に、は避けてくださいiterrows。あなたの場合、各行はdtypeになるので、絶対に避けてobjectくださいSeries
Phillip Cloud

条件にブールマスクを作成し、それらすべての行を更新してから、残りを他の値に設定する方がよいでしょう
EdChum

iterrows()は使用しないでください。それはパンダの歴史の中で最悪のアンチパターンを露骨に可能にするものです。
cs95

回答:


232

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

6
pandas.pydata.org/pandas-docs/stable/generated/…を参照してください。2番目の箇条書き:「2.反復しているものは絶対に変更しないでください」
Davor Josipovic

32
同じように読んだかどうかはわかりません。私の疑似コードを見ると、イテレータからの値ではなく、データフレームに変更を加えています。イテレータ値は、値/オブジェクトのインデックスにのみ使用されます。ドキュメントで言及されている理由により、失敗するのはrow ['ifor'] = some_thingです。
rakke

3
説明していただきありがとうございます。
Davor Josipovic 2016年

8
現在はset_valueも廃止されており、.at(または.iat)を使用する必要があるため、ループは次のようになります。 i、 'ifor'] = ifor_val
complexM

2
set_valueは非推奨であり、将来のリリースで削除される予定です。代わりに.at []または.iat []アクセサを使用してください
RoyaumeIX

75

Pandas DataFrameオブジェクトは、シリーズのシリーズと考える必要があります。つまり、列の観点から考える必要があります。これが重要である理由は、使用pd.DataFrame.iterrowsするときにシリーズとして行を反復しているためです。ただし、これらはデータフレームが格納しているシリーズではないため、繰り返し処理中に作成される新しいシリーズです。つまり、それらを割り当てようとしても、それらの編集は元のデータフレームに反映されません。

さて、それが邪魔にならないようになりました:何をしますか?

この投稿の前の提案は次のとおりです。

  1. 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

また、前の行の値をif条件に使用する必要がある場合はどうなりますか?OG dfに遅延列を追加しますか?
ユカ

効率的には、時間差のある列を追加するよりもアプローチが優れていますか、それとも小規模なデータセットの影響は無視できますか (1万行未満)
Yuca、

場合によります。遅れたカラムを使いに行きます。この答えは、ループする必要がある場合の対処法を示しています。しかし、ループする必要がない場合は、ループしないでください。
piRSquared

それを手に入れた、それがためにあなたのフィードバック持つことが可能かどうもstackoverflow.com/q/51753001/9754169を、それは素晴らしいだろう:D
YUCA

古い選択肢と.at []を対比するのに最適
Justas '27

35

使用できるメソッドはitertuples()、DataFrameの行を名前付きタプルとして反復し、インデックス値をタプルの最初の要素として使用します。また、に比べてはるかに高速iterrows()です。の場合itertuples()、それぞれrowIndexDataFrameに含ま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、使用して.atはるかに高速に比べていますloc


3
正確なインデックスを指定するだけなので、パフォーマンスを向上させるために.locの代わりに.atを使用することを考えるかもしれません。詳細については、この質問参照してください
SantiStSupery

変だと思いますがdf.loc[row.Index, 3] = x動作しません。一方、df.loc[row.Index, 'ifor'] = x動作します!
seralouk

19

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が提案するように、ループはおそらくベクトル化アルゴリズムに置き換えるほうがよいでしょう。


10

ええと、とにかく反復する場合は、何よりも単純な方法を使用しないでください。 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

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

0

を使用してlambda関数を使用することをお勧めしますdf.apply()-

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

-3

列から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には、最初はColumn1とColumn2のみが含まれます。Sortid列を作成し、df1からMAXを増分する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.