Perbarui bingkai data dalam panda saat iterasi baris demi baris

214

Saya memiliki bingkai data panda yang terlihat seperti ini (ini yang cukup besar)

           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 

sekarang saya ingin mengulang baris demi baris dan ketika saya melewati setiap baris, nilai dari ifor setiap baris dapat berubah tergantung pada beberapa kondisi dan saya perlu mencari dataframe lain.

Sekarang, bagaimana saya memperbarui ini saat saya mengulanginya. Sudah mencoba beberapa hal yang tidak ada yang berhasil.

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

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

Tidak satu pun dari pendekatan ini yang berhasil. Saya tidak melihat nilai-nilai diperbarui dalam kerangka data.

AMM
sumber
2
Saya pikir kamu mau df.ix[i,'ifor']. df.ix[i]['ifor']bermasalah karena itu dirantai pengindeksan (yang tidak dapat diandalkan dalam panda).
Karl D.
1
Bisakah Anda memberikan bingkai lainnya serta <something>. Apakah kode Anda dapat di-vektor-kan tergantung pada hal-hal itu. Secara umum, hindari iterrows. Dalam kasus Anda, Anda pasti harus menghindarinya karena setiap baris akan menjadi objectdtype Series.
Phillip Cloud
Anda akan lebih baik membuat topeng boolean untuk kondisi Anda, memperbarui semua baris itu dan kemudian mengatur sisanya ke nilai lain
EdChum
Tolong jangan gunakan iterrows (). Ini adalah pendukung nyata dari pola anti terburuk dalam sejarah panda.
cs95

Jawaban:

232

Anda dapat menetapkan nilai dalam loop menggunakan 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)

Jika Anda tidak membutuhkan nilai-nilai baris, Anda cukup mengulangi indeks df, tetapi saya menyimpan yang asli untuk-loop jika Anda membutuhkan nilai baris untuk sesuatu yang tidak ditampilkan di sini.

memperbarui

df.set_value () telah ditinggalkan sejak versi 0.21.0 Anda dapat menggunakan df.at () sebagai gantinya:

for i, row in df.iterrows():
    ifor_val = something
    if <condition>:
        ifor_val = something_else
    df.at[i,'ifor'] = ifor_val
rakke
sumber
6
Lihat pandas.pydata.org/pandas-docs/stable/generated/… , bullet kedua: "2.Anda tidak boleh memodifikasi sesuatu yang Anda ulangi"
Davor Josipovic
32
Saya tidak yakin apakah kita membacanya sama persis. Jika Anda melihat kode pseudo saya, saya melakukan modifikasi pada dataframe, bukan pada nilai dari iterator. Nilai iterator hanya digunakan untuk indeks nilai / objek. Apa yang akan gagal adalah baris ['ifor'] = some_thing, untuk alasan yang disebutkan dalam dokumentasi.
rakke
3
Terimakasih atas klarifikasinya.
Davor Josipovic
8
sekarang set_value juga didepresiasi, dan harus menggunakan .at (atau .iat), sehingga loop saya terlihat seperti ini: untuk saya, baris dalam df.iterrows (): ifor_val = sesuatu jika <condition>: ifor_val = something_else df.at [ i, 'ifor'] = ifor_val
complexM
2
set_value sudah usang dan akan dihapus di rilis mendatang. Silakan gunakan .at [] atau .iat [] sebagai gantinya
RoyaumeIX
75

Objek DataFrame Pandas harus dianggap sebagai Seri Seri. Dengan kata lain, Anda harus memikirkannya dalam hal kolom. Alasan mengapa ini penting adalah karena ketika Anda menggunakan pd.DataFrame.iterrowsAnda beralih melalui baris sebagai Seri. Tapi ini bukan Seri yang disimpan oleh frame data dan jadi itu adalah Seri baru yang dibuat untuk Anda saat Anda beralih. Itu menyiratkan bahwa ketika Anda mencoba untuk menetapkannya, suntingan itu tidak akan berakhir tercermin dalam bingkai data asli.

Ok, sekarang setelah itu: Apa yang kita lakukan?

Saran sebelum posting ini termasuk:

  1. pd.DataFrame.set_valuetidak digunakan pada Pandas versi 0.21
  2. pd.DataFrame.ixsudah usang
  3. pd.DataFrame.locbaik-baik saja tetapi dapat bekerja pada pengindeks array dan Anda dapat melakukan lebih baik

Rekomendasi saya
Gunakanpd.DataFrame.at

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

Anda bahkan dapat mengubah ini menjadi:

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

Respon terhadap komentar

dan bagaimana jika saya perlu menggunakan nilai dari baris sebelumnya untuk kondisi 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
piRquared
sumber
dan bagaimana jika saya perlu menggunakan nilai dari baris sebelumnya untuk kondisi if? tambahkan kolom lagged ke OG df?
Yuca
efisiensi bijaksana, apakah pendekatan Anda lebih baik vs menambahkan kolom tertinggal atau efeknya diabaikan untuk dataset kecil? (Baris <10k)
Yuca
Itu tergantung. Saya akan menggunakan kolom lagged. Jawaban ini menunjukkan apa yang harus dilakukan jika Anda harus mengulang. Tetapi jika Anda tidak perlu mengulang, maka tidak perlu.
piRSquared
Mengerti, juga jika mungkin untuk mendapatkan umpan balik Anda untuk stackoverflow.com/q/51753001/9754169 maka akan luar biasa: D
Yuca
Bagus untuk membandingkan .at [] dengan alternatif yang lebih lama
Justas
35

Metode yang dapat Anda gunakan adalah itertuples(), itu berulang di baris DataFrame sebagai namedtuple, dengan nilai indeks sebagai elemen pertama dari tuple. Dan itu jauh lebih cepat dibandingkan dengan iterrows(). Sebab itertuples(), masing row- masing berisi Indexdi dalam DataFrame, dan Anda bisa menggunakan locuntuk mengatur nilainya.

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

Dalam kebanyakan kasus, itertuples()lebih cepat dari iatatau at.

Terima kasih @SantiStSupery, menggunakan .atjauh lebih cepat daripadaloc .

GoingMyWay
sumber
3
Karena Anda hanya menunjuk pada indeks yang tepat, Anda mungkin berpikir untuk menggunakan .at alih-alih .loc untuk meningkatkan kinerja Anda. Lihat pertanyaan ini untuk info lebih lanjut tentang ini
SantiStSupery
berpikir aneh tetapi df.loc[row.Index, 3] = xtidak berhasil. Di sisi lain, df.loc[row.Index, 'ifor'] = xberhasil!
seralouk
19

Anda harus menetapkan nilai dengan df.ix[i, 'exp']=Xatau df.loc[i, 'exp']=Xalih-alih df.ix[i]['ifor'] = x.

Jika tidak, Anda sedang mengerjakan suatu tampilan, dan seharusnya mendapatkan pemanasan:

-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

Namun yang pasti, loop mungkin sebaiknya diganti oleh beberapa algoritma vektor untuk memanfaatkan sepenuhnya DataFrameseperti yang disarankan oleh @Phillip Cloud.

CT Zhu
sumber
10

Nah, jika Anda akan beralih lagi, mengapa tidak menggunakan metode yang paling sederhana, df['Column'].values[i]

df['Column'] = ''

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

Atau jika Anda ingin membandingkan nilai-nilai baru dengan yang lama atau yang seperti itu, mengapa tidak menyimpannya dalam daftar lalu tambahkan pada akhirnya.

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

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

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

Lebih baik menggunakan lambdafungsi menggunakan df.apply()-

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

Tambahkan angka MAX dari kolom. Sebagai contoh :

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

Output saya:

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 

Sekarang, saya perlu membuat kolom di df2 dan mengisi nilai kolom yang menambah MAX.

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

Catatan: df2 pada awalnya hanya akan berisi Column1 dan Column2. kita membutuhkan kolom Sortid untuk dibuat dan tambahan MAX dari df1.

Shazir Jabbar
sumber