Pandas — Сравнение двух фреймов данных и поиск строк, которые изменились

#pandas

#pandas

Вопрос:

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

Снимок 1:

 prod_id, prod_name, sale, price_per_unit
prod_a, prod_name_a, 10, 20
prod_b, prod_name_b, 4, 3
prod_c, prod_name_c, 3, 10
prod_d, prod_name_d, 5, 4
  

Снимок 2:

 prod_id, prod_name, sale, price_per_unit
prod_a, prod_name_a, 10, 20
prod_b, prod_name_b, 14, 13
prod_c, prod_name_c, 5, 1
prod_d, prod_name_d, 7, 2
  

Я пытаюсь сравнить их и вернуть обратно строки, которые изменились.

Ожидаемый результат:

 prod_id, prod_name, sale, price_per_unit, source
prod_b, prod_name_b, 4, 3, snapshot_1
prod_b, prod_name_b, 14, 13, snapshot_2
prod_c, prod_name_c, 3, 10, snapshot_1
prod_c, prod_name_c, 5, 1, snapshot_2
prod_d, prod_name_d, 5, 4, snapshot_1
prod_d, prod_name_d, 7, 2, snapshot_2
  

Ответ №1:

Вы можете сравнить все значения по DataFrame.ne и DataFrame.any (необходим одинаковый индекс и одинаковые столбцы в обоих фреймах данных), а затем использовать concat с новыми столбцами по DataFrame.assign , отсортировать и создать последний индекс по умолчанию:

 mask = df1.ne(df2).any(axis=1)

df = pd.concat([df1[mask].assign(source = 'snapshot_1'), 
                df2[mask].assign(source = 'snapshot_2')]
       ).sort_index().reset_index(drop=True)

print (df)
  prod_id    prod_name  sale  price_per_unit      source
0  prod_b  prod_name_b     4               3  snapshot_1
1  prod_b  prod_name_b    14              13  snapshot_2
2  prod_c  prod_name_c     3              10  snapshot_1
3  prod_c  prod_name_c     5               1  snapshot_2
4  prod_d  prod_name_d     5               4  snapshot_1
5  prod_d  prod_name_d     7               2  snapshot_2
  

Комментарии:

1. спасибо, что сработало. Однако, если строка пуста в обоих фреймах данных для одного и того же столбца, она извлекает обе эти строки, тогда как на самом деле она не должна извлекать это как разницу в значениях.. В любом случае, мы можем добавить это к приведенному выше коду..

2. @scottmartin — да, тогда используй хитрость — замени на те же значения неправильные значения — mask = df1.fillna(0).ne(df2.fillna(0)).any(axis=1)