Pandas Группировка по заданному c значению столбца - PullRequest
1 голос
/ 03 мая 2020

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

Ticket ID   User    Date        Category
1926        a       1/1/2020    cat_7
1947        a       1/1/2020    cat_6
1901        c       1/2/2020    cat_7
1067        a       1/3/2020    cat_1
1683        a       1/4/2020    cat_3
1281        a       1/4/2020    cat_3
1561        a       1/5/2020    cat_5
1932        a       1/5/2020    cat_5
1234        c       1/5/2020    cat_6
1013        c       1/7/2020    cat_7
1575        b       1/9/2020    cat_8
1152        b       1/10/2020   cat_4
1235        c       1/10/2020   cat_7
1596        b       1/11/2020   cat_4
1523        c       1/11/2020   cat_1
1447        b       1/12/2020   cat_4
1576        b       1/12/2020   cat_5
1260        c       1/13/2020   cat_2
1556        b       1/15/2020   cat_5
1838        b       1/16/2020   cat_5
1182        b       1/17/2020   cat_5

В этот ожидаемый результат:

User    Category 1  Next Category   Count
a       cat_1       cat_3           2
                    cat_5           2
b       cat_1       cat_4           3
                    cat_5           4
c       cat_1       cat_2           1

Я не уверен, что указанное c значение из столбца можно извлечь и использовать для группировки действий, произошедших после cat_1

Моя неудачная попытка:

df.groupby(["User", "Category"])["Ticket ID"].count()

Что привело к на это:

User  Category    Count
a     cat_1       1
      cat_3       2
      cat_5       2
      cat_6       1
      cat_7       1
b     cat_1       1
      cat_4       3
      cat_5       4
c     cat_1       1
      cat_2       1
      cat_6       1
      cat_7       3
      cat_8       1

1 Ответ

2 голосов
/ 03 мая 2020

Вы можете попробовать:

def f(x):
    x = x.reset_index(drop=True)
    return x.iloc[x[x["Category"].eq('cat_1')].index[0]+1:]

df.groupby("User")\
    .apply(f) \
    .reset_index(drop=True) \
    .groupby(["User", "Category"]) \
    .agg({"Ticket ID": "count"}) \
    .assign(Category_1="cat_1") \
    .set_index("Category_1", append=True)\
    .reorder_levels([0, 2, 1])

Пояснения :

Существует два основных шага:

  • Для каждого User group, удалить строки перед первым cat_1 значением категории
  • Вычислить count для каждого ["User", "Category"]

Шаги:

  1. Сгруппируйте набор данных по столбцу "User", используя groupby
  2. Отфильтруйте все строки, чтобы выбрать только строки после первого вхождения cat_1 с помощью функции f.

    1. Сначала сбросьте индекс, используя reset_index.
    2. Выберите индекс первой строки cat_1, используя x[x["Category"].eq('cat_1')].index[0]
    3. Добавить +1 к индексу из предыдущего шага, так как нам не нужна строка cat_1.
    4. Использование iloc для нарезки строк перед индексом, определенным на шаге 2.3.
  3. Удалите избыточный индекс User с помощью reset_index и drop=True

  4. Сгруппируйте фрейм данных в столбцах User и Category с использованием groupby

  5. Агрегировать столбцы с помощью agg и подсчитать все Ticket_id.

Здесь у нас есть выходные значения. Следующие шаги здесь, чтобы соответствовать желаемому ожидаемому результату .

Переименуйте вывод count в count, используя rename.

Добавьте столбец Category_1, используя assign

Установите столбец Category_1 в качестве индекса, используя set_index с append=True

Изменение порядка уровней индекса с помощью reorder_levels


Полный код + иллюстрация

def f(x):
    x = x.reset_index(drop=True)
    return x.iloc[x[x["Category"].eq('cat_1')].index[0]+1:]


# Step 2
print(df.groupby("User")
        .apply(f))
#         Ticket ID User       Date Category
# User
# a    3       1683    a   1/4/2020    cat_3
#      4       1281    a   1/4/2020    cat_3
#      5       1561    a   1/5/2020    cat_5
#      6       1932    a   1/5/2020    cat_5
# b    1       1152    b  1/10/2020    cat_4
#      2       1596    b  1/11/2020    cat_4
#      3       1447    b  1/12/2020    cat_4
#      4       1576    b  1/12/2020    cat_5
#      5       1556    b  1/15/2020    cat_5
#      6       1838    b  1/16/2020    cat_5
#      7       1182    b  1/17/2020    cat_5
# c    6       1260    c  1/13/2020    cat_2

# Step 3
print(df.groupby("User")
        .apply(f)
        .reset_index(drop=True))
#     Ticket ID User       Date Category
# 0        1683    a   1/4/2020    cat_3
# 1        1281    a   1/4/2020    cat_3
# 2        1561    a   1/5/2020    cat_5
# 3        1932    a   1/5/2020    cat_5
# 4        1152    b  1/10/2020    cat_4
# 5        1596    b  1/11/2020    cat_4
# 6        1447    b  1/12/2020    cat_4
# 7        1576    b  1/12/2020    cat_5
# 8        1556    b  1/15/2020    cat_5
# 9        1838    b  1/16/2020    cat_5
# 10       1182    b  1/17/2020    cat_5
# 11       1260    c  1/13/2020    cat_2

# Step 5
print(df.groupby("User")
        .apply(f)
        .reset_index(drop=True)
        .groupby(["User", "Category"])
        .agg({"Ticket ID": "count"}))
#                Ticket ID
# User Category
# a    cat_3             2
#      cat_5             2
# b    cat_4             3
#      cat_5             4
# c    cat_2             1

# Step 6
print(df.groupby("User")
        .apply(f)
        .reset_index(drop=True)
        .groupby(["User", "Category"])
        .agg({"Ticket ID": "count"})
        .rename(columns={"Ticket ID": "count"}))
#                count
# User Category
# a    cat_3         2
#      cat_5         2
# b    cat_4         3
#      cat_5         4
# c    cat_2         1

print(df.groupby("User")
        .apply(f)
        .reset_index(drop=True)
        .groupby(["User", "Category"])
        .agg({"Ticket ID": "count"})
        .rename(columns={"Ticket ID": "count"})
        .assign(Category_1="cat_1")
        .set_index("Category_1", append=True)
        .reorder_levels([0, 2, 1]))
#                           count
# User Category_1 Category
# a    cat_1      cat_3         2
#                 cat_5         2
# b    cat_1      cat_4         3
#                 cat_5         4
# c    cat_1      cat_2         1
#                count Category_1

# Step 7
print(df.groupby("User")
        .apply(f)
        .reset_index(drop=True)
        .groupby(["User", "Category"])
        .agg({"Ticket ID": "count"})
        .rename(columns={"Ticket ID": "count"})
        .assign(Category_1="cat_1"))
# User Category
# a    cat_3         2      cat_1
#      cat_5         2      cat_1
# b    cat_4         3      cat_1
#      cat_5         4      cat_1
# c    cat_2         1      cat_1
#                           count

# Step 8
print(df.groupby("User")
        .apply(f)
        .reset_index(drop=True)
        .groupby(["User", "Category"])
        .agg({"Ticket ID": "count"})
        .rename(columns={"Ticket ID": "count"})
        .assign(Category_1="cat_1")
        .set_index("Category_1", append=True))
# User Category Category_1
# a    cat_3    cat_1           2
#      cat_5    cat_1           2
# b    cat_4    cat_1           3
#      cat_5    cat_1           4
# c    cat_2    cat_1           1
#                           count

# Step 9
print(df.groupby("User")
        .apply(f)
        .reset_index(drop=True)
        .groupby(["User", "Category"])
        .agg({"Ticket ID": "count"})
        .rename(columns={"Ticket ID": "count"})
        .assign(Category_1="cat_1")
        .set_index("Category_1", append=True)
        .reorder_levels([0, 2, 1]))
# User Category_1 Category
# a    cat_1      cat_3         2
#                 cat_5         2
# b    cat_1      cat_4         3
#                 cat_5         4
# c    cat_1      cat_2         1
...