Получите уникальные значения из столбца одного фрейма данных и используйте их для фильтрации строк в другом фрейме данных.

Я хочу использовать один столбец в df1 как фильтр на df2:

df1 = [('Client', ['A', 'A', 'A', 'B', 'C', 'D', 'D',]),
                    ('Num_Trades', ['1', '2', '3', '1', '1', '1', '1',])
      ]

df1 = pd.DataFrame.from_items(df1)
display(df1)

    Client  Num_Trades
0   A       1
1   A       2
2   A       3
3   B       1
4   C       1
5   D       1
6   D       1

Теперь извлеките уникальных клиентов из df1:

mask_array = df1.Client.unique()
mask_array = dataframe=pd.DataFrame(mask_array, columns=['Client']) 
# mask_list = df1['Client'].unique().tolist()
# mask_list = dataframe=pd.DataFrame(mask_list, columns=['Client']) 
display(mask_array)

    Client
0   A
1   B
2   C
3   D

Пример фрейма данных для фильтрации:

df2 = [('Client', ['A', 'B', 'A', 'Y',]),
('Product', ['GOVT', 'GOVT', 'GOVT', 'GOVT',]),
('currency_str', ['USD', 'GBP', 'USD', 'NZD',]),
('Amount', ['10', '20', '30', '40',]),
         ]
# create pandas df
df2 = pd.DataFrame.from_items(df2)
display(df2)


        Client  Product currency_str    Amount
0       A       GOVT    USD             10
1       B       GOVT    GBP             20
2       A       GOVT    USD             30
3       Y       GOVT    NZD             40

Желаемый результат - это просто сумма всех строк по Amount, где клиент существует в df1:

Client  Product currency_str    Amount
A       GOVT    USD             40
B       GOVT    GBP             20

Мой код создает объекты DataFrame изменяемые, поэтому они не могут быть хешированы. Я также пробовал использовать массив и список. Итак, что нужно сделать с уникальным набором записей, чтобы их можно было использовать в качестве фильтра для df2?

d = [ 
        ('Amount', 'sum')     
    ] 

# aggregate 
mask = df2['Client'].str.contains(mask_list) 
df2 = df2[mask].groupby(['Client','Product','currency_str'])['Amount'].agg(d).reset_index()
display(df2)
1
0
113
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Вы можете использовать join с | для регулярного выражения OR, если нужен фильтр по подстрокам:

mask = df2['Client'].str.contains('|'.join(df1.Client.unique()))

Или используйте isin, если хотите фильтровать по значениям:

mask = df2['Client'].isin(df1.Client.unique())

df2['Amount'] = df2['Amount'].astype(int)
df2 = df2[mask].groupby(['Client','Product','currency_str'])['Amount'].agg(d).reset_index()
print(df2)
  Client Product currency_str  Amount
0      A    GOVT          USD      40
1      B    GOVT          GBP      20

Спасибо, @jezrael! работающий. Быстрый вопрос, чтобы я мог передать в маску список, массив или фрейм данных? Проблема была в сильной сумме?

Peter Lucas 26.10.2018 08:33

@PeterLucas - смотря что нужно, но 1d массив, список серий должен работать нормально. DataFrame проблематичен, необходимо выбрать один столбец (Series) или сгладить значения до серии или массива 1d

jezrael 26.10.2018 08:37

У меня это работает. Я заметил, что сумма на самом деле является строкой, поэтому в идеале ее необходимо преобразовать перед groupby. Если вы не можете преобразовать здесь мое решение:

Создайте список уникальных клиентов df1:

df1['Client'].unique()

array(['A', 'B', 'C', 'D'], dtype=object)

Затем используйте его для фильтрации df2 в столбце Client

df2[
    df2['Client'].isin(df1['Client'].unique())
]

Теперь добавьте groupby и lambda для работы с суммами строк:

df2[
    df2['Client'].isin(df1['Client'].unique())
].groupby(['Client','Product','currency_str'])['Amount'].apply(lambda x: sum([np.int(x) for x in x.values]))

Client  Product  currency_str
A       GOVT     USD             40
B       GOVT     GBP             20
Name: Amount, dtype: int64

NB:

apply(lambda x: sum([np.int(x) for x in x.values]))

делает следующее. Каждое значение в столбце amount конвертируется в int через np.int и сохраняется в списке. Затем сумма вносится в этот список. Пример: Для клиента A: groupby возвращает суммы «10» и «30», но вы не можете суммировать строки. Так что конвертируйте индивидуально, а затем примените sum ().

Добавлять:

.to_frame('Amount').reset_index()


    Client  Product     currency_str    Amount
0   A       GOVT        USD             40
1   B       GOVT        GBP             20

Согласовано. Просто имейте в виду, что .agg (d) для меня не суммирует строки.

user319436 26.10.2018 08:55

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