Мне нужно сравнить два кадра данных с разными столбцами и найти различия между ними.
Хотя этот пример является числовым, мои данные — нет, я использую его как образец набора данных.
import pandas as pd
# Sample DataFrames
ProdDF = pd.DataFrame({'Project.name': ['Project A', 'Project B', 'Project C', 'Project D'],
'Line identifier': [1, 2, 3, 4],
'Column1': [10, 20, 30, 40],
'Column2': [100, 200, 300, 400]})
TestDF = pd.DataFrame({'Project.name': ['Project A', 'Project B', 'Project C', 'Project E'],
'Line identifier': [1, 2, 3, 5],
'Column1': [10, 20, 35, 45],
'Column2': [100, 200, 350, 450],
'Column3': [100, 200, 350, 450]})
key_columns = ['Project.name', 'Line identifier']
# Merge DataFrames on key columns
merged_df = pd.merge(ProdDF, TestDF, on=key_columns, how='outer', suffixes=('_Prod',
'_Test'))
print(merged_df)
output = pd.DataFrame(columns=['Row', 'Column', 'Misaligned Data'])
for index, row in merged_df.iterrows():
for column in merged_df.columns:
if column not in key_columns:
prod_column = column + '_Prod'
test_column = column + '_Test'
if prod_column in merged_df.columns and test_column in merged_df.columns:
if row[prod_column] != row[test_column]:
output = output.append({'Row': index, 'Column': column, 'Misaligned Data': (row[prod_column], row[test_column])}, ignore_index=True)
print(output)
Это дает мне следующий результат:
Project.name Line identifier Column1_Prod Column2_Prod Column1_Test Column2_Test
Column3
0 Project A 1 10.0 100.0 10.0 100.0
100.0
1 Project B 2 20.0 200.0 20.0 200.0
200.0
2 Project C 3 30.0 300.0 35.0 350.0
350.0
Я хотел бы, чтобы результат был:
Project.Name, Line identifier Prod Test
Project C 3 30 35
Project A 1 100 NaN
Project A 2 200 NaN
Project A 3 250 NaN
Я ищу только различия между кадрами данных.
Вместо этого вы можете изменить свой цикл, сравнивая столбцы из кадра данных Prod, чтобы найти различия с merged_df.
formatted_output = []
for index, row in merged_df.iterrows():
# compare columns from ProdDF
for column in ProdDF.columns.difference(key_columns):
prod_column = column + '_Prod'
test_column = column + '_Test'
# Check if both columns are in the merged DataFrame
if prod_column in merged_df.columns or test_column in merged_df.columns:
prod_value = row[prod_column] if prod_column in merged_df.columns else None
test_value = row[test_column] if test_column in merged_df.columns else None
# compare to find differences
if prod_value != test_value:
formatted_output.append({
'Project.Name': row['Project.name'],
'Line identifier': row['Line identifier'],
'Prod': prod_value,
'Test': test_value
})
output_df = pd.DataFrame(formatted_output)
# sort by 'Project.Name' and 'Line identifier'
output_df = output_df.sort_values(by=['Project.Name', 'Line identifier'])
# print DataFrame with formatted output
print(output_df)
import pandas as pd
idx = ['Project.name', 'Line identifier']
keys = ('Prod', 'Test')
comp = (pd.concat([df.set_index(idx) for df in [ProdDF, TestDF]],
axis=0,
join='inner',
keys=keys
)
.unstack(0)
.swaplevel(axis=1)
.pipe(lambda df: df[keys[0]]
.compare(df[keys[1]],
result_names=keys
)
)
)
Выход:
Column1 Column2
Prod Test Prod Test
Project.name Line identifier
Project C 3 30.0 35.0 300.0 350.0
Project D 4 40.0 NaN 400.0 NaN
Project E 5 NaN 45.0 NaN 450.0
Чтобы соответствовать конкретному формату вашего вопроса, добавьте:
comp.stack(0).droplevel(-1).reset_index()
Project.name Line identifier Prod Test
0 Project C 3 30.0 35.0
1 Project C 3 300.0 350.0
2 Project D 4 40.0 NaN
3 Project D 4 400.0 NaN
4 Project E 5 NaN 45.0
5 Project E 5 NaN 450.0
Объяснение / Промежуточные продукты
idx
(ваш «key_columns») в качестве индекса для вашего dfs
с помощью df.set_index.axis=0
.
join='inner'
отбрасывает столбцы не общие.keys=keys
отслеживает источник («Prod» или «Test»).# pd.concat(...)
Column1 Column2
Project.name Line identifier
Prod Project A 1 10 100
Project B 2 20 200
Project C 3 30 300
Project D 4 40 400
Test Project A 1 10 100
Project B 2 20 200
Project C 3 35 350
Project E 5 45 450
keys
уровень индекса (0
) в столбцы, и поменяйте местами уровни с помощью df.swaplevel, чтобы сделать его верхним уровнем MultiIndex:# pd.concat(...).unstack(0).swaplevel(axis=1)
Prod Test Prod Test
Column1 Column1 Column2 Column2
Project.name Line identifier
Project A 1 10.0 10.0 100.0 100.0
Project B 2 20.0 20.0 200.0 200.0
Project C 3 30.0 35.0 300.0 350.0
Project D 4 40.0 NaN 400.0 NaN
Project E 5 NaN 45.0 NaN 450.0
df.compare
между «Prod» (df[keys[0]]
) и «Test» (df[keys[1]]
).
result_names=keys
гарантирует, что в результате будут использоваться эти имена, а не значения по умолчанию «self» и «other».
После добавления formatted_output = [] сверху, это потрясающе, чем вы так много