Мой вопрос является расширением ответа на который здесь:
Добавление двух фреймов данных pandas
Предполагая те же кадры данных, но с новым столбцом, содержащим строки.
import pandas as pd
df1 = pd.DataFrame([('Dog',1,2),('Cat',3,4),('Rabbit',5,6)], columns=['Animal','a','b'])
df2 = pd.DataFrame([('Dog',100,200),('Cat',300,400),('Rabbit',500,600)], columns=['Animal','a','b']
Использование решения создаст это:
df_add = df1.add(df2, fill_value=0)
Out:
Animal a b
0 DogDog 101 202
1 CatCat 303 404
2 RabbitRabbit 505 606
Потенциальным решением может быть просто индексирование столбца Animal, а затем запуск функции .add и повторная деиндексация столбца Animal. Но есть ли более простой способ просто изменить эту формулу df_add = df1.add(df2, fill_value=0) так, чтобы было дано следующее решение:
Out:
Animal a b
0 Dog 101 202
1 Cat 303 404
2 Rabbit 505 606
Я попробовал df_add.iloc[:,1:] = df1.iloc[:,1:].add(df2.iloc[:,1:], fill_value=0), и это не сработало.
Временная установка ключей в качестве индекса - лучший подход, по моему мнению.
Кроме того, можно ли иметь дублированные ключи на любом входе? Если да, что должно произойти?
Ваш вопрос не совсем ясен. Pandas выполняет операции сложения после выравнивания индексов (индекс + столбцы), поэтому, если вы хотите, чтобы Dog был добавлен в Dog независимо от его позиции, лучше всего установить индекс:
key = ['Animal']
out = df1.set_index(key).add(df2.set_index(key), fill_value=0).reset_index()
Выход:
Animal a b
0 Dog 101 202
1 Cat 303 404
2 Rabbit 505 606
Это гарантирует отсутствие несоответствия. Например:
df1 = pd.DataFrame([('Cat',3,4),('Dog',1,2),('Parrot',8,9)], columns=['Animal','a','b'])
df2 = pd.DataFrame([('Dog',100,200),('Cat',300,400),('Rabbit',800,00)], columns=['Animal','a','b'])
key = ['Animal']
df_add = df1.set_index(key).add(df2.set_index(key), fill_value=0).reset_index()
Выход:
Animal a b
0 Cat 303.0 404.0
1 Dog 101.0 202.0
2 Parrot 8.0 9.0
3 Rabbit 500.0 600.0
Теперь, если ваши DataFrames уже выровнены. Т.е. Животные расположены в том же порядке, а индексы DataFrame идентичны. Вы можете использовать быстрый трюк, чтобы игнорировать столбец «Животное»: установите столбец df2
как пустую строку:
df_add = df1.add(df2.assign(Animal=''))
Выход:
Animal a b
0 Dog 101 202
1 Cat 303 404
2 Rabbit 505 606
Однако это рискованно, если вы не до конца уверены, что индексы животных и DataFrame идентичны.
Спасибо, в моем случае я уверен, что индексы идентичны. Но в целях безопасности я воспользуюсь вашим первым предложением.
Я бы рекомендовал вам сохранить столбцы для ключа и агрегации как отдельные переменные, чтобы код был красивее и гибче:
key_columns = ['Animal']
sum_columns = ['a', 'b']
После этого все, что вам нужно сделать, это объединить фреймы данных и агрегировать их по ключевым столбцам:
pd.concat([df1, df2], ignore_index=True) \
.fillna(0) \
.groupby(key_columns) \
.agg({col: 'sum' for col in sum_columns}) \
.reset_index()
Если вы не хотите перечислять все столбцы в sum_columns
, вы можете вычислить его на основе имен всех столбцов в df1.columns
и key_columns
, например, так:
key_columns = ['Animal']
sum_columns = list(set(df1.columns) - set(key_columns))
Наслаждаться!
PS: fillna(0)
заполняет значения NaN 0, reset_index()
восстанавливает Animal
как столбец, потому что после процедуры groupby...agg
он стал индексом.
Спасибо, я думаю, что это тоже очень полезное решение, мне оно нравится. Единственное, что меня беспокоит, это то, что если у вас есть сценарий, в котором количество столбцов велико (> 10), запись всех имен столбцов в sum_columns может оказаться непрактичной.
@Dinks123 Dinks123 Я отредактировал ответ. Вы можете вычислить имена агрегаций, как уже упоминалось.
что, если бы вместо кролика в
df1
у вас был «Попугай»? Каким должен быть ожидаемый результат?