Сопоставить значения от 1 столбца до другого столбца, если он существует при группировке по идентификатору - PullRequest
1 голос
/ 10 июля 2019

У меня есть датафрейм, который выглядит следующим образом.

s_id  h_id   h_val  h_others
1      600     5    {700,500}
1      700     12   {600,500,400}
1      500     6    {600,700}
2     ...     ...    ...

То, что я хочу сделать, - при группировании по s_id итерировать по h_others, посмотреть, найден ли каждый идентификатор в словарях в h_id для этого конкретного s_id.Если он найден, я хочу отобразить его значение, которое можно найти в h_val, сложить их и создать новый столбец с суммой сопоставленных значений h_others.Если он не найден, идентификатор можно просто сопоставить с 0, чтобы он не влиял на сумму.

Ожидаемый результат:

s_id  h_id   h_val  h_others       sum_h_others
1      600     5    {700,500}       18     
1      700     12   {600,500,400}   11
1      500     6    {600,700}       17     
2     ...     ...    ...

Ответы [ 2 ]

1 голос
/ 10 июля 2019

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

import pandas as pd
import ast
from io import StringIO
df = pd.read_table(StringIO("""s_id  h_id   h_val  h_others
1      600     5    {700,500}
1      700     12   {600,500,400}
1      500     6    {600,700}"""), sep='\s+')

summs = []
for s_id, s in list(zip(df.s_id, df.h_others.values)):
    df['sum_h_others'] = 0
    summ = 0
    for d in ast.literal_eval(s):
        try:
            summ += sum(df.loc[df['s_id'] == s_id].loc[(df['h_id'] == d), 'h_val'].values)
        except IndexError:
            pass
    summs.append(summ)
df['sum_h_others'] = summs

Выход:

   s_id  h_id  h_val       h_others  sum_h_others
0     1   600      5      {700,500}            18
1     1   700     12  {600,500,400}            11
2     1   500      6      {600,700}            17
1 голос
/ 10 июля 2019

Давайте заимствуем функцию unnesting у @ WeNYoBen , но немного изменим ее, чтобы она работала с вашими сетами.Затем расчет может быть выполнен с помощью слияния.

from itertools import chain 

def unnesting(df, explode):
    idx = df.index.repeat(df[explode[0]].str.len())
    df1 = pd.concat([
        pd.DataFrame({x: [*chain.from_iterable(df[x].to_numpy())]}) for x in explode], axis=1)
    df1.index = idx

    return df1.join(df.drop(explode, 1), how='left')

df1 = unnesting(df, explode=['h_others'])

s = (df1.reset_index().merge(df.reset_index(), 
                             left_on=['h_others', 's_id'], 
                             right_on=['h_id', 's_id'])
         .query('index_x != index_y')
         .groupby('index_x').h_val_y.sum())

df['sum_h_others'] = s

Вывод:

   s_id  h_id  h_val         h_others  sum_h_others
0     1   600      5       {700, 500}            18
1     1   700     12  {600, 500, 400}            11
2     1   500      6       {600, 700}            17

Более простой вариант - отобразить после unnesting, но применение делает это медленнее:

d = {(k1, k2): v for k1, k2, v in zip(*df[['s_id', 'h_id', 'h_val']].to_numpy().T)}
#{(1, 500): 6, (1, 600): 5, (1, 700): 12}

df['sum_h_others'] = df1[['s_id', 'h_others']].apply(tuple, 1).map(d).groupby(level=0).sum()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...