it-swarm.com.de

Ordnen Sie die Werte in der Pandasäule einem Dikt zu

Ich habe ein Wörterbuch, das so aussieht: di = {1: "A", 2: "B"}

Ich würde es gerne auf die Spalte "col1" eines Datenrahmens anwenden, ähnlich:

     col1   col2
0       w      a
1       1      2
2       2    NaN

bekommen:

     col1   col2
0       w      a
1       A      2
2       B    NaN

Wie kann ich das am besten machen? Aus einigen Gründen zeigt das Durchsuchen von Googeln nur Links, wie man Spalten aus Diktaten bildet und umgekehrt: - / 

180
TheChymera

Sie können .replace verwenden. Zum Beispiel:

>>> 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

oder direkt auf der Series , d. h. df["col1"].replace(di, inplace=True).

211
DSM

map kann viel schneller sein als replace

Wenn Ihr Wörterbuch mehr als ein paar Schlüssel enthält, kann die Verwendung von map viel schneller als replace sein. Es gibt zwei Versionen dieses Ansatzes, abhängig davon, ob Ihr Wörterbuch alle möglichen Werte erschöpfend abbildet (und auch, ob nicht übereinstimmende Werte beibehalten oder in NaNs konvertiert werden sollen):

Erschöpfendes Mapping

In diesem Fall ist das Formular sehr einfach:

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

Obwohl map am häufigsten eine Funktion als Argument verwendet, kann sie alternativ ein Wörterbuch oder eine Serie verwenden: Dokumentation für Pandas.series.map

Nicht erschöpfendes Mapping

Wenn Sie ein nicht erschöpfendes Mapping haben und die vorhandenen Variablen für Nichtübereinstimmungen beibehalten möchten, können Sie fillna hinzufügen:

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

wie in @ jpps Antwort hier: Werte in einer Pandaserie effizient über Wörterbuch ersetzen

Benchmarks

Verwendung der folgenden Daten mit Pandas Version 0.23.1:

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 ) })

und mit %timeit zu testen, scheint map etwa 10x schneller zu sein als replace

Beachten Sie, dass Ihre Beschleunigung mit map von Ihren Daten abhängt. Die größte Beschleunigung scheint mit großen Wörterbüchern und erschöpfenden Ersetzungen zu sein. Weitere ausführliche Benchmarks und Diskussionen finden Sie unter @jpp answer (oben verlinkt).

95
JohnE

In Ihrer Frage ist ein bisschen mehrdeutig. Es gibt zumindest drei zwei interpretationen:

  1. die Schlüssel in di beziehen sich auf Indexwerte
  2. die Schlüssel in di beziehen sich auf df['col1']-Werte
  3. die Schlüssel in di beziehen sich auf Indexpositionen (nicht auf die Frage des OPs, sondern nur zum Spaß.)

Nachfolgend finden Sie eine Lösung für jeden Fall.


Fall 1: Wenn die Schlüssel von di auf Indexwerte verweisen sollen, können Sie die update-Methode verwenden:

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

Zum Beispiel,

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)

erträge

  col1 col2
1    w    a
2    B   30
0    A  NaN

Ich habe die Werte Ihres ursprünglichen Posts so geändert, dass klarer ist, was update macht . Beachten Sie, wie die Schlüssel in di Indexwerten zugeordnet werden. Die Reihenfolge der Indexwerte - dh der Index locations - spielt keine Rolle.


Fall 2: Wenn sich die Schlüssel in di auf df['col1']-Werte beziehen, zeigen @DanAllan und @DSM, wie dies mit replace zu erreichen ist:

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)

erträge

  col1 col2
1    w    a
2    A   30
0    B  NaN

Beachten Sie, wie in diesem Fall die Schlüssel in di so geändert wurden, dass sie mit values ​​ in df['col1'] übereinstimmen.


Fall 3: Wenn sich die Schlüssel in di auf Indexpositionen beziehen, können Sie verwenden

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

schon seit

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)

erträge

  col1 col2
1    A    a
2   10   30
0    B  NaN

Hier wurden die erste und die dritte Zeile geändert, da die Schlüssel in di0 und 2 sind, die sich bei der 0-basierten Python-Indexierung auf die erste und dritte Position beziehen.

51
unutbu

Hinzufügen zu dieser Frage, wenn in einem Datenframe mehr als eine Spalte neu zugeordnet werden muss:

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

Ich hoffe es kann für jemanden nützlich sein.

Prost

3
Nico Coallier

DSM hat die akzeptierte Antwort, aber die Kodierung scheint nicht für jeden zu funktionieren. Hier ist eine Version, die mit der aktuellen Version von Pandas funktioniert (0.23.4 Stand 8/2018):

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())

Sie werden sehen wie es aussieht:

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

Die Dokumente für pandas.DataFrame.replace sind hier .

1
wordsforthewise

Oder 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
>>> 
0
U9-Forward

Ein nativerer Pandas-Ansatz besteht darin, eine Ersetzungsfunktion wie folgt anzuwenden:

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) 

Nachdem Sie die Funktion definiert haben, können Sie sie auf Ihren Datenrahmen anwenden.

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

Eine nette Komplettlösung, die eine Karte Ihrer Klassenbeschriftungen enthält:

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

Auf diese Weise können Sie jederzeit auf die ursprüngliche Klassenbezeichnung von labels_dict verweisen.

0
dorien