Pandas лівий зовнішній приєднати результати в таблиці більше, ніж ліва таблиця


80

З того, що я розумію про ліве зовнішнє з'єднання, отримана таблиця ніколи не повинна мати більше рядків, ніж ліва таблиця ... Будь ласка, дайте мені знати, якщо це неправильно ...

Моя ліва таблиця - 192572 рядки та 8 стовпців.

Моя права таблиця - 42160 рядків і 5 стовпців.

У моїй лівій таблиці є поле "id", яке відповідає стовпцю в моїй правій таблиці під назвою "key".

Тому я зливаю їх як такі:

combined = pd.merge(a,b,how='left',left_on='id',right_on='key')

Але тоді комбінована форма - 236569.

Що я нерозумію?


Чи можете ви розмістити деякі мінімальні дані, що це демонструють (будь ласка, не всі 200 тис.)?
Paul H

@PaulH проблема полягає в тому, що я не можу знайти причину, за якою це робиться ... коли я використовую це pd.mergeна невеликому розділі коду, отримана таблиця насправді має лише розмір лівої таблиці
Terence Chow

Відповіді:


117

Ви можете очікувати, що це збільшиться, якщо ключі збігаються з кількома рядками в іншому DataFrame:

In [11]: df = pd.DataFrame([[1, 3], [2, 4]], columns=['A', 'B'])

In [12]: df2 = pd.DataFrame([[1, 5], [1, 6]], columns=['A', 'C'])

In [13]: df.merge(df2, how='left')  # merges on columns A
Out[13]: 
   A  B   C
0  1  3   5
1  1  3   6
2  2  4 NaN

Щоб уникнути такої поведінки, скиньте дублікати в df2:

In [21]: df2.drop_duplicates(subset=['A'])  # you can use take_last=True
Out[21]: 
   A  C
0  1  5

In [22]: df.merge(df2.drop_duplicates(subset=['A']), how='left')
Out[22]: 
   A  B   C
0  1  3   5
1  2  4 NaN

Чи є спосіб це придушити? У вашому прикладі мені не потрібно бачити рядок 0 або 1, а лише один із цих 2 рядків ...
Теренс Чоу

1
@Chowza так, скиньте дублікати, відредаговану відповідь, щоб це відобразити.
Andy Hayden,

1
Просто FYI, cols зараз застарілий. Натомість використовуйте 'підмножину': df.merge (df2.drop_duplicates (subset = ['A']), how = 'left')
SummerEla

3
@SummerEla Дякую! Я дійсно мав би пройти всі мої запитання та виправити припинення роботи (повинен мати можливість це зробити) ...
Енді Хейден,

3
Щойно зрозумів, що якщо ви робите це для внутрішнього об’єднання, а не для лівого, вам потрібно видалити дублікати в обох кадрах даних відповідно до цієї відповіді.
кардамон

7

Існують також стратегії, які ви можете використовувати, щоб уникнути такої поведінки, яка не передбачає втрати дубльованих даних, якщо, наприклад, не всі стовпці дублюються. Якщо у вас є

In [1]: df = pd.DataFrame([[1, 3], [2, 4]], columns=['A', 'B'])

In [2]: df2 = pd.DataFrame([[1, 5], [1, 6]], columns=['A', 'C'])

Одним із способів було б взяти середнє значення дубліката (також можна взяти суму тощо ...)

In [3]: df3 = df2.groupby('A').mean().reset_index()

In [4]: df3
Out[4]: 
     C
A     
1  5.5

In [5]: merged = pd.merge(df,df3,on=['A'], how='outer')

In [6]: merged
Out[204]: 
   A  B    C
0  1  3  5.5
1  2  4  NaN

Крім того, якщо у вас є нечислові дані, які неможливо перетворити за допомогою pd.to_numeric (), або якщо ви просто не хочете брати середнє, ви можете змінити змінну злиття, перерахувавши дублікати. Однак ця стратегія застосовуватиметься, коли дублікати існують в обох наборах даних (що може спричинити однакову проблемну поведінку, а також є загальною проблемою):

In [7]: df = pd.DataFrame([['a', 3], ['b', 4],['b',0]], columns=['A', 'B'])

In [8]: df2 = pd.DataFrame([['a', 3], ['b', 8],['b',5]], columns=['A', 'C'])

In [9]: df['count'] = df.groupby('A')['B'].cumcount()

In [10]: df['A'] = np.where(df['count']>0,df['A']+df['count'].astype(str),df['A'].astype(str))

In[11]: df
Out[11]: 
    A  B  count
0   a  3      0
1   b  4      0
2  b1  0      1

Зробіть те ж саме для df2, опустіть змінні підрахунку в df і df2 і об'єднайте в 'A':

In [16]: merged
Out[16]: 
    A  B  C
0   a  3  3        
1   b  4  8        
2  b1  0  5        

Пара приміток. У цьому останньому випадку я використовую .cumcount () замість .duplicated, оскільки може бути так, що у вас є більше одного дубліката для даного спостереження. Крім того, я використовую .astype (str) для перетворення значень підрахунку в рядки, оскільки я використовую команду np.where (), але використання pd.concat () або щось інше може дозволити різні програми.

Нарешті, якщо випадок є, що лише в одному наборі даних є дублікати, але ви все одно хочете зберегти їх, тоді ви можете використовувати першу половину останньої стратегії, щоб диференціювати дублікати в результаті злиття.


4

Невеликим доповненням до поданих відповідей є те, що існує параметр з іменем validate, який можна використовувати для видалення помилки, якщо в правій таблиці є дубльовані ідентифікатори:

combined = pd.merge(a,b,how='left',left_on='id',right_on='key', validate = 'm:1')
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.