У меня есть два фрейма данных dfA и dfB:
dfA =
entityId entityName property value
0 1 bob propA a
1 1 bob propB b
2 1 bob propC c
3 2 dave propA aa
4 2 dave propC c
5 3 bob propA a
6 3 bob propB bb
7 3 bob propD d
8 4 alex propE ee
9 4 alex propF fff
dfB =
entityId entityValid property value propValid propId
0 123 yes propA a yes 1
1 123 yes propB b yes 2
2 123 yes propC c yes 3
3 124 no propA aa no 4
4 124 no propC c yes 3
5 125 not sure propA a yes 1
6 125 not sure propB bb yes 5
7 125 not sure propD d yes 6
8 126 no propE ee yes 7
9 126 no propF FF yes 8
Я хотел бы знать, есть ли то, что сущности в dfA являются точными совпадениями с сущностями в dfB в терминах столбцов свойств и значений.
Будет ли наиболее целесообразно разблокировать кадры данных и сначала выразить каждую сущность в одной строке? Конечный результат, который я искал, будет таким, как будто это, однако, любой вклад о том, как подойти к проблеме, оценен.
resultDf =
entityId entityName dfBEntityIdMatch valid invalidProps
0 1 bob 123 yes ()
1 2 dave 124 no (4)
2 3 bob 125 not sure ()
3 4 alex '---' '---' '---'
Заранее спасибо.
Код для создания данных:
import pandas as pd
pd.set_option('display.max_columns',20)
dfA = pd.DataFrame([[1, 'bob', 'propA', 'a'],
[1, 'bob', 'propB', 'b' ],
[1, 'bob', 'propC', 'c' ],
[2, 'dave', 'propA', 'aa' ],
[2, 'dave', 'propC', 'c' ],
[3, 'bob', 'propA', 'a' ],
[3, 'bob', 'propB', 'bb' ],
[3, 'bob', 'propD', 'd' ],
[4, 'alex', 'propE', 'ee' ],
[4, 'alex', 'propF', 'fff' ]],
columns=['entityId', 'entityName', 'property', 'value'])
dfB = pd.DataFrame([[123, 'yes', 'propA', 'a', 'yes', 1],
[123, 'yes', 'propB', 'b', 'yes', 2],
[123, 'yes', 'propC', 'c', 'yes', 3],
[124, 'no', 'propA', 'aa', 'no', 4],
[124, 'no', 'propC', 'c', 'yes', 3],
[125, 'not sure', 'propA', 'a', 'yes', 1 ],
[125, 'not sure', 'propB', 'bb', 'yes', 5 ],
[125, 'not sure', 'propD', 'd', 'yes', 6 ],
[126, 'no', 'propE', 'ee', 'yes', 7],
[126, 'no', 'propF', 'FF', 'yes', 8 ]],
columns=['entityId', 'entityValid', 'property', 'value', 'propValid', 'propId'])
вот один из способов получить что-то похожее на ваш ожидаемый результат, по крайней мере, на данные, которые вы предоставляете. Сначала создайте столбец "invalidProps" в dfB
dfB.loc[dfB['propValid'] == 'no','invalidProps'] = dfB.loc[dfB['propValid'] == 'no','propId']
dfB['invalidProps'] = dfB['invalidProps'].fillna('')
Теперь вы можете использовать groupby
как groupby
независимо, так и agg
с различными методами. Вам нужно sort_values
по свойствам и "значению", если ваши реальные данные не находятся в одном и том же порядке между dataframe
dfA_g = (dfA.sort_values(['property', 'value'])
.groupby(['entityId','entityName'],as_index=False).agg(tuple))
dfB_g = (dfB.sort_values(['property', 'value'])
.groupby(['entityId','entityValid'],as_index=False)
.agg({'property':lambda x: tuple(x),
'value':lambda x: tuple(x),
'invalidProps':lambda x: tuple(filter(None,x))}))
Теперь вы можете merge
с "свойством" и "значением" и использовать fillna
для замены значений nan, drop
ненужные столбцы и rename
одну из них:
resultDf = (dfA_g.merge(dfB_g, how='left', on=['property', 'value'],suffixes=('','_'))
.fillna('---').drop(['property', 'value'],1)
.rename(columns={'entityId_':'dfBEntityIdMatch', 'entityValid':'valid'}))
и вы получите что-то вроде:
entityId entityName dfBEntityIdMatch valid invalidProps
0 1 bob 123 yes ()
1 2 dave 124 no (4.0,)
2 3 bob 125 not sure ()
3 4 alex --- --- ---