Проверьте, сколько элементов из списка pandas daframe содержится в столбце - PullRequest
0 голосов
/ 24 июня 2018

У меня есть такой фрейм данных:

 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

У меня также есть список, содержащий теги item_tag:

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

Теперь я хочу проверить, сколько типов элементов из my_list заказывал каждый покупатель.Например, для клиента 23 это число будет равно 1, поскольку клиент 23 заказывает только товар, помеченный как A, но не B или D. Однако клиент 55 заказал товары B и D, поэтому эта переменная индикатора будет равна 2, как дваТипы предметов из my_list присутствуют в его заказах.(он также заказал элемент F, но этот элемент отсутствует в my_list.)для каждого элемента в списке, но я подозреваю, что есть более элегантный способ.Я не смог найти ни одного, ни в Google, ни здесь.Мой фрейм данных содержит миллион строк, поэтому я ищу наиболее эффективное решение.

В результате я хочу фрейм данных, подобный этому:

 index   customerID   if_A  if_B  if_D  sum_in_list
   0         23         1     0    0        1
   1         55         0     1    1        2

Ответы [ 3 ]

0 голосов
/ 24 июня 2018

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

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
0 голосов
/ 24 июня 2018

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

Использование crosstab и 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, чтобы держать его в строке

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 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
0 голосов
/ 24 июня 2018

Вот один из способов, используя get_dummies + 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...