Satırları tekrarlayarak pandalardaki bir veri çerçevesini güncelleme


214

Buna benzeyen bir panda veri çerçevesi var (oldukça büyük bir tane)

           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 

şimdi satır satır yineleme yapmak istiyorum ve her satırdan geçerken, her satırın değeri ifor bazı koşullara bağlı olarak değişebilir ve başka bir veri çerçevesi aramak gerekir.

Şimdi, bunu yinelediğimde nasıl güncelleyebilirim. Hiçbiri işe yaramayan birkaç şey denedi.

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

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

Bu yaklaşımların hiçbiri işe yaramıyor. Veri çerçevesinde güncellenen değerleri görmüyorum.


2
Bence istiyorsun df.ix[i,'ifor']. df.ix[i]['ifor']sorunlu çünkü zincirleme indeksleme (pandalarda güvenilir değil).
Karl D.

1
Yanı sıra diğer çerçeve sağlayabilir <something>. Kodunuzun vectorize edilip edilemeyeceği bu şeylere bağlı olacaktır. Genel olarak kaçının iterrows. Sizin durumunuzda, her satır bir dtype olacağından kesinlikle kaçınmalısınız . objectSeries
Phillip Cloud

Durumunuz için bir boole maskesi oluşturmaktan daha iyi olur, tüm bu satırları güncelleyin ve kalanını diğer değere ayarlayın
EdChum

Lütfen iterrows () kullanmayın. Pandalar tarihinin en kötü anti-paterninin açık bir sağlayıcısıdır.
cs95

Yanıtlar:


232

Df.set_value öğesini kullanarak döngüdeki değerleri atayabilirsiniz:

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

Satır değerlerine ihtiyacınız yoksa, sadece df dizinleri üzerinde yineleme yapabilirsiniz, ancak burada gösterilmeyen bir şey için satır değerine ihtiyacınız olması durumunda orijinal for-loop'u tuttum.

Güncelleme

0.21.0 sürümünden bu yana df.set_value () kullanımdan kaldırılmıştır, bunun yerine df.at () kullanabilirsiniz:

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

6
Bkz. Pandas.pydata.org/pandas-docs/stable/generated/… , ikinci madde işareti: " 2.Yetlediğiniz bir şeyi asla değiştirmemelisiniz"
Davor Josipoviç

32
Tam olarak aynı okuduğumuzdan emin değilim. Sahte koduma bakarsanız, yineleyicideki değerde değil, veri çerçevesinde değişiklik yaparım. Yineleyici değeri yalnızca değerin / nesnenin dizini için kullanılır. Başarısız olacak olan doküman [] ifor '] = some_thing'dir.
rakke

3
Açıklama için teşekkürler.
Davor Josipovic

8
Şimdi set_value da kullanımdan kaldırılmıştır ve .at (veya .iat) kullanmalıdır, bu yüzden döngüm şöyle görünür: i için, df.iterrows (): ifor_val = bir şey varsa <condition>: ifor_val = bir şey_else df.at [ i, 'ifor'] = ifor_val
complexM

2
set_value kullanımdan kaldırıldı ve gelecekteki bir sürümde kaldırılacak. Lütfen bunun yerine .at [] veya .iat [] erişimcilerini kullanın
RoyaumeIX

75

Pandalar DataFrame nesnesi bir Seri Serisi olarak düşünülmelidir. Başka bir deyişle, sütunlar olarak düşünmelisiniz. Bunun önemli olmasının nedeni, kullandığınız pd.DataFrame.iterrowszaman Seri olarak satırlar boyunca yinelemenizdir. Ancak bunlar veri çerçevesinin depoladığı Seri değildir ve bu nedenle siz yinelediğiniz sırada sizin için oluşturulan yeni Serilerdir. Bu, bunları atamaya çalıştığınızda, bu düzenlemelerin orijinal veri çerçevesine yansıtılmayacağı anlamına gelir.

Tamam, şimdi bu yoldan çıktı: Ne yapacağız?

Bu gönderiden önceki öneriler şunları içerir:

  1. pd.DataFrame.set_valueolan Pandalar sürümü 0.21 itibarıyla kullanımdan kaldırılmıştır
  2. pd.DataFrame.ixkullanımdan kaldırıldı
  3. pd.DataFrame.locgayet iyi ancak dizi indeksleyicileri üzerinde çalışabilir ve daha iyisini yapabilirsiniz

Tavsiyem
Kullanpd.DataFrame.at

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

Bunu şu şekilde de değiştirebilirsiniz:

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

Yoruma yanıt

ve if koşulu için önceki satırın değerini kullanmam gerekirse ne olur?

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

ve if koşulu için önceki satırın değerini kullanmam gerekirse ne olur? OG df gecikmeli bir sütun eklemek?
Yuca

verimlilik açısından, yaklaşımınız gecikmeli bir sütun eklemeye göre daha mı iyi yoksa küçük veri kümeleri için bu etki ihmal edilebilir mi? (<10 bin satır)
Yuca

Bu bağlıdır. Gecikmeli bir sütun kullanmak istiyorum. Bu cevap, döngü yapmanız gerektiğinde ne yapacağınızı göstermektedir. Ama ilmek yapman gerekmiyorsa, yapma.
piRSquared

Anladım, ayrıca stackoverflow.com/q/51753001/9754169 için görüşlerinizi almak mümkün olsaydı harika olurdu: D
Yuca

.At

35

Kullanabileceğiniz bir yöntem itertuples(), veri kümesinin ilk öğesi olarak dizin değeri ile adlandırılmış gruplar olarak DataFrame satırları üzerinde yinelemektir. Ve kıyasla çok daha hızlı iterrows(). İçin itertuples(), her rowit'i içeren IndexDataFrame içinde, ve kullanabileceğiniz locdeğerini ayarlamak için.

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

Çoğu durumda, veya itertuples()değerinden daha hızlıdır .iatat

Teşekkürler @SantiStSupery, kullanmak .atçok daha hızlıloc .


3
Yalnızca kesin bir dizini işaretlediğinizden, performansınızı artırmak için .loc yerine .at kullanmayı düşünebilirsiniz. Bu konuda daha fazla bilgi için bu soruya bakın
SantiStSupery

garip düşünüyorum ama df.loc[row.Index, 3] = xçalışmıyor. Öte yandan, df.loc[row.Index, 'ifor'] = xçalışıyor!
seralouk

19

Değer yerine df.ix[i, 'exp']=Xveya df.loc[i, 'exp']=Xyerine değer atamalısınız df.ix[i]['ifor'] = x.

Aksi takdirde bir görünüm üzerinde çalışıyorsunuz ve ısınmanız gerekiyor:

-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

Ama kesinlikle, DataFrame@Phillip Cloud'un önerdiği gibi tam olarak kullanmak için döngü muhtemelen vektörize edilmiş bir algoritma ile değiştirilmelidir .


10

Her neyse yineleyecekseniz, neden en basit yöntemi kullanmıyorsunuz, df['Column'].values[i]

df['Column'] = ''

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

Ya da yeni değerleri eski ya da bunun gibi bir şeyle karşılaştırmak istiyorsanız, neden bir listede saklamayın ve sonunda ekleyin.

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

lambdaFonksiyonları kullanarak daha iyi df.apply()-

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

-3

Bir sütundan MAX sayısını artırın. Örneğin :

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

Çıktım:

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 

Şimdi, df2 bir sütun oluşturmak ve MAX artıran sütun değerleri doldurmak gerekiyor.

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

Not: df2 başlangıçta yalnızca Sütun1 ve Sütun2'yi içerecektir. df1'den MAX öğesinin yaratılması ve artması için Sortid sütununa ihtiyacımız var.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.