Добавление двух фреймов данных pandas вместе — отдельные столбцы

Мой вопрос является расширением ответа на который здесь:

Добавление двух фреймов данных 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), и это не сработало.

что, если бы вместо кролика в df1 у вас был «Попугай»? Каким должен быть ожидаемый результат?

mozway 01.08.2024 10:30

Временная установка ключей в качестве индекса - лучший подход, по моему мнению.

mozway 01.08.2024 10:34

Кроме того, можно ли иметь дублированные ключи на любом входе? Если да, что должно произойти?

mozway 01.08.2024 10:39
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
3
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Ваш вопрос не совсем ясен. 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 идентичны.

Спасибо, в моем случае я уверен, что индексы идентичны. Но в целях безопасности я воспользуюсь вашим первым предложением.

Dinks123 01.08.2024 11:06

Я бы рекомендовал вам сохранить столбцы для ключа и агрегации как отдельные переменные, чтобы код был красивее и гибче:

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 01.08.2024 11:15

@Dinks123 Dinks123 Я отредактировал ответ. Вы можете вычислить имена агрегаций, как уже упоминалось.

Fomalhaut 01.08.2024 11:35

Другие вопросы по теме