Pandas Слева Outer Join результаты в таблице больше, чем левая таблица
Из того, что я понимаю о левом внешнем соединении, в результирующей таблице никогда не должно быть больше строк, чем в левой таблице... Пожалуйста, дайте мне знать, если это неправильно...
Моя левая таблица - 192572 строки и 8 столбцов.
Моя правая таблица - 42160 строк и 5 столбцов.
В моей левой таблице есть поле с именем 'id', которое соответствует столбцу в моей правой таблице с именем 'key'.
Поэтому я объединять их как таковые:
combined = pd.merge(a,b,how='left',left_on='id',right_on='key')
Но тогда объединенная форма 236569.
Что я не понимаю?
Ответы
Ответ 1
Вы можете ожидать, что это увеличится, если ключи соответствуют более одной строке в другом 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
Ответ 2
Есть также стратегии, которые вы можете использовать, чтобы избежать такого поведения, которое не предполагает потерю дублированных данных, если, например, не все столбцы дублируются. Если у вас есть
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, отбросьте переменные count в 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() или что-то еще может позволить для других приложений.
Наконец, если это тот случай, когда только в одном наборе данных есть дубликаты, но вы все еще хотите их сохранить, вы можете использовать первую половину последней стратегии, чтобы дифференцировать дубликаты в результате слияния.
Ответ 3
Небольшое дополнение к данным ответам заключается в том, что существует параметр с именем validate, который можно использовать для выдачи ошибки, если в правой таблице совпадают идентификаторы:
combined = pd.merge(a,b,how='left',left_on='id',right_on='key', validate = 'm:1')