Как избежать слияния в Pandas

У меня есть фрейм данных, который выглядит так:

Я хочу сгруппировать фрейм данных по #PROD и #CURRENCY и заменить TP содержимым оффшорных данных в столбце Loc, не создавая два фрейма данных и не объединяя их.

Окончательный результат будет выглядеть примерно так:

Мне удалось создать выходные данные, разделив фрейм данных на два (оншорный и оффшорный), а затем создав объединение #PROD и #CURRENCY. Однако мне было интересно, есть ли более чистый способ сделать это?

Код для Dataframe:

import pandas as pd
data=[['Offshore','NY','A','USD','ABC_USD'],['Onshore','BH','A','USD',''],                  ['Onshore','AE','A','USD',''],\
     ['Offshore','NY','A','GBP','GBP_ABC'],['Onshore','BH','A','GBP',''],                           ['Onshore','AE','A','GBP',''],\
     ['Onshore','BH','A','EUR',''],['Onshore','AE','A','EUR','']]

df = pd.DataFrame(data, columns=['Loc', 'Country','#PROD','#CURRENCY','TP'])
df

Открыто заново: потому что нам нужно фильтровать, где находится LocOffshore, а не просто получать значение TP.

U13-Forward 18.06.2024 13:10

Я думаю, что merge — самый верный и чистый подход. Не нужно ни сортировать данные, ни беспокоиться о побочных эффектах groupby.

mozway 18.06.2024 13:23
Почему в 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
2
68
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Вы можете использовать это:

df["TP"] = (
    df.sort_values("Loc")  # ensure Offshore comes before Onshore
    .replace("", np.nan)  # replace "" with nan so it can be forward filled
    .groupby(["#PROD", "#CURRENCY"])["TP"]
    .ffill()
    .fillna("")
)
        Loc Country #PROD #CURRENCY       TP
0  Offshore      NY     A       USD  ABC_USD
1   Onshore      BH     A       USD  ABC_USD
2   Onshore      AE     A       USD  ABC_USD
3  Offshore      NY     A       GBP  GBP_ABC
4   Onshore      BH     A       GBP  GBP_ABC
5   Onshore      AE     A       GBP  GBP_ABC
6   Onshore      BH     A       EUR         
7   Onshore      AE     A       EUR         

Вы можете использовать groupby, затем transform, чтобы получить значение first столбца TP, где Loc соответствует Offshore.

Я заранее сортирую DataFrame, чтобы значения Offshore были выше значений Onshore.

Пытаться:

df['TP'] = (
    df.sort_values('Loc')
    .groupby(['#PROD', '#CURRENCY'])['TP']
    .transform('first')
    )
print(df)

Выход:

        Loc Country #PROD #CURRENCY       TP
0  Offshore      NY     A       USD  ABC_USD
1   Onshore      BH     A       USD  ABC_USD
2   Onshore      AE     A       USD  ABC_USD
3  Offshore      NY     A       GBP  GBP_ABC
4   Onshore      BH     A       GBP  GBP_ABC
5   Onshore      AE     A       GBP  GBP_ABC
6   Onshore      BH     A       EUR         
7   Onshore      AE     A       EUR  
Ответ принят как подходящий

Я думаю, что слияние — самый простой и эффективный способ сделать это:

df['TP'] = df[cols].merge(df[df['Loc'].eq('Offshore')], how='left')['TP'].values

Не нужно сортировать, не нужно беспокоиться о том, какие значения присутствуют изначально.

Альтернативно:

cols = ['#PROD', '#CURRENCY']
s = (df[cols].reset_index().merge(df[df['Loc'].eq('Offshore')])
     .set_index('index')['TP']
    )
df.loc[s.index, 'TP'] = s

Выход:

        Loc Country #PROD #CURRENCY       TP
0  Offshore      NY     A       USD  ABC_USD
1   Onshore      BH     A       USD  ABC_USD
2   Onshore      AE     A       USD  ABC_USD
3  Offshore      NY     A       GBP  GBP_ABC
4   Onshore      BH     A       GBP  GBP_ABC
5   Onshore      AE     A       GBP  GBP_ABC
6   Onshore      BH     A       EUR      NaN
7   Onshore      AE     A       EUR      NaN

Общее решение, которое будет работать для любого количества переменных, можно получить, используя что-то вроде этого:

group_variables = ["#PROD", "#CURRENCY"]
target_variable = "TP"
groups = df.groupby(group_variables)
for location, value in groups[target_variable].apply(lambda x: "".join(x)).items():
    condition = pd.concat([df[var].eq(v) for var, v in zip(group_variables, location)], axis=1).all(axis=1)
    df.loc[condition, (target_variable)] = value

Выход:

        Loc Country #PROD #CURRENCY       TP
0  Offshore      NY     A       USD  ABC_USD
1   Onshore      BH     A       USD  ABC_USD
2   Onshore      AE     A       USD  ABC_USD
3  Offshore      NY     A       GBP  GBP_ABC
4   Onshore      BH     A       GBP  GBP_ABC
5   Onshore      AE     A       GBP  GBP_ABC
6   Onshore      BH     A       EUR         
7   Onshore      AE     A       EUR      

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