Проверьте, сколько элементов из списка pandas daframe содержится в столбце

У меня есть dataframe, как это:

 index   customerID    item_tag   orderID    Amount
   0         23            A         1        34.50
   1         55            B         2        11.22
   2         23            A         3         9.34
   3         55            D         4       123.44
   4         55            F         5       231.40

У меня также есть список, содержащий my_list = [ 'A' , 'B' , 'D' ] следующим образом:

my_list

Теперь я хочу проверить, сколько типов элементов my_listбыло заказано каждым клиентом. Например, для клиента 23 это число будет = 1, так как заказчик 23 будет указывать только элемент, помеченный как A, но не B или D. Клиент 55, однако, заказал элементы B и D, поэтому эта переменная индикатора будет равна 2, так как две типы предметов из числа my_listприсутствуют в его заказах. (он также заказал элемент F, но этот предмет не находится в groupby([customerId, item_tag], as_index = False).count()).

До сих пор я пытался , но для этого требуется создать новый dataframe (возможно, не обязательно?), А затем использовать оператор if для каждого элемента в списке, но я подозреваю, что есть более элегантный способ. Я не мог найти ни одного, ни Google, ни здесь. У моей DataFrame есть миллион строк, поэтому я ищу наиболее эффективное решение. index customerID if_A if_B if_D sum_in_list 0 23 1 0 0 1 1 55 0 1 1 2

В результате я хочу, чтобы dataframe выглядел следующим образом:

get_dummies

python,pandas,dataframe,pandas-groupby,

1

Ответов: 3


2 принят

Вот один из способов использования groupby+ : вы получаете счет бесплатно:res = pd.get_dummies(df[['customerID', 'item_tag']], columns=['item_tag']) .groupby(['customerID'], as_index=False).sum() print(res) customerID item_tag_A item_tag_B item_tag_D item_tag_F 0 23 2 0 0 0 1 55 0 1 1 1

L = ['A', 'B', 'D']

df_filtered = df.loc[df['item_tag'].isin(L), ['customerID', 'item_tag']] 

res = pd.get_dummies(df_filtered, columns=['item_tag'])
        .groupby(['customerID']).any().astype(int).reset_index()

res['total_count'] = res.iloc[:, 1:].sum(axis=1)

print(res)

   customerID  item_tag_A  item_tag_B  item_tag_D  total_count
0          23           1           0           0            1
1          55           0           1           1            2

Есть несколько дополнительных шагов, если вы хотите получить двоичный результат и ограничить определенные теги:

wanted = df[df['item_tag'].isin(my_list)]
wanted.groupby(['customerID', 'item_tag'])
      .count().unstack()['Amount'].fillna(0).astype(int)

#item_tag    A  B  D
#customerID         
#23          2  0  0
#55          0  1  1

Мое решение отфильтровывает нежелательные продукты, а затем группирует:

crosstab

Это фильтрованная кросс-таблица, и мы можем увидеть несколько вариантов их выполнения здесь, в ответ на вопрос № 9

Использование clip_upperиpd.crosstab(df.customerID, df.item_tag).clip_upper()[my_list] item_tag A B D customerID 23 1 0 0 55 0 1 1

assign

Добавить, lambdaчтобы получить суммирование при использовании a, чтобы сохранить его в строкеpd.crosstab(df.customerID, df.item_tag).clip_upper(1)[my_list].assign( Total=lambda d: d.sum(1)) item_tag A B D Total customerID 23 1 0 0 1 55 0 1 1 2

pandas.Series

item_tag

Интересная альтернатива с построением нового объекта серии. Я item_tagпострою его таким образом, чтобы разместить s на первом уровне MultiIndex, оставив его удобным для использования locи нарезать теги, которые меня волнуют.

s = pd.Series(1, set(zip(df.item_tag, df.customerID)))
s.loc[my_list].unstack(0, fill_value=0).assign(
    Total=lambda d: d.sum(1))

    A  B  D  Total
23  1  0  0      1
55  0  1  1      2
питон, панды, dataframe, панды-GroupBy,
Похожие вопросы
Яндекс.Метрика