Pandalar bir dizi / veri çerçevesi sütununun koşullu oluşturulması


314

Aşağıdaki satırlar boyunca bir veri çerçevesi var:

    Type       Set
1    A          Z
2    B          Z           
3    B          X
4    C          Y

Ben Set = 'Z' ve Set = aksi takdirde 'kırmızı' renk yeşil ayarlar dataframe (= eşit sayıda kayıt / satır sayısı) ile aynı uzunlukta veri karesine (veya bir seri oluşturmak) başka bir sütun eklemek istiyorum .

Bunu yapmanın en iyi yolu nedir?

Yanıtlar:


711

Aralarından seçim yapabileceğiniz yalnızca iki seçeneğiniz varsa:

df['color'] = np.where(df['Set']=='Z', 'green', 'red')

Örneğin,

import pandas as pd
import numpy as np

df = pd.DataFrame({'Type':list('ABBC'), 'Set':list('ZZXY')})
df['color'] = np.where(df['Set']=='Z', 'green', 'red')
print(df)

verim

  Set Type  color
0   Z    A  green
1   Z    B  green
2   X    B    red
3   Y    C    red

İkiden fazla koşulunuz varsa kullanınnp.select . Örneğin, isterseniz colorolmak

  • yellow ne zaman (df['Set'] == 'Z') & (df['Type'] == 'A')
  • aksi bluehalde(df['Set'] == 'Z') & (df['Type'] == 'B')
  • aksi purplehalde(df['Type'] == 'B')
  • aksi takdirde black,

sonra kullan

df = pd.DataFrame({'Type':list('ABBC'), 'Set':list('ZZXY')})
conditions = [
    (df['Set'] == 'Z') & (df['Type'] == 'A'),
    (df['Set'] == 'Z') & (df['Type'] == 'B'),
    (df['Type'] == 'B')]
choices = ['yellow', 'blue', 'purple']
df['color'] = np.select(conditions, choices, default='black')
print(df)

hangi sonuç verir

  Set Type   color
0   Z    A  yellow
1   Z    B    blue
2   X    B  purple
3   Y    C   black

1
ile iki madde koyarsam işe yaramazsa ve
Amol Sharma

2
df ['color'] = list (np.where (df ['Set'] == 'Z', 'yeşil', 'kırmızı')) panda uyarısını bastırır: Kopyada bir değer ayarlanmaya çalışıyor bir DataFrame dilim. Bunun yerine .loc [row_indexer, col_indexer] = değer kullanmayı deneyin
denson

3
'yeşil' ve 'kırmızı' sütun aritmetiği ile de değiştirilebilir. ör. ,df['foo'] = np.where(df['Set']=='Z', df['Set'], df['Type'].shift(1))
Alejandro

np.where yeni bir sütun oluşturur mu? Bu kodu kullandım ve df.color.head () yaptığımda: 'numpy.ndarray' nesnesinin 'head' özelliği yok
vvv

3
Bunu defalarca değerlendiremediğim için utanç verici. Bir oylama yeterli görünmüyor.
Harper

120

Liste anlama, koşullu olarak başka bir sütun oluşturmanın başka bir yoludur. Örneğin örnekte olduğu gibi sütunlardaki nesne dtypes'leriyle çalışıyorsanız, liste kavrayışları diğer yöntemlerin çoğundan daha iyi performans gösterir.

Örnek liste kavrayışı:

df['color'] = ['red' if x == 'Z' else 'green' for x in df['Set']]

% timeit testleri:

import pandas as pd
import numpy as np

df = pd.DataFrame({'Type':list('ABBC'), 'Set':list('ZZXY')})
%timeit df['color'] = ['red' if x == 'Z' else 'green' for x in df['Set']]
%timeit df['color'] = np.where(df['Set']=='Z', 'green', 'red')
%timeit df['color'] = df.Set.map( lambda x: 'red' if x == 'Z' else 'green')

1000 loops, best of 3: 239 µs per loop
1000 loops, best of 3: 523 µs per loop
1000 loops, best of 3: 263 µs per loop

4
Çok daha büyük veri çerçeveleri (düşünmek- pd.DataFrame({'Type':list('ABBC')*100000, 'Set':list('ZZXY')*100000})boyutu) ile, numpy.whereoutpaces map, ancak liste kavrama kralı olduğunu unutmayın (yaklaşık% 50 daha hızlı numpy.where).
blacksite

3
Koşulun birden çok sütundan bilgi alması gerekiyorsa liste anlama yöntemi kullanılabilir mi? Ben böyle bir şey arıyorum (bu işe yaramaz):df['color'] = ['red' if (x['Set'] == 'Z') & (x['Type'] == 'B') else 'green' for x in df]
Mappi

2
Veri çerçevesine yineleme ekleyin, ardından satır üzerinden birden çok sütuna erişebilirsiniz: ['red' if (row ['Set'] == 'Z') & (row ['Type'] == 'B') else 'green 'indeks için, satır içi df.iterrows ()]' da
cheekybastard

1
Veri çerçevesindeki başka bir diziden değiştirme değerleri almanız gerekiyorsa, bu güzel çözümün işe yaramayacağını unutmayın, örneğindf['color_type'] = np.where(df['Set']=='Z', 'green', df['Type'])
Paul Rougieux

@ cheekybastard Ya da, çünkü .iterrows()kötü şöhretli ve DataFrame yineleme sırasında değiştirilmemelidir.
AMC

21

Bunun başarılmasının bir başka yolu da

df['color'] = df.Set.map( lambda x: 'red' if x == 'Z' else 'green')

İyi bir yaklaşım, bu daha hızlı verimlilik (daha büyük veri kümelerinde) için not edilebilir, ancak ek bir adım gerektirir.
Yaakov Bressler

21

Listedeki tuşlara yeni değerleri eşleştirmek için bir sözlük kullanarak bu kedinin derisini almanın başka bir yolu:

def map_values(row, values_dict):
    return values_dict[row]

values_dict = {'A': 1, 'B': 2, 'C': 3, 'D': 4}

df = pd.DataFrame({'INDICATOR': ['A', 'B', 'C', 'D'], 'VALUE': [10, 9, 8, 7]})

df['NEW_VALUE'] = df['INDICATOR'].apply(map_values, args = (values_dict,))

Neye benziyor:

df
Out[2]: 
  INDICATOR  VALUE  NEW_VALUE
0         A     10          1
1         B      9          2
2         C      8          3
3         D      7          4

Bu yaklaşım, yapmak için çok türlü ifelseifadeleriniz olduğunda çok güçlü olabilir (yani, değiştirilecek birçok benzersiz değer).

Ve elbette bunu her zaman yapabilirsiniz:

df['NEW_VALUE'] = df['INDICATOR'].map(values_dict)

Ancak bu yaklaşım, applymakinemde yukarıdakinden üç kat daha yavaştır .

Ve bunu kullanarak dict.getşunları da yapabilirsiniz :

df['NEW_VALUE'] = [values_dict.get(v, None) for v in df['INDICATOR']]

Bu cevabı beğendim çünkü değerlerin birden fazla nasıl değiştirileceğini gösteriyor
Monica Heddneck 21:18

Ancak bu yaklaşım, makinemde yukarıdan uygulama yaklaşımının üç katından daha yavaştır. Bunları nasıl karşılaştırdınız? Hızlı ölçümlerimden, .map()çözüm ~ 10 kat daha hızlı .apply().
AMC

Güncelleme: 100.000.000 satırda, 52 dize değeri, .apply()47 saniye sürer, sadece 5.91 saniye sürer .map().
AMC

19

Aşağıdakiler burada zamanlanan yaklaşımlardan daha yavaştır , ancak birden fazla sütunun içeriğine dayalı olarak ekstra sütunu hesaplayabiliriz ve ekstra sütun için ikiden fazla değer hesaplanabilir.

Yalnızca "Ayarla" sütununu kullanan basit bir örnek:

def set_color(row):
    if row["Set"] == "Z":
        return "red"
    else:
        return "green"

df = df.assign(color=df.apply(set_color, axis=1))

print(df)
  Set Type  color
0   Z    A    red
1   Z    B    red
2   X    B  green
3   Y    C  green

Daha fazla renk ve daha fazla sütun dikkate alınan örnek:

def set_color(row):
    if row["Set"] == "Z":
        return "red"
    elif row["Type"] == "C":
        return "blue"
    else:
        return "green"

df = df.assign(color=df.apply(set_color, axis=1))

print(df)
  Set Type  color
0   Z    A    red
1   Z    B    red
2   X    B  green
3   Y    C   blue

Düzenleme (21/06/2019): plydata kullanma

Kullanımı da mümkündür plydata (bu bile yavaş kullanmaktan daha görünüyor bu tür şeyleri yapmaya assignve applyolsa).

from plydata import define, if_else

Basit if_else:

df = define(df, color=if_else('Set=="Z"', '"red"', '"green"'))

print(df)
  Set Type  color
0   Z    A    red
1   Z    B    red
2   X    B  green
3   Y    C  green

İç içe if_else:

df = define(df, color=if_else(
    'Set=="Z"',
    '"red"',
    if_else('Type=="C"', '"green"', '"blue"')))

print(df)                            
  Set Type  color
0   Z    A    red
1   Z    B    red
2   X    B   blue
3   Y    C  green

10

Belki de Panda'nın yeni güncellemeleriyle bu mümkün olmuştur, ancak şu ana kadar sorunun en kısa ve belki de en iyi cevabı olduğunu düşünüyorum. Sen kullanabilirsiniz .locyöntemi ve kullanımı bir şartla veya birkaç ihtiyaca göre.

Kod Özeti:

df=pd.DataFrame(dict(Type='A B B C'.split(), Set='Z Z X Y'.split()))
df['Color'] = "red"
df.loc[(df['Set']=="Z"), 'Color'] = "green"

#practice!
df.loc[(df['Set']=="Z")&(df['Type']=="B")|(df['Type']=="C"), 'Color'] = "purple"

Açıklama:

df=pd.DataFrame(dict(Type='A B B C'.split(), Set='Z Z X Y'.split()))

# df so far: 
  Type Set  
0    A   Z 
1    B   Z 
2    B   X 
3    C   Y

bir 'renk' sütunu ekleyin ve tüm değerleri "kırmızı" olarak ayarlayın

df['Color'] = "red"

Tek koşulunuzu uygulayın:

df.loc[(df['Set']=="Z"), 'Color'] = "green"


# df: 
  Type Set  Color
0    A   Z  green
1    B   Z  green
2    B   X    red
3    C   Y    red

veya birden fazla koşul istiyorsanız:

df.loc[(df['Set']=="Z")&(df['Type']=="B")|(df['Type']=="C"), 'Color'] = "purple"

Pandas mantıksal işleçlerini ve koşullu seçimi buradan okuyabilirsiniz: Pandas'ta mantıksal indeksleme için mantıksal işleçler


2
Şimdiye kadar en iyisi. Muhtemelen kod daha fazla koşul için ekleyebilirsinizdf.loc[(df['Set']=="Z") & (df['Type']=="A"), 'Color'] = "green"
Salvador Vigo

2
Bu kabul edilen cevap olmalı. Aslında deyimsel ve genişletilebilir.
AMC

1

Yöntemli bir astar .apply()aşağıdaki gibidir:

df['color'] = df['Set'].apply(lambda set_: 'green' if set_=='Z' else 'red')

Bundan sonra, dfveri çerçevesi şöyle görünür:

>>> print(df)
  Type Set  color
0    A   Z  green
1    B   Z  green
2    B   X    red
3    C   Y    red

0

Devasa verilerle çalışıyorsanız, not edilmiş bir yaklaşım en iyisi olacaktır:

# First create a dictionary of manually stored values
color_dict = {'Z':'red'}

# Second, build a dictionary of "other" values
color_dict_other = {x:'green' for x in df['Set'].unique() if x not in color_dict.keys()}

# Next, merge the two
color_dict.update(color_dict_other)

# Finally, map it to your column
df['color'] = df['Set'].map(color_dict)

Tekrarlanan birçok değeriniz olduğunda bu yaklaşım en hızlı olacaktır. Genel kuralım şu durumlarda hatırlamaktır: data_size> 10**4& n_distinct<data_size/4

Ex 2.500 veya daha az farklı değere sahip 10.000 satır içeren bir notu not edin.


Pekala, eşlenecek sadece 2 ayrı değer, 100.000.000 satır ile, "not" olmadan çalışması 6.67 saniye ve ile birlikte 9.86 saniye sürüyor.
AMC

100.000.000 satır, 52 farklı değer, bunlardan 1'i ilk çıkış değerine eşlenir ve diğer 51'in tümü diğerine karşılık gelir: hatırlama olmadan 7.99 saniye, 11.1 saniye ile.
AMC

Değerleriniz rastgele sırada mı? Yoksa arka arkaya mı? Pandaların yüksek hızı önbelleklemeden kaynaklanıyor @AMC
Yaakov Bressler

1
Değerleriniz rastgele sırada mı? Yoksa arka arkaya mı? Değerler rastgele, kullanılarak seçilir random.choices().
AMC
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.