Как эффективно сравнить два кадра данных и получить значение столбца на основе условия

data1 = {
    'alias_cd': ['12345', '12345', '12345'],
    'country_cd': ['AU', 'AU', 'AU2'],
    'pos_name': ['st1', 'Jh', 'Jh'],
    'ts_allocated': [100, 100, 100],
    'tr_id': ['None', 'None', 'None'],
    'ty_name': ['E2E', 'E2E', 'E2E']
}

data2 = {
    'alias_cd': ['12345', '12345'],
    'country_cd': ['AU', 'AU3'],
    'pos_name': ['st1', 'st2'],
    'ts_allocated': [200, 100],
    'tr_id': ['None', 'None'],
    'ty_name': ['E2E', 'E2E']
}

df1 = pd.DataFrame(data1)
df2 = pd.DataFrame(data2)

вывод должен быть

   alias_cd country_cd pos_name  ts_allocated          tr_id    ty_name  etl_flag
1  12345            AU  st1      200                   None      E2E     U
2  12345           AU3  st2      100                   None      E2E     D
3  12345            AU  st1      100                   None      E2E     I
4  12345            AU  Jh       100                   None      E2E     I
5  12345           AU2  Jh       100                   None      E2E     I

Потому что:

Комбинация alias_cd и Country_cd действует как первичный ключ.

1. Если комбинация существует в df2 и df1 (12345 AU), она будет помечена как «Обновить» в df2, а все соответствующие строки в df1 для той же комбинации будут отмечены как «Вставить». в приведенном выше примере для записей 12345 AU в df2 будет etl_flag= «Обновить» и добавить записи для той же комбинации от df1 до df2 с etl_flag как «Вставить».

2.12345 AU3 существует в df2, но не в df1, поэтому в столбце etl_flag он будет помечен как «DELETE».

3. Любая новая комбинация, которая появляется в df1 и отсутствует в df2, будет помечена как «Вставка» в столбце etl_flag.

Как я могу достичь этого эффективно? Это то, что я пробовал, но он не дает правильного вывода:

df2['etl_flag'] = 'U'

to_insert = df1[~df1.apply(lambda x: (df2['alias_cd'] == x['alias_cd']) & (df2['country_cd'] == x['country_cd']), axis=1)]
to_insert['etl_flag'] = 'I'
df2 = pd.concat([df2, to_insert], ignore_index=True)

to_delete = df2[~df2.apply(lambda x: (df1['alias_cd'] == x['alias_cd']) & (df1['country_cd'] == x['country_cd']), axis=1)]
to_delete['etl_flag'] = 'D'

final_df = pd.concat([df2, to_delete], ignore_index=True)
final_df.sort_values(by=['alias_cd', 'country_cd'], inplace=True)

print(final_df[['alias_cd', 'country_cd', 'pos_name', 'ts_allocated', 'tr_id', 'ty_name', 'etl_flag']])

логика неясна, почему 12345/AU2 присвоен I?

mozway 22.06.2024 12:58

@mozway 12345/AU2 будет «I», потому что этого нет в df2, это новая комбинация.

ista120 22.06.2024 13:15

Хорошо, значит, любая строка в df1 всегда будет иметь I

mozway 22.06.2024 13:26
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
3
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

IIUC, вы можете сначала выполнить слияние слева-с включенным индикатором df2, чтобы определить статус U/D, а затем конкат. df1 всегда получает I:

# columns used as primary key
cols = ['alias_cd', 'country_cd']

out = pd.concat(
    [df2.assign(etl_flag=df2.merge(df1[cols].drop_duplicates(),
                                   on=cols, how='left', indicator=True)
                ['_merge'].map({'left_only': 'D', 'both': 'U'})
                .values),
     df1.assign(etl_flag='I')]
)

Выход:

  alias_cd country_cd pos_name  ts_allocated tr_id ty_name etl_flag
0    12345         AU      st1           200  None     E2E        U
1    12345        AU3      st2           100  None     E2E        D
0    12345         AU      st1           100  None     E2E        I
1    12345         AU       Jh           100  None     E2E        I
2    12345        AU2       Jh           100  None     E2E        I

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