Pandas Merge - So vermeiden Sie das Duplizieren von Spalten


93

Ich versuche eine Zusammenführung zwischen zwei Datenrahmen. Jeder Datenrahmen hat zwei Indexebenen (Datum, Cusip). In den Spalten stimmen einige Spalten beispielsweise zwischen den beiden überein (Währung, Einstellungsdatum).

Was ist der beste Weg, um diese nach Index zusammenzuführen, aber nicht zwei Kopien der Währung und des Adj-Datums zu nehmen.

Jeder Datenrahmen besteht aus 90 Spalten, daher versuche ich zu vermeiden, dass alles von Hand geschrieben wird.

df:                 currency  adj_date   data_col1 ...
date        cusip
2012-01-01  XSDP      USD      2012-01-03   0.45
...

df2:                currency  adj_date   data_col2 ...
date        cusip
2012-01-01  XSDP      USD      2012-01-03   0.45
...

Wenn ich mache:

dfNew = merge(df, df2, left_index=True, right_index=True, how='outer')

Ich bekomme

dfNew:              currency_x  adj_date_x   data_col2 ... currency_y adj_date_y
date        cusip
2012-01-01  XSDP      USD      2012-01-03   0.45             USD         2012-01-03

Vielen Dank! ...

Antworten:


143

Sie können die Spalten berechnen, die sich nur in einem DataFrame befinden, und damit eine Teilmenge der Spalten in der Zusammenführung auswählen.

cols_to_use = df2.columns.difference(df.columns)

Führen Sie dann die Zusammenführung durch (beachten Sie, dass dies ein Indexobjekt ist, aber eine praktische tolist()Methode hat).

dfNew = merge(df, df2[cols_to_use], left_index=True, right_index=True, how='outer')

Dadurch wird vermieden, dass Spalten beim Zusammenführen zusammenstoßen.


Was ist, wenn der Schlüssel eine Spalte ist und derselbe heißt? Es würde mit dem ersten Schritt fallen gelassen werden.
Guerra

ich danke dir sehr!!!
Cloudy_Green vor

87

Ich benutze die suffixesOption in .merge():

dfNew = df.merge(df2, left_index=True, right_index=True,
                 how='outer', suffixes=('', '_y'))
dfNew.drop(dfNew.filter(regex='_y$').columns.tolist(),axis=1, inplace=True)

Danke @ijoseph


15
Wäre eine hilfreichere Antwort, wenn sie den Code für filtering enthalten würde (was ziemlich einfach ist, aber dennoch zeitaufwändig nachzuschlagen / fehleranfällig, um sich zu erinnern). dh dfNew.drop(list(dfNew.filter(regex='_y$')), axis=1, inplace=True)
ijoseph

5

Ich bin frisch mit Pandas, aber ich wollte das Gleiche erreichen, indem ich Spaltennamen mit _x oder _y automatisch vermeide und doppelte Daten entferne. Ich habe es schließlich durch diese mit Antwort und diese eine von Stackoverflow

sales.csv

    Stadt, Staat, Einheiten
    Mendocino, CA, 1
    Denver, CO, 4
    Austin, TX, 2

Revenue.csv

    branch_id; Stadt; Einnahmen; state_id
    10; Austin; 100; TX
    20; Austin; 83; TX
    30; Austin; 4; TX
    47; Austin; 200; TX
    20; Denver; 83; CO
    30; Springfield; 4; I.

merge.py Pandas importieren

def drop_y(df):
    # list comprehension of the cols that end with '_y'
    to_drop = [x for x in df if x.endswith('_y')]
    df.drop(to_drop, axis=1, inplace=True)


sales = pandas.read_csv('data/sales.csv', delimiter=';')
revenue = pandas.read_csv('data/revenue.csv', delimiter=';')

result = pandas.merge(sales, revenue,  how='inner', left_on=['state'], right_on=['state_id'], suffixes=('', '_y'))
drop_y(result)
result.to_csv('results/output.csv', index=True, index_label='id', sep=';')

Wenn ich den Zusammenführungsbefehl ausführe, ersetze ich das _xSuffix durch eine leere Zeichenfolge und kann Spalten entfernen, die mit enden_y

output.csv

    id; Stadt; Bundesland; Einheiten; Zweig-ID; Einnahmen; Bundesland-ID
    0; Denver; CO; 4; 20; 83; CO
    1; Austin; TX; 2; 10; 100; TX
    2; Austin; TX; 2; 20; 83; TX
    3; Austin; TX; 2; 30; 4; TX
    4; Austin; TX; 2; 47; 200; TX

3

Aufbauend auf der Antwort von @ rprog können Sie die verschiedenen Teile des Suffix- und Filterschritts mit einem negativen regulären Ausdruck in einer Zeile kombinieren:

dfNew = df.merge(df2, left_index=True, right_index=True,
             how='outer', suffixes=('', '_DROP')).filter(regex='^(?!.*_DROP)')

Oder mit df.join:

dfNew = df.join(df2),lsuffix="DROP").filter(regex="^(?!.*DROP)")

Der reguläre Ausdruck hier behält alles bei, was nicht mit dem Wort "DROP" endet. Verwenden Sie daher nur ein Suffix, das nicht bereits in den Spalten angezeigt wird.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.