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

user1911092
quelle

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.

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

rprog
quelle
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
JulienD
quelle
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.

Elliott Collins
quelle