Panda’s samenvoegen – Hoe dubbele kolommen voorkomen

Ik probeer twee dataframes samen te voegen. Elk dataframe heeft twee indexniveaus (datum, cusip). In de kolommen komen sommige kolommen overeen tussen de twee (valuta, adj date) bijvoorbeeld.

Wat is de beste manier om deze samen te voegen op index, maar om geen twee kopieën van valuta en adj-datum te nemen.

Elk dataframe is 90 kolommen, dus ik probeer te voorkomen dat ik alles met de hand uitschrijf.

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

Als ik dat doe:

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

Ik krijg

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

Bedankt!


Antwoord 1, autoriteit 100%

U kunt de kolommen berekenen die zich slechts in één DataFrame bevinden en dit gebruiken om een ​​subset van kolommen in de samenvoeging te selecteren.

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

Voer vervolgens de samenvoeging uit (merk op dat dit een indexobject is, maar het heeft een handige tolist()-methode).

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

Hiermee wordt voorkomen dat kolommen tijdens het samenvoegen met elkaar botsen.


Antwoord 2, autoriteit 76%

Ik gebruik de optie suffixesin .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)

Bedankt @ijoseph


Antwoord 3, autoriteit 8%

Voortbouwend op het antwoord van @rprog, kunt u de verschillende delen van het achtervoegsel & filter stap in één regel met een negatieve regex:

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

Of gebruik df.join:

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

De regex hier houdt alles bij dat nieteindigt met het woord “DROP”, dus zorg ervoor dat u een achtervoegsel gebruikt dat niet al in de kolommen voorkomt.


Antwoord 4, autoriteit 3%

Ik ben net nieuw met Panda’s, maar ik wilde hetzelfde bereiken door automatisch kolomnamen met _x of _y te vermijden en dubbele gegevens te verwijderen. Ik heb het eindelijk gedaan door dit antwoorden dit eenvan Stackoverflow

sales.csv

stad;staat;eenheden
  Mendocino;CA;1
  Denver; CO;4
  Austin;TX;2

opbrengst.csv

branch_id;city;inkomsten;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
panda’s importeren

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

Bij het uitvoeren van de samenvoegopdracht vervang ik het achtervoegsel _xdoor een lege tekenreeks en kan ik kolommen verwijderen die eindigen op _y

output.csv

id;stad;staat;eenheden;filiaal-id;omzet;staat_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

Antwoord 5

Dit is een beetje om het probleem heen, maar ik heb een functie geschreven die in feite de extra kolommen behandelt:

def merge_fix_cols(df_company,df_product,uniqueID):
    df_merged = pd.merge(df_company,
                         df_product,
                         how='left',left_on=uniqueID,right_on=uniqueID)    
    for col in df_merged:
        if col.endswith('_x'):
            df_merged.rename(columns = lambda col:col.rstrip('_x'),inplace=True)
        elif col.endswith('_y'):
            to_drop = [col for col in df_merged if col.endswith('_y')]
            df_merged.drop(to_drop,axis=1,inplace=True)
        else:
            pass
    return df_merged

Het lijkt goed te werken met mijn samenvoegingen!


Antwoord 6

Kun je niet eerst de kolommen in een van beide df subsetten?

[i for i in df.columns if i not in df2.columns]
dfNew = merge(df **[i for i in df.columns if i not in df2.columns]**, df2, left_index=True, right_index=True, how='outer')

Antwoord 7

Als het aantal kolommen dat u wilt vermijden lager is dan het aantal kolommen dat u wilt behouden… kunt u dit soort filtering gebruiken:

df.loc[:, ~df.columns.isin(['currency', 'adj_date'])]

Hiermee worden alle kolommen in het dataframe gefilterd, behalve de kolommen ‘currency’ en ‘adj_date’, u moet de samenvoeging ongeveer als volgt schrijven:

   dfNew = merge(df, 
                  df2.loc[:, ~df.columns.isin(['currency', 'adj_date'])], 
                  left_index=True,
                  right_index=True,
                  how='outer')

Let op de “~”, dit betekent “niet”.


Antwoord 8

U kunt dubbele kolommen opnemen in de sleutel waarop u wilt samenvoegen om ervoor te zorgen dat er slechts één kopie in het resultaat verschijnt.

# Generate some dummy data.
shared = pd.DataFrame({'key': range(5), 'name': list('abcde')})
a = shared.copy()
a['value_a'] = np.random.normal(0, 1, 5)
b = shared.copy()
b['value_b'] = np.random.normal(0, 1, 5)
# Standard merge.
merged = pd.merge(a, b, on='key')
print(merged.columns)  # Index(['key', 'name_x', 'value_a', 'name_y', 'value_b'], dtype='object')
# Merge with both keys.
merged = pd.merge(a, b, on=['key', 'name'])
print(merged.columns)  # Index(['key', 'name', 'value_a', 'value_b'], dtype='object')

Deze methode zorgt er ook voor dat waarden in kolommen die in beide dataframes voorkomen, consistent zijn (bijvoorbeeld dat de valuta in beide kolommen hetzelfde is). Als dit niet het geval is, wordt de corresponderende rij verwijderd (if how = 'inner') of voorkomen met ontbrekende waarden (if how = 'outer').

Other episodes