Я пытаюсь выделить именно то, что изменилось между двумя кадрами.
Предположим, у меня есть два кадра данных Python Pandas:
"StudentRoster Jan-1":
id Name score isEnrolled Comment
111 Jack 2.17 True He was late to class
112 Nick 1.11 False Graduated
113 Zoe 4.12 True
"StudentRoster Jan-2":
id Name score isEnrolled Comment
111 Jack 2.17 True He was late to class
112 Nick 1.21 False Graduated
113 Zoe 4.12 False On vacation
Моя цель - вывести таблицу HTML, которая:
- Определяет строки, которые изменились (может быть int, float, boolean, string)
Выводит строки с одинаковыми, старыми и новыми значениями (в идеале в таблицу HTML), чтобы потребитель мог ясно видеть, что изменилось между двумя фреймами данных:
"StudentRoster Difference Jan-1 - Jan-2": id Name score isEnrolled Comment 112 Nick was 1.11| now 1.21 False Graduated 113 Zoe 4.12 was True | now False was "" | now "On vacation"
Я полагаю, я мог бы сделать сравнение строка за строкой и столбец за столбцом, но есть ли более простой способ?
df.compare
.Ответы:
Первая часть похожа на Константина, вы можете получить логическое значение, строки которого пусты *:
Затем мы можем увидеть, какие записи изменились:
Здесь первая запись - это индекс, а вторая - столбцы, которые были изменены.
* Примечание: важно, чтобы
df1
и здесьdf2
использовался тот же индекс. Чтобы преодолеть эту неоднозначность, вы можете убедиться, что вы смотрите только на общие ярлыки, используяdf1.index & df2.index
, но я думаю, что я оставлю это как упражнение.источник
df1
с тем, что находится первымdf2
, независимо от значения индекса. JFYI на случай, если я не единственный человек, для которого это не было очевидно. ; D Спасибо!nan
как в df1, так и в df1, эта функция сообщит, что она изменилась сnan
наnan
. Это потому чтоnp.nan != np.nan
возвращаетсяTrue
.Подчеркивая разницу между двумя фреймами данных
Можно использовать свойство стиля DataFrame, чтобы выделить цвет фона ячеек, где есть разница.
Используя данные примера из исходного вопроса
Первым шагом является объединение DataFrames по горизонтали с
concat
функцией и выделение каждого кадра с помощьюkeys
параметра:Вероятно, проще поменять местами уровни столбцов и поместить одинаковые имена столбцов рядом друг с другом:
Теперь гораздо проще обнаружить различия в кадрах. Но мы можем пойти дальше и использовать это
style
свойство, чтобы выделить разные ячейки. Для этого мы определяем пользовательскую функцию, которую вы можете увидеть в этой части документации .Это будет подсвечивать ячейки, которые имеют пропущенные значения. Вы можете либо заполнить их, либо предоставить дополнительную логику, чтобы они не выделялись.
источник
df_final[(df != df2).any(1)].style.apply(highlight_diff, axis=None)
Этот ответ просто расширяет @Andy Hayden, делая его устойчивым к числовым полям
nan
, и превращая его в функцию.Итак, с вашими данными (слегка отредактировано, чтобы иметь NaN в столбце оценки):
Вывод:
источник
печать
источник
id
в качестве индекса,df.groupby(level='id')
возникает ошибка, и я не уверен, почему ...Я столкнулся с этой проблемой, но нашел ответ, прежде чем найти этот пост:
На основании ответа unutbu загрузите ваши данные ...
... определить вашу функцию сравнения ...
Затем вы можете просто использовать Panel для вывода:
Кстати, если вы находитесь в IPython Notebook, вы можете использовать цветную функцию сравнения, чтобы задавать цвета в зависимости от того, являются ли ячейки разными, равными или левыми / правыми нулевыми:
источник
my_panel = pd.Panel(dict(df1=df1,df2=df2))
внутри функцииreport_diff()
? Я имею в виду, возможно ли сделать это:print report_diff(df1,df2)
и получить тот же вывод, что и ваш оператор печати?pd.Panel(dict(df1=df1,df2=df2)).apply(report_diff, axis=0)
- это круто!!!Если ваши два кадра данных имеют одинаковые идентификаторы, то выяснить, что изменилось, довольно просто. Простое выполнение
frame1 != frame2
даст вам логический DataFrame, где каждыйTrue
является данными, которые изменились. Исходя из этого, вы можете легко получить индекс каждой измененной строки, выполнивchangedids = frame1.index[np.any(frame1 != frame2,axis=1)]
.источник
Другой подход с использованием concat и drop_duplicates:
Вывод:
источник
После возни с ответом @ journois, я смог заставить его работать, используя MultiIndex вместо Panel из-за ограничения Panel .
Сначала создайте фиктивные данные:
Затем определите свою функцию сравнения , в этом случае я буду использовать ту, которая из его ответа
report_diff
останется прежней:Затем я собираюсь объединить данные в фрейм данных MultiIndex:
И, наконец, я собираюсь применить
report_diff
вниз каждой группы столбцов:Это выводит:
И это все!
источник
Расширение ответа @cge, что довольно круто для большей читабельности результата:
Полный демонстрационный пример:
источник
Вот еще один способ с помощью выбора и слияния:
Вот то же самое из скриншота Jupyter:
источник
панды> = 1.1:
DataFrame.compare
С pandas 1.1 вы можете по существу реплицировать вывод Теда Петру одним вызовом функции. Пример взят из документации:
Здесь «self» относится к фрейму данных LHS, а «other» - к фрейму данных RHS. По умолчанию равные значения заменяются на NaN, поэтому вы можете сосредоточиться только на различиях. Если вы хотите показать значения, которые также равны, используйте
Вы также можете изменить ось сравнения, используя
align_axis
:Это сравнивает значения по строкам, а не по столбцам.
источник
Функция, которая находит несимметричное различие между двумя фреймами данных, реализована ниже: (на основе разницы в наборах для панд ) GIST: https://gist.github.com/oneryalcin/68cf25f536a25e65f0b3c84f9c118e03
Пример:
источник
импортировать панд как pd импортировать numpy как np
df = pd.read_excel ('D: \ HARISH \ DATA SCIENCE \ 1 MY Training \ SAMPLE DATA & projs \ CRICKET DATA \ СПИСОК ИГРОКОВ IPL \ СПИСОК ИГРОКОВ IPL _ harish.xlsx')
df1 = srh = df [df ['TEAM']. str.contains ("SRH")] df2 = csk = df [df ['TEAM']. str.contains ("CSK")]
srh = srh.iloc [:, 0: 2] csk = csk.iloc [:, 0: 2]
csk = csk.reset_index (drop = True) csk
srh = srh.reset_index (drop = True) srh
new = pd.concat ([srh, csk], axis = 1)
new.head ()
** ТИП ИГРОКА ТИП ИГРОКА
0 Дэвид Уорнер Бэтсмен ... М.С. Дони Капитан
1 Бхуванешвар Кумар Боулер ... Ravindra Jadeja All-Rounder
2 Маниш Пандей Бэтсмен ... Суреш Райна, универсал
3 Рашид-хан Арман Боулер ... Кедар Джадхав Универсал
4 Shikhar Dhawan Batsman .... Dwayne Bravo All-Rounder
источник