Pandas Merge - Как избежать дублирования столбцов


93

Я пытаюсь объединить два фрейма данных. Каждый фрейм данных имеет два уровня индекса (дата, cusip). В столбцах некоторые столбцы совпадают между двумя (например, валюта, дата корректировки).

Как лучше всего объединить их по индексу, но не брать две копии валюты и даты корректировки.

Каждый фрейм данных состоит из 90 столбцов, поэтому я стараюсь не писать все вручную.

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

Если я сделаю:

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

я получил

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

Спасибо! ...

Ответы:


143

Вы можете определить столбцы, которые находятся только в одном DataFrame, и использовать это для выбора подмножества столбцов при слиянии.

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

Затем выполните слияние (обратите внимание, что это объект индекса, но у него есть удобный tolist()метод).

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

Это позволит избежать столкновения столбцов при слиянии.


Что, если ключом является столбец и называется он так же? Это было бы отброшено с первого шага.
Герра

большое спасибо!!!
Cloudy_Green

88

Я использую suffixesопцию в .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)

Спасибо @ijoseph


15
Было бы более полезным ответом, если бы он включал код для filtering (который довольно прост, но все же требует времени для поиска / запоминания с возможностью ошибок). ie dfNew.drop(list(dfNew.filter(regex='_y$')), axis=1, inplace=True)
ijoseph

5

Я новичок в Pandas, но я хотел добиться того же, автоматически избегая имен столбцов с _x или _y и удаляя повторяющиеся данные. Я , наконец , сделал это, используя этот ответ , и этот один из Stackoverflow

sales.csv

    город; государство; единицы
    Мендосино; Калифорния; 1
    Денвер; Колорадо; 4
    Остин; Техас; 2

доход.csv

    Branch_id; city; доход; state_id
    10; Остин; 100; Техас
    20; Остин; 83; Техас
    30; Остин; 4; Техас
    47; Остин; 200; Техас
    20; Денвер; 83; CO
    30; Спрингфилд; 4; I

merge.py импорт панд

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

При выполнении команды слияния я заменяю _xсуффикс пустой строкой и могу удалить столбцы, заканчивающиеся на_y

output.csv

    id; город; штат; единицы; branch_id; доход; state_id
    0; Денвер; CO; 4; 20; 83; CO
    1; Остин; Техас; 2; 10; 100; Техас
    2; Остин; Техас; 2; 20; 83; Техас
    3; Остин; Техас; 2; 30; 4; Техас
    4; Остин; Техас; 2; 47; 200; Техас

3

Основываясь на ответе @rprog, вы можете объединить различные части шага суффикса и фильтра в одну строку, используя отрицательное регулярное выражение:

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

Или используя df.join:

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

Регулярное выражение здесь сохраняет все, что не заканчивается словом «DROP», поэтому просто убедитесь, что вы используете суффикс, который еще не появляется среди столбцов.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.