pandalar diğer sütunlardaki değerlere dayalı yeni sütunlar oluşturur / satır başına birden çok sütunun işlevini uygular


316

Ben bu altı sütunların (için (bir if-else merdiveni kullanır) benim özel bir işlev uygulamak istediğiniz ERI_Hispanic, ERI_AmerInd_AKNatv, ERI_Asian, ERI_Black_Afr.Amer, ERI_HI_PacIsl, ERI_Whitebenim dataframe her satırda).

Diğer sorulardan farklı yöntemler denedim, ancak yine de sorunum için doğru cevabı bulamıyorum. Bunun kritik parçası, eğer kişi Hispanik olarak sayılırsa, başka bir şey olarak sayılamaz. Başka bir etnik köken sütununda "1" olsa bile, iki veya daha fazla ırk değil, İspanyol olarak sayılırlar. Benzer şekilde, tüm ERI sütunlarının toplamı 1'den büyükse, bunlar iki veya daha fazla yarış olarak sayılır ve benzersiz bir etnik köken olarak sayılamaz (Hispanik hariç). Umarım bu mantıklıdır. Herhangi bir yardım büyük takdir edilecektir.

Bu neredeyse her satır boyunca bir for döngüsü yapmak gibidir ve her kayıt bir kritere uyuyorsa bir listeye eklenir ve orijinalden kaldırılır.

Aşağıdaki veri çerçevesinde SQL'de aşağıdaki özelliklere göre yeni bir sütun hesaplamam gerekiyor:

========================= KRİTERLER ======================== =======

IF [ERI_Hispanic] = 1 THEN RETURN Hispanic
ELSE IF SUM([ERI_AmerInd_AKNatv] + [ERI_Asian] + [ERI_Black_Afr.Amer] + [ERI_HI_PacIsl] + [ERI_White]) > 1 THEN RETURN Two or More
ELSE IF [ERI_AmerInd_AKNatv] = 1 THEN RETURN A/I AK Native
ELSE IF [ERI_Asian] = 1 THEN RETURN Asian
ELSE IF [ERI_Black_Afr.Amer] = 1 THEN RETURN Black/AA
ELSE IF [ERI_HI_PacIsl] = 1 THEN RETURN Haw/Pac Isl.”
ELSE IF [ERI_White] = 1 THEN RETURN White

Yorum: Eğer İspanyollar için ERI Bayrağı Doğru ise (1), çalışan “Hispanik” olarak sınıflandırılır

Yorum: Birden fazla İspanyol olmayan ERI Bayrağı doğruysa, “İki veya Daha Fazla” döndürün

====================== DATAFRAME ===========================

     lname          fname       rno_cd  eri_afr_amer    eri_asian   eri_hawaiian    eri_hispanic    eri_nat_amer    eri_white   rno_defined
0    MOST           JEFF        E       0               0           0               0               0               1           White
1    CRUISE         TOM         E       0               0           0               1               0               0           White
2    DEPP           JOHNNY              0               0           0               0               0               1           Unknown
3    DICAP          LEO                 0               0           0               0               0               1           Unknown
4    BRANDO         MARLON      E       0               0           0               0               0               0           White
5    HANKS          TOM         0                       0           0               0               0               1           Unknown
6    DENIRO         ROBERT      E       0               1           0               0               0               1           White
7    PACINO         AL          E       0               0           0               0               0               1           White
8    WILLIAMS       ROBIN       E       0               0           1               0               0               0           White
9    EASTWOOD       CLINT       E       0               0           0               0               0               1           White

Özel işleviniz, bazı değişkenlerin değerlerinin diğerlerine göre öncelikli olduğu uzun bir if-else merdiveni. Buna donanım mühendisliği açısından öncelik-kod çözücü denir .
smci

Yanıtlar:


407

Tamam, bunun için iki adım - ilk önce istediğiniz çeviriyi yapan bir işlev yazmak - Sahte kodunuza dayalı bir örnek bir araya getirdim:

def label_race (row):
   if row['eri_hispanic'] == 1 :
      return 'Hispanic'
   if row['eri_afr_amer'] + row['eri_asian'] + row['eri_hawaiian'] + row['eri_nat_amer'] + row['eri_white'] > 1 :
      return 'Two Or More'
   if row['eri_nat_amer'] == 1 :
      return 'A/I AK Native'
   if row['eri_asian'] == 1:
      return 'Asian'
   if row['eri_afr_amer']  == 1:
      return 'Black/AA'
   if row['eri_hawaiian'] == 1:
      return 'Haw/Pac Isl.'
   if row['eri_white'] == 1:
      return 'White'
   return 'Other'

Bunun üzerinden geçmek isteyebilirsiniz, ancak işleve giden parametrenin "satır" etiketli bir Seri nesnesi olarak kabul edildiğini görmek için hile yapıyor gibi görünüyor.

Ardından, işlevi uygulamak için pandalardaki uygula işlevini kullanın - ör.

df.apply (lambda row: label_race(row), axis=1)

Axis = 1 belirtecine dikkat edin; bu, uygulamanın bir sütun düzeyinde değil, bir satırda yapıldığı anlamına gelir. Sonuçlar burada:

0           White
1        Hispanic
2           White
3           White
4           Other
5           White
6     Two Or More
7           White
8    Haw/Pac Isl.
9           White

Bu sonuçlardan memnunsanız, sonuçları tekrar çalıştırın ve sonuçları orijinal veri çerçevenizdeki yeni bir sütuna kaydedin.

df['race_label'] = df.apply (lambda row: label_race(row), axis=1)

Ortaya çıkan veri çerçevesi şöyle görünür (yeni sütunu görmek için sağa kaydırın):

      lname   fname rno_cd  eri_afr_amer  eri_asian  eri_hawaiian   eri_hispanic  eri_nat_amer  eri_white rno_defined    race_label
0      MOST    JEFF      E             0          0             0              0             0          1       White         White
1    CRUISE     TOM      E             0          0             0              1             0          0       White      Hispanic
2      DEPP  JOHNNY    NaN             0          0             0              0             0          1     Unknown         White
3     DICAP     LEO    NaN             0          0             0              0             0          1     Unknown         White
4    BRANDO  MARLON      E             0          0             0              0             0          0       White         Other
5     HANKS     TOM    NaN             0          0             0              0             0          1     Unknown         White
6    DENIRO  ROBERT      E             0          1             0              0             0          1       White   Two Or More
7    PACINO      AL      E             0          0             0              0             0          1       White         White
8  WILLIAMS   ROBIN      E             0          0             1              0             0          0       White  Haw/Pac Isl.
9  EASTWOOD   CLINT      E             0          0             0              0             0          1       White         White

69
sadece bir not: sadece fonksiyonunuza satır besliyorsanız, şunları yapabilirsiniz:df.apply(label_race, axis=1)
Paul H

1
Başka bir satıra benzer bir şey yapmak istersem aynı işlevi kullanabilir miyim? Örneğin, sonuçlardan, ['race_label'] == “Beyaz”, 'Beyaz' vb. Döndürürse. Ancak ['race_label'] == 'Bilinmeyen' ['rno_defined'] sütunundaki değerleri döndürürse. Aynı işlevin işe yarayacağını varsayıyorum, ancak diğer sütundaki değerleri nasıl alacağımı anlayamıyorum.
Dave

2
Sen 'race_label' alanına, yani görünüyor yeni bir işlev yazma ve yeni bir alanı sonuçları gönderebilir veya olabilir - ve son değişen, bu bu durumda, düzenleme orijinal işlevi daha iyi olabileceğini düşünüyorum return 'Other'hattı için return row['rno_defined']hangi gerektiği if / then ifadeleri kümesinin bir eşleşme bulamadığı durumlarda (diğer bir deyişle şu anda 'Diğer' ifadesini görürsünüz) bu sütundaki değeri kullanın.
Thomas Kimber

9
Basitleştirebilirsiniz: df.apply(lambda row: label_race (row),axis=1)-df.apply(label_race, axis=1)
user48956

5
Daha yeni sürümlerde, 'SettingWithCopyWarning' alırsanız, 'ata' yöntemine bakmalısınız. Bkz. Stackoverflow.com/a/12555510/3015186
np8

218

Bu, 'diğerlerinden pandalar yeni sütunu' için ilk Google sonucu olduğundan, basit bir örnek:

import pandas as pd

# make a simple dataframe
df = pd.DataFrame({'a':[1,2], 'b':[3,4]})
df
#    a  b
# 0  1  3
# 1  2  4

# create an unattached column with an index
df.apply(lambda row: row.a + row.b, axis=1)
# 0    4
# 1    6

# do same but attach it to the dataframe
df['c'] = df.apply(lambda row: row.a + row.b, axis=1)
df
#    a  b  c
# 0  1  3  4
# 1  2  4  6

Eğer alırsanız SettingWithCopyWarningbu şekilde de yapabilirsiniz:

fn = lambda row: row.a + row.b # define a function for the new column
col = df.apply(fn, axis=1) # get column data with an index
df = df.assign(c=col.values) # assign values to column 'c'

Kaynak: https://stackoverflow.com/a/12555510/243392

Sütun adınız boşluk içeriyorsa aşağıdaki gibi bir sözdizimi kullanabilirsiniz:

df = df.assign(**{'some column name': col.values})

Ve işte uygulamak ve atamak için belgeler .


1
Kısa cevap, gerekli damıtılmış!
Frode Akselsen

1
Ben alıyorum SettingWithCopyWarningyaptığımda df['c'] = df.apply(lambda row: row.a + row.b, axis=1) burada gerçek bir sorun, bu konuda ya endişelenmeyin gerektiğidir?
Nate

2
@Nate bu uyarıyı hiç almadım - belki de veri çerçevesindeki verilere bağlıdır? Ama cevabı 2017'den başka bir cevaba dayanarak değiştirdim.
Brian Burns

57

Yukarıdaki cevaplar mükemmel şekilde geçerlidir, ancak vektörize edilmiş bir çözüm şeklinde mevcuttur numpy.select. Bu, koşulları tanımlamanıza, daha sonra bu koşulların çıktılarını, kullanmaktan çok daha verimli bir şekilde tanımlamanıza olanak tanır apply:


İlk olarak, koşulları tanımlayın:

conditions = [
    df['eri_hispanic'] == 1,
    df[['eri_afr_amer', 'eri_asian', 'eri_hawaiian', 'eri_nat_amer', 'eri_white']].sum(1).gt(1),
    df['eri_nat_amer'] == 1,
    df['eri_asian'] == 1,
    df['eri_afr_amer'] == 1,
    df['eri_hawaiian'] == 1,
    df['eri_white'] == 1,
]

Şimdi, ilgili çıktıları tanımlayın:

outputs = [
    'Hispanic', 'Two Or More', 'A/I AK Native', 'Asian', 'Black/AA', 'Haw/Pac Isl.', 'White'
]

Son olarak şunu kullanarak numpy.select:

res = np.select(conditions, outputs, 'Other')
pd.Series(res)

0           White
1        Hispanic
2           White
3           White
4           Other
5           White
6     Two Or More
7           White
8    Haw/Pac Isl.
9           White
dtype: object

Neden numpy.selecttekrar kullanılmalı apply? İşte bazı performans kontrolleri:

df = pd.concat([df]*1000)

In [42]: %timeit df.apply(lambda row: label_race(row), axis=1)
1.07 s ± 4.16 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [44]: %%timeit
    ...: conditions = [
    ...:     df['eri_hispanic'] == 1,
    ...:     df[['eri_afr_amer', 'eri_asian', 'eri_hawaiian', 'eri_nat_amer', 'eri_white']].sum(1).gt(1),
    ...:     df['eri_nat_amer'] == 1,
    ...:     df['eri_asian'] == 1,
    ...:     df['eri_afr_amer'] == 1,
    ...:     df['eri_hawaiian'] == 1,
    ...:     df['eri_white'] == 1,
    ...: ]
    ...:
    ...: outputs = [
    ...:     'Hispanic', 'Two Or More', 'A/I AK Native', 'Asian', 'Black/AA', 'Haw/Pac Isl.', 'White'
    ...: ]
    ...:
    ...: np.select(conditions, outputs, 'Other')
    ...:
    ...:
3.09 ms ± 17 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Kullanmak numpy.selectbize büyük ölçüde iyileştirilmiş performans sağlar ve tutarsızlık yalnızca veri büyüdükçe artar.


8
Bu çözüm çok küçümseniyor. Uygula ile benzer bir şey yapabileceğimi biliyordum ama binlerce dosya için bu işlemi yapmak zorunda olduğum için bir alternatif arıyordum. Gönderinizi bulduğuma çok sevindim.
mlx

Benzer bir şey oluşturmakta sorun yaşıyorum. "Bir serinin gerçek değeri belirsiz ..." hata mesajını alıyorum. Kodum Kansas_City = ['ND', 'SD', 'NE', 'KS', 'MN', 'IA', 'MO'] koşullar = [Kansas_City'deki df_merge ['state_alpha']] outputs = [' Kansas City '] df_merge [' Region '] = np.select (koşullar, çıktılar,' Diğer ') Herhangi bir yardımcı olabilir mi?
Shawn Schreier

3
Bu kabul edilen cevap olmalı. Diğerleri iyi ama daha büyük verilerde çalıştığınızda, bu çalışan tek şey ve inanılmaz derecede hızlı çalışıyor.
Proletarya

29

.apply()ilk parametre olarak bir işlevi alır; geçmek label_raceböylece fonksiyonu:

df['race_label'] = df.apply(label_race, axis=1)

Bir işlevi geçmek için lambda işlevi yapmanız gerekmez.


12

bunu dene,

df.loc[df['eri_white']==1,'race_label'] = 'White'
df.loc[df['eri_hawaiian']==1,'race_label'] = 'Haw/Pac Isl.'
df.loc[df['eri_afr_amer']==1,'race_label'] = 'Black/AA'
df.loc[df['eri_asian']==1,'race_label'] = 'Asian'
df.loc[df['eri_nat_amer']==1,'race_label'] = 'A/I AK Native'
df.loc[(df['eri_afr_amer'] + df['eri_asian'] + df['eri_hawaiian'] + df['eri_nat_amer'] + df['eri_white']) > 1,'race_label'] = 'Two Or More'
df.loc[df['eri_hispanic']==1,'race_label'] = 'Hispanic'
df['race_label'].fillna('Other', inplace=True)

O / P:

     lname   fname rno_cd  eri_afr_amer  eri_asian  eri_hawaiian  \
0      MOST    JEFF      E             0          0             0   
1    CRUISE     TOM      E             0          0             0   
2      DEPP  JOHNNY    NaN             0          0             0   
3     DICAP     LEO    NaN             0          0             0   
4    BRANDO  MARLON      E             0          0             0   
5     HANKS     TOM    NaN             0          0             0   
6    DENIRO  ROBERT      E             0          1             0   
7    PACINO      AL      E             0          0             0   
8  WILLIAMS   ROBIN      E             0          0             1   
9  EASTWOOD   CLINT      E             0          0             0   

   eri_hispanic  eri_nat_amer  eri_white rno_defined    race_label  
0             0             0          1       White         White  
1             1             0          0       White      Hispanic  
2             0             0          1     Unknown         White  
3             0             0          1     Unknown         White  
4             0             0          0       White         Other  
5             0             0          1     Unknown         White  
6             0             0          1       White   Two Or More  
7             0             0          1       White         White  
8             0             0          0       White  Haw/Pac Isl.  
9             0             0          1       White         White 

.locyerine kullanın apply.

vektörleşmeyi geliştirir.

.loc Basit bir şekilde çalışır, koşula göre satırları maskeler, satırları dondurmaya uygular.

daha fazla ayrıntı için ziyaret edin .loc docs

Performans metrikleri:

Kabul edilen cevap:

def label_race (row):
   if row['eri_hispanic'] == 1 :
      return 'Hispanic'
   if row['eri_afr_amer'] + row['eri_asian'] + row['eri_hawaiian'] + row['eri_nat_amer'] + row['eri_white'] > 1 :
      return 'Two Or More'
   if row['eri_nat_amer'] == 1 :
      return 'A/I AK Native'
   if row['eri_asian'] == 1:
      return 'Asian'
   if row['eri_afr_amer']  == 1:
      return 'Black/AA'
   if row['eri_hawaiian'] == 1:
      return 'Haw/Pac Isl.'
   if row['eri_white'] == 1:
      return 'White'
   return 'Other'

df=pd.read_csv('dataser.csv')
df = pd.concat([df]*1000)

%timeit df.apply(lambda row: label_race(row), axis=1)

Döngü başına 1,15 s ± 46,5 ms (7 çalışmanın ortalama ± standart sapması, her biri 1 döngü)

Önerilen Cevabım:

def label_race(df):
    df.loc[df['eri_white']==1,'race_label'] = 'White'
    df.loc[df['eri_hawaiian']==1,'race_label'] = 'Haw/Pac Isl.'
    df.loc[df['eri_afr_amer']==1,'race_label'] = 'Black/AA'
    df.loc[df['eri_asian']==1,'race_label'] = 'Asian'
    df.loc[df['eri_nat_amer']==1,'race_label'] = 'A/I AK Native'
    df.loc[(df['eri_afr_amer'] + df['eri_asian'] + df['eri_hawaiian'] + df['eri_nat_amer'] + df['eri_white']) > 1,'race_label'] = 'Two Or More'
    df.loc[df['eri_hispanic']==1,'race_label'] = 'Hispanic'
    df['race_label'].fillna('Other', inplace=True)
df=pd.read_csv('s22.csv')
df = pd.concat([df]*1000)

%timeit label_race(df)

Çevrim başına 24,7 ms ± 1,7 ms (7 çalışmanın ortalama ± standart sapması, her biri 10 döngü)

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.