Panda sütunundaki değerleri bir dikte ile yeniden eşleme


318

Ben böyle bir sözlük var: di = {1: "A", 2: "B"}

Ben benzer bir veri çerçevesinin "col1" sütununa uygulamak istiyorum:

     col1   col2
0       w      a
1       1      2
2       2    NaN

almak:

     col1   col2
0       w      a
1       A      2
2       B    NaN

Bunu en iyi nasıl yapabilirim? Bazı nedenlerden dolayı, bununla ilgili googling terimleri bana yalnızca diktlerden sütunlar nasıl yapılacağına ilişkin bağlantıları gösterir:

Yanıtlar:


341

Kullanabilirsiniz .replace. Örneğin:

>>> df = pd.DataFrame({'col2': {0: 'a', 1: 2, 2: np.nan}, 'col1': {0: 'w', 1: 1, 2: 2}})
>>> di = {1: "A", 2: "B"}
>>> df
  col1 col2
0    w    a
1    1    2
2    2  NaN
>>> df.replace({"col1": di})
  col1 col2
0    w    a
1    A    2
2    B  NaN

veya doğrudan Series, yani df["col1"].replace(di, inplace=True).


1
col```` is tuple. The error info is 'Ndarray (dtype = object)' ve 'tuple' 'türlerini karşılaştıramazsam benim için işe yaramaz
Pengju Zhao

18
Bu artık çalışmıyor gibi görünüyor hiç cevap 4 yıl önce oldu verilmiş şaşırtıcı değildir. Operasyonun ne kadar genel olduğu göz önüne alındığında, bu sorunun yeni bir cevaba ihtiyacı var ...
PrestonH

2
@PrestonH Benim için mükemmel çalışıyor. Koşu:'3.6.1 |Anaconda custom (64-bit)| (default, May 11 2017, 13:25:24) [MSC v.1900 64 bit (AMD64)]'
Dan

Benim için çalışıyor. Ancak TÜM sütunlardaki değerleri değiştirmek istersem nasıl olur?
famargar

2
Gösterilen cevaplar için benim için çalışan tek yöntem, Seride doğrudan bir değişiklik yapmaktı. Teşekkürler!
Dirigo

243

map daha hızlı olabilir replace

Sözlüğünüzde birden fazla anahtar varsa, kullanmak mapçok daha hızlı olabilir replace. Sözlüğünüzün olası tüm değerleri kapsamlı bir şekilde eşleyip eşlemediğine (ve aynı zamanda eşleşmeyenlerin değerlerini korumasını veya NaN'lere dönüştürülmesini isteyip istemediğinize bağlı olarak) bu yaklaşımın iki sürümü vardır:

Kapsamlı Haritalama

Bu durumda, form çok basittir:

df['col1'].map(di)       # note: if the dictionary does not exhaustively map all
                         # entries then non-matched entries are changed to NaNs

mapEn yaygın olarak bir işlevi argüman olarak alsa da, alternatif olarak bir sözlük veya seri alabilir: Pandas.series.map belgeleri

Kapsamlı Olmayan Haritalama

Kapsamlı olmayan bir eşlemeniz varsa ve eşleşmeyenler için mevcut değişkenleri korumak istiyorsanız, şunları ekleyebilirsiniz fillna:

df['col1'].map(di).fillna(df['col1'])

@ jpp'ın cevabındaki gibi: Pandalar serisindeki değerleri sözlük aracılığıyla verimli bir şekilde değiştirin

Deneyler

Panda verileri 0.23.1 ile aşağıdaki verileri kullanma:

di = {1: "A", 2: "B", 3: "C", 4: "D", 5: "E", 6: "F", 7: "G", 8: "H" }
df = pd.DataFrame({ 'col1': np.random.choice( range(1,9), 100000 ) })

ve ile test , yaklaşık 10 kat daha hızlı %timeitgörünüyor . mapreplace

İle hızlandırmanızın mapverilerinize göre değişeceğini unutmayın. En büyük hızlanma, büyük sözlükler ve kapsamlı ikameler ile görünüyor. Daha kapsamlı karşılaştırmalar ve tartışma için @jpp yanıtına (yukarıda bağlantılı) bakın.


17
Bu cevap için son kod bloğu kesinlikle en zarif değil, ancak bu cevap biraz krediyi hak ediyor. Büyük sözlükler için daha hızlı büyüklük sıralarıdır ve tüm RAM'imi kullanmaz. Yarım dakikada yaklaşık 9 milyon girişi olan bir sözlük kullanarak 10.000 satırlık bir dosyayı yeniden eşleştirdi. df.replaceFonksiyonu, düzenli ve küçük dicts için yararlı iken, 20 dakika ya da daha çalıştıktan sonra çöktü.
griffinc


@griffinc Geri bildiriminiz için teşekkür ederiz ve bu yanıtı kapsamlı olmayan davayı yapmak için çok daha basit bir yolla güncellediğimi unutmayın (@jpp sayesinde)
JohnE

1
mapaynı zamanda bunu yapmanın bir yolunu bulamadığım bir endeks üzerinde çalışıyorreplace
Max Ghenis

1
@AlexSB Tamamen genel bir cevap veremem, ancak haritanın çok daha hızlı olacağını ve aynı şeyi başaracağını düşünüyorum. Genel olarak, birleştirme aynı şeyi yapan diğer seçeneklerden daha yavaş olacaktır.
JohnE

59

Sorunuzda biraz belirsizlik var. En az üç iki yorum vardır:

  1. anahtarlar didizin değerlerine atıfta bulunur
  2. anahtarlar değerlere diatıfta bulunurdf['col1']
  3. anahtarlar didizin konumlarına atıfta bulunur (OP'nin sorusu değil, eğlenmek için atılır.)

Aşağıda her durum için bir çözüm bulunmaktadır.


Durum 1: tuşlarının didizin değerlerine başvurması gerekiyorsa, updateyöntemi kullanabilirsiniz :

df['col1'].update(pd.Series(di))

Örneğin,

import pandas as pd
import numpy as np

df = pd.DataFrame({'col1':['w', 10, 20],
                   'col2': ['a', 30, np.nan]},
                  index=[1,2,0])
#   col1 col2
# 1    w    a
# 2   10   30
# 0   20  NaN

di = {0: "A", 2: "B"}

# The value at the 0-index is mapped to 'A', the value at the 2-index is mapped to 'B'
df['col1'].update(pd.Series(di))
print(df)

verim

  col1 col2
1    w    a
2    B   30
0    A  NaN

Orijinal yayınınızdaki değerleri değiştirdim, böylece ne updateyaptığı daha net . Anahtarların didizin değerleriyle nasıl ilişkilendirildiğine dikkat edin. Dizin değerlerinin sırası - yani dizin konumları - önemli değildir.


Durum 2: Anahtarlar değerlere diatıfta bulunuyorsa df['col1'], @DanAllan ve @DSM bunun nasıl yapılacağını gösterir replace:

import pandas as pd
import numpy as np

df = pd.DataFrame({'col1':['w', 10, 20],
                   'col2': ['a', 30, np.nan]},
                  index=[1,2,0])
print(df)
#   col1 col2
# 1    w    a
# 2   10   30
# 0   20  NaN

di = {10: "A", 20: "B"}

# The values 10 and 20 are replaced by 'A' and 'B'
df['col1'].replace(di, inplace=True)
print(df)

verim

  col1 col2
1    w    a
2    A   30
0    B  NaN

Bu durumda tuşlar nasıl Not dimaç için değiştirildi değerler içinde df['col1'].


Durum 3: Anahtarlar didizin konumlarına başvuruyorsa,

df['col1'].put(di.keys(), di.values())

dan beri

df = pd.DataFrame({'col1':['w', 10, 20],
                   'col2': ['a', 30, np.nan]},
                  index=[1,2,0])
di = {0: "A", 2: "B"}

# The values at the 0 and 2 index locations are replaced by 'A' and 'B'
df['col1'].put(di.keys(), di.values())
print(df)

verim

  col1 col2
1    A    a
2   10   30
0    B  NaN

Tuşları çünkü Burada, birinci ve üçüncü sıraları, değiştirilmiş diolan 0ve 2Python'un 0 tabanlı indeksleme ile birinci ve üçüncü konumlara işaret hangi.


replaceeşit derecede iyi ve belki de burada olanlar için daha iyi bir kelime.
Dan Allan

OP'nin yayınladığı hedef veri çerçevesi belirsizliği ortadan kaldırmıyor mu? Yine de, bu cevap faydalıdır, bu yüzden +1.
DSM

@DSM: Hata, sen doğru Case3 olasılığı yoktur, ama ben dizin hedef değerleri sütun değerlere eşit olduğundan OP hedef veri çerçevesi Case1'den Case2 ayırt sanmıyorum.
unutbu

Gönderilen diğer birçok kişi gibi, @ DSM'nin yöntemi maalesef benim için işe yaramadı, ancak @ unutbu'nun 1. vakası işe yaradı. update()ile karşılaştırıldığında biraz kludgy gibi görünüyor replace(), ama en azından işe yarıyor.
Geoff

4

Bir veri veri çerçevesinde yeniden eşlenecek birden fazla sütununuz varsa bu soruya ekleme:

def remap(data,dict_labels):
    """
    This function take in a dictionnary of labels : dict_labels 
    and replace the values (previously labelencode) into the string.

    ex: dict_labels = {{'col1':{1:'A',2:'B'}}

    """
    for field,values in dict_labels.items():
        print("I am remapping %s"%field)
        data.replace({field:values},inplace=True)
    print("DONE")

    return data

Umarım birisi için yararlı olabilir.

Şerefe


1
DataFrame.replace()Ne zaman eklendiğini bilmememe rağmen bu işlevsellik zaten sağlanmıştır .
AMC

3

DSM'nin kabul ettiği cevap var, ancak kodlama herkes için işe yaramıyor gibi görünüyor. İşte pandaların mevcut sürümü ile çalışan bir tane (8/2018 itibariyle 0.23.4):

import pandas as pd

df = pd.DataFrame({'col1': [1, 2, 2, 3, 1],
            'col2': ['negative', 'positive', 'neutral', 'neutral', 'positive']})

conversion_dict = {'negative': -1, 'neutral': 0, 'positive': 1}
df['converted_column'] = df['col2'].replace(conversion_dict)

print(df.head())

Göründüğünüz gibi olacak:

   col1      col2  converted_column
0     1  negative                -1
1     2  positive                 1
2     2   neutral                 0
3     3   neutral                 0
4     1  positive                 1

Pandas.DataFrame.replace için dokümanlar burada .


DSM'nin cevabını almakta hiçbir zaman sorun yaşamadım ve çoğu insanın da yapmadığı yüksek oy toplamı göz önüne alındığında tahmin ediyorum. Karşılaştığınız sorun hakkında daha spesifik olmak isteyebilirsiniz. Belki de DSM'lerden farklı örnek verilerinizle ilgisi vardır?
JohnE

Hmm, belki bir versiyon sorunu. Bununla birlikte, her iki cevap da şimdi burada.
wordsforthewise

1
Kabul edilen cevaptaki çözüm sadece belirli türlerde çalışır, Series.map()daha esnek görünüyor.
AMC

2

Veya şunu yapın apply:

df['col1'].apply(lambda x: {1: "A", 2: "B"}.get(x,x))

Demo:

>>> df['col1']=df['col1'].apply(lambda x: {1: "A", 2: "B"}.get(x,x))
>>> df
  col1 col2
0    w    a
1    1    2
2    2  NaN
>>> 

diDikte listelerin bir diktesi olduğunda ne olur ? Listede yalnızca bir değeri nasıl eşleyebilirsiniz?
FaCoffee

Yapabilirsin, ama neden istediğini anlamıyorum.
AMC

2

Verilen map, değiştirilmekten daha hızlıdır (@ JohnE'nin çözümü), belirli değerleri eşlemek istediğiniz Ayrıntılı Olmayan eşlemelerNaN konusunda dikkatli olmanız gerekir . Bu durumda uygun yöntem maskSerileri siz yapmanızı gerektirir .fillna, aksi takdirde eşlemeyi geri alırsınız NaN.

import pandas as pd
import numpy as np

d = {'m': 'Male', 'f': 'Female', 'missing': np.NaN}
df = pd.DataFrame({'gender': ['m', 'f', 'missing', 'Male', 'U']})

keep_nan = [k for k,v in d.items() if pd.isnull(v)]
s = df['gender']

df['mapped'] = s.map(d).fillna(s.mask(s.isin(keep_nan)))

    gender  mapped
0        m    Male
1        f  Female
2  missing     NaN
3     Male    Male
4        U       U

1

Sınıf etiketlerinizin haritasını tutan güzel ve eksiksiz bir çözüm:

labels = features['col1'].unique()
labels_dict = dict(zip(labels, range(len(labels))))
features = features.replace({"col1": labels_dict})

Bu şekilde, herhangi bir noktada label_dict içindeki orijinal sınıf etiketine başvurabilirsiniz.


1

Nico Coallier (birden çok sütuna uygula) ve U10-Forward (yöntemlerin uygulanma stilini kullanarak) tarafından önerilenlerin bir uzantısı olarak ve bunu tek katmanlı olarak özetleyeceğim:

df.loc[:,['col1','col2']].transform(lambda x: x.map(lambda x: {1: "A", 2: "B"}.get(x,x))

.transform()Bir dizi olarak her sütun işler. Bunun aksine, .apply()DataFrame içinde toplanan sütunları geçirir.

Sonuç olarak Seri yöntemini uygulayabilirsiniz map().

Son olarak, U10 sayesinde bu davranışı keşfettim. Serinin tamamını .get () ifadesinde kullanabilirsiniz. Ben davranışını yanlış anlamadım ve dizi bitwisely yerine ardışık olarak işler sürece. Değerleri için hesaplar tarafından aksi Nan olarak düşünülebilir, harita sözlükte söz etmedi yöntemle
.get(x,x).map()


.transform()Bir dizi olarak her sütun işler. Bunun aksine, .apply()DataFrame içinde toplanan sütunları geçirir. Sadece denedim, iyi apply()çalışıyor. Her locikisini de kullanmaya gerek yok, bu çok karmaşık görünüyor. df[["col1", "col2"]].apply(lambda col: col.map(lambda elem: my_dict.get(elem, elem)))iyi çalışmalı. Hesapları değerleri için size tarafından aksi Nan olarak düşünülebilir, harita sözlükte söz etmedi yöntemle de kullanabilirsiniz sonradan. .get(x,x).map()fillna()
AMC

Son olarak, U10 sayesinde bu davranışı keşfettim. Serinin tamamını .get () ifadesinde kullanabilirsiniz. Ben davranışını yanlış anlamadım ve dizi bitwisely yerine sırayla işler sürece.Bunu yeniden üretemem, ayrıntılandırabilir misin? Aynı adlandırılmış değişkenler burada muhtemelen bir rol oynamaktadır.
AMC

0

Daha doğal bir panda yaklaşımı, aşağıdaki gibi bir değiştirme işlevi uygulamaktır:

def multiple_replace(dict, text):
  # Create a regular expression  from the dictionary keys
  regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))

  # For each match, look-up corresponding value in dictionary
  return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text) 

İşlevi tanımladıktan sonra, veri çerçevenize uygulayabilirsiniz.

di = {1: "A", 2: "B"}
df['col1'] = df.apply(lambda row: multiple_replace(di, row['col1']), axis=1)

Daha yerel bir panda yaklaşımı, aşağıdaki gibi bir değiştirme işlevini uygulamaktır. Bu , Pandalar tarafından sağlanan çok daha basit yöntemlerden daha "doğal" (deyimsel?)
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.