Как посчитать уникальные значения из двух столбцов на основе другого столбца?(за удостоверение личности) - PullRequest
3 голосов
/ 23 мая 2019

У меня есть 6 миллионов данных транзакций, поэтому мне нужны некоторые функции для быстрого запуска.По сути, у меня есть уникальные идентификаторы клиентов и класс автомобилей, которые они зарезервировали и фактически ездили в конце.Клиенты могут иметь один или несколько вариантов аренды автомобиля.Для конкретного клиента в каждый момент времени я хочу подсчитать, сколько он / она испытывает уникальных различных классов автомобилей, комбинируя уникальный класс автомобиля (зарезервированный и пригнанный)

На самом деле, мои данные даже не в этомпорядок, что означает, что идентификатор и даты не отсортированы.Схема, показанная ниже, предназначена для удобства.Было бы неплохо, если бы вы также могли обработать несортированную проблему!

Спасибо!

Данные выглядят так:

id  date reserved drove
1   2017    A       B
1   2018    B       A
1   2019    A       C
2   2017    A       B
2   2018    C       D
3   2018    D       D

Я хочу этот результат:

id  date  experience
1   2017     2 #(A+B)
1   2018     2 #still the same as 2017 because this customer just experienced A and B (A+B)
1   2019     3 #one more experience because C is new car class (A+B+C)
2   2017     2 #(A+B)
2   2018     4 #(A+B+C+D)
3   2018     1 #(D)

Ответы [ 3 ]

1 голос
/ 23 мая 2019

Вот подход, основанный на numpy:

import numpy as np
# sort values column-wise
df[['reserved','drove']] = np.sort(df[['reserved','drove']])
# sort values by id, reserved and drove
df = df.sort_values(['id','reserved','drove'])

А теперь давайте определим некоторые условия для получения ожидаемого результата:

# Does the id change?
c1 = df.id.ne(df.id.shift()).values
# is the next row the same? (for each col individually)
c2 = (df[['reserved','drove']].ne(df[['reserved','drove']].shift(1))).values
# Is the value in "drove" the same?
c3 = (df[['reserved','drove']].ne(df[['reserved','drove']].shift(1, axis=1))).values

df['experience'] = ((c2 + c1[:,None]) * c3).sum(1)
df = df[['id','date']].assign(experience = df.groupby('id').experience.cumsum())

print(df)

   id  date  experience
0   1  2017           2
1   1  2018           2
2   1  2019           3
3   2  2017           2
4   2  2018           4
5   3  2018           1
1 голос
/ 23 мая 2019

Это можно сделать двумя строками (и я уверен, что кто-то может выполнить это в одной строке):
Создайте список всех наблюдаемых значений как зарезервированных, так и заправленных, а затем посчитайте их содержимое (используя cumsum)

df['aux'] = list(map(list, zip(df.reserved, df.drove)))
df['aux_cum'] = [len(set(x)) for x in df.groupby('id')['aux'].apply(lambda x: x.cumsum())]

Выход:

   id  date reserved drove     aux  aux_cum
0   1  2017        A     B  [A, B]        2
1   1  2018        B     A  [B, A]        2
2   1  2019        A     C  [A, C]        3
3   2  2017        A     B  [A, B]        2
4   2  2018        C     D  [C, D]        4
5   3  2018        D     D  [D, D]        1

Красивый формат:

print(df.drop(['reserved','drove','aux'], axis=1)

   id  date  aux_cum
0   1  2017        2
1   1  2018        2
2   1  2019        3
3   2  2017        2
4   2  2018        4
5   3  2018        1
1 голос
/ 23 мая 2019

Как насчет этого?Использует понимание списка, так как Pandas DF не подходит для работы с множествами (и именно в этом заключается эта проблема).

df = pd.DataFrame([
    [1, 2017, 'a', 'b'],
    [1, 2018, 'a', 'b'],
    [1, 2019, 'a', 'c'],
    [2, 2017, 'a', 'b'],
    [2, 2018, 'c', 'd'],
    [3, 2018, 'd', 'd'],
], columns=['id', 'date', 'reserved', 'drove'])

list_of_sets = [(v[0], v[1], {v[2], v[3]}) for v in df.values]

sorted_list = sorted(list_of_sets)  # not necc if sorted before

result = pd.DataFrame([
    (info[0], info[1], len(info[2].union(sorted_list[i-1][2])))
    if info[0] == sorted_list[i-1][0] 
    else (info[0], info[1], len(info[2]))
    for i, info in enumerate(sorted_list)
], columns=['id', 'date', 'count'])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...