Scalanie pand - jak uniknąć powielania kolumn

93

Próbuję połączyć dwie ramki danych. Każda ramka danych ma dwa poziomy indeksu (data, cusip). Na przykład niektóre kolumny w kolumnach pasują do tych dwóch (waluta, data dostosowania).

Jaki jest najlepszy sposób na scalenie ich według indeksu, ale nie należy brać dwóch kopii waluty i daty dostosowania.

Każda ramka danych ma 90 kolumn, więc staram się unikać pisania wszystkiego ręcznie.

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

Jeśli zrobię:

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

dostaję

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

Dziękuję Ci! ...

user1911092
źródło

Odpowiedzi:

143

Możesz opracować kolumny, które znajdują się tylko w jednej ramce DataFrame i użyć tego do wybrania podzbioru kolumn w scalaniu.

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

Następnie wykonaj scalanie (zauważ, że jest to obiekt indeksu, ale ma przydatną tolist()metodę).

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

Pozwoli to uniknąć kolizji kolumn podczas scalania.

EdChum
źródło
Co jeśli klucz jest kolumną i nazywa się tak samo? Zostanie porzucony przy pierwszym kroku.
Guerra
Dziękuję bardzo!!!
Cloudy_Green
88

Korzystam z suffixesopcji w .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)

Dzięki @ijoseph

rprog
źródło
15
Bardziej pomocna byłaby odpowiedź, gdyby zawierała kod do filteringerencji (co jest dość proste, ale wciąż czasochłonne, aby wyszukać / zapamiętać błędy). tj. dfNew.drop(list(dfNew.filter(regex='_y$')), axis=1, inplace=True)
ijoseph
5

Jestem nowy w Pandach, ale chciałem osiągnąć to samo, automatycznie unikając nazw kolumn z _x lub _y i usuwając zduplikowane dane. I wreszcie zrobił to za pomocą tej odpowiedzi i ten jeden z Stackoverflow

sales.csv

    miasto; stan; jednostki
    Mendocino; CA; 1
    Denver; CO; 4
    Austin; TX; 2

przychody.csv

    identyfikator_ oddziału; miasto; przychody; identyfikator_stanu
    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 importuj pandy

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=';')

Wykonując polecenie merge, zastępuję _xsufiks pustym ciągiem i mogę usunąć kolumny kończące się na_y

output.csv

    identyfikator; miasto; stan; jednostki; identyfikator_ oddziału; przychód; identyfikator_stanu
    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
źródło
3

Opierając się na odpowiedzi @ rprog, możesz połączyć różne fragmenty kroku sufiksu i filtra w jedną linię za pomocą negatywnego wyrażenia regularnego:

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

Lub za pomocą df.join:

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

Wyrażenie regularne tutaj zachowuje wszystko, co nie kończy się słowem „DROP”, więc po prostu upewnij się, że używasz sufiksu, który nie pojawia się jeszcze wśród kolumn.

Elliott Collins
źródło