Сортировка и ранжирование по датам, по группе в pandas df - PullRequest
0 голосов
/ 05 октября 2018

На следующем типе данных я хотел бы иметь возможность сортировать и ранжировать поле id на дату:

df = pd.DataFrame({
'id':[1, 1, 2, 3, 3, 4, 5, 6,6,6,7,7], 
'value':[.01, .4, .2, .3, .11, .21, .4, .01, 3, .5, .8, .9],
'date':['10/01/2017 15:45:00','05/01/2017 15:56:00',
        '11/01/2017 15:22:00','06/01/2017 11:02:00','05/01/2017 09:37:00',
        '05/01/2017 09:55:00','05/01/2017 10:08:00','03/02/2017 08:55:00',
        '03/02/2017 09:15:00','03/02/2017 09:31:00','09/01/2017 15:42:00',
        '19/01/2017 16:34:00']})

, чтобы эффективно ранжировать или индексировать, для id, на основеdate.

Я использовал

df.groupby('id')['date'].min()

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

enter image description here

Есть какие-нибудь идеи по поводу этой сортировки / ранжирования / маркировки?

РЕДАКТИРОВАТЬ

Моя оригинальная модель проигнорировала очень распространенную проблему.

Поскольку возможно, что некоторыеid с несколькими параллельными тестами, поэтому они отображаются в нескольких строках в базе данных с совпадающими датами (date соответствует дате их регистрации).Они должны учитываться как одна и та же дата, а не увеличивать date_rank: я сгенерировал модель с обновленным date_rank, чтобы продемонстрировать, как это будет выглядеть:

df = pd.DataFrame({
'id':[1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6,6,6,7,7], 
'value':[.01, .4, .5, .7, .77, .1,.2, 0.3, .11, .21, .4, .01, 3, .5, .8, .9, .1],
'date':['10/01/2017 15:45:00','10/01/2017 15:45:00','05/01/2017 15:56:00',
        '11/01/2017 15:22:00','11/01/2017 15:22:00','06/01/2017 11:02:00','05/01/2017 09:37:00','05/01/2017 09:37:00','05/01/2017 09:55:00',
        '05/01/2017 09:55:00','05/01/2017 10:08:00','05/01/2017 10:09:00','03/02/2017 08:55:00',
        '03/02/2017 09:15:00','03/02/2017 09:31:00','09/01/2017 15:42:00',
        '19/01/2017 16:34:00']})

И счетчик может себе это позволить:

enter image description here

Ответы [ 2 ]

0 голосов
/ 05 октября 2018

Вы можете сделать это с помощью sort_values, groupby и cumcount

df['date_rank'] = df.sort_values(['id', 'date'], ascending=[True, False]).groupby(['id']).cumcount() + 1

demo

In [1]: df = pd.DataFrame({
    ...: 'id':[1, 1, 2, 3, 3, 4, 5, 6,6,6,7,7],
    ...: 'value':[.01, .4, .2, .3, .11, .21, .4, .01, 3, .5, .8, .9],
    ...: 'date':['10/01/2017 15:45:00','05/01/2017 15:56:00',
    ...:         '11/01/2017 15:22:00','06/01/2017 11:02:00','05/01/2017 09:37:00',
    ...:         '05/01/2017 09:55:00','05/01/2017 10:08:00','03/02/2017 08:55:00',
    ...:         '03/02/2017 09:15:00','03/02/2017 09:31:00','09/01/2017 15:42:00',
    ...:         '19/01/2017 16:34:00']})
    ...:

In [2]: df['date_rank'] = df.sort_values(['id', 'date'], ascending=[True, False]).groupby(['id']).cumcount() + 1
    ...:

In [3]: df
Out[3]:
    id  value                 date  date_rank
0    1   0.01  10/01/2017 15:45:00          1
1    1   0.40  05/01/2017 15:56:00          2
2    2   0.20  11/01/2017 15:22:00          1
3    3   0.30  06/01/2017 11:02:00          1
4    3   0.11  05/01/2017 09:37:00          2
5    4   0.21  05/01/2017 09:55:00          1
6    5   0.40  05/01/2017 10:08:00          1
7    6   0.01  03/02/2017 08:55:00          3
8    6   3.00  03/02/2017 09:15:00          2
9    6   0.50  03/02/2017 09:31:00          1
10   7   0.80  09/01/2017 15:42:00          2
11   7   0.90  19/01/2017 16:34:00          1

Редактировать

вы можете сделать это методом ранга

df.groupby(['id'])['date'].rank(ascending=False, method='dense').astype(int)

демо

In [1]: df['rank'] = df.groupby(['id'])['date'].rank(ascending=False, method='dense').astype(int)

In [2]: df
Out[2]:
    id  value                date  rank
0    1   0.01 2017-10-01 15:45:00     1
1    1   0.40 2017-10-01 15:45:00     1
2    1   0.50 2017-05-01 15:56:00     2
3    2   0.70 2017-11-01 15:22:00     1
4    2   0.77 2017-11-01 15:22:00     1
5    3   0.10 2017-06-01 11:02:00     1
6    3   0.20 2017-05-01 09:37:00     2
7    3   0.30 2017-05-01 09:37:00     2
8    4   0.11 2017-05-01 09:55:00     1
9    4   0.21 2017-05-01 09:55:00     1
10   5   0.40 2017-05-01 10:08:00     2
11   5   0.01 2017-05-01 10:09:00     1
12   6   3.00 2017-03-02 08:55:00     3
13   6   0.50 2017-03-02 09:15:00     2
14   6   0.80 2017-03-02 09:31:00     1
15   7   0.90 2017-09-01 15:42:00     1
16   7   0.10 2017-01-19 16:34:00     2
0 голосов
/ 05 октября 2018

Вы можете попробовать отсортировать значения даты по убыванию и агрегировать значения группы 'id'.

Логика @ praveen очень проста. Расширяя логику, вы можете использовать астип категории для преобразования значений в категории.и может получить коды (ключи) этих категорий, но это будет немного отличаться от ожидаемого результата

df1 = df.sort_values(['id', 'date'], ascending=[True, False])
df1['date_rank'] =df1.groupby(['id']).apply(lambda x: x['date'].astype('category',ordered=False).cat.codes+1).values

Out:

                 date   id  value   date_rank
0   10/01/2017 15:45:00 1   0.01    2
1   10/01/2017 15:45:00 1   0.40    2
2   05/01/2017 15:56:00 1   0.50    1
3   11/01/2017 15:22:00 2   0.70    1
4   11/01/2017 15:22:00 2   0.77    1
5   06/01/2017 11:02:00 3   0.10    2
6   05/01/2017 09:37:00 3   0.20    1
7   05/01/2017 09:37:00 3   0.30    1
8   05/01/2017 09:55:00 4   0.11    1
9   05/01/2017 09:55:00 4   0.21    1
11  05/01/2017 10:09:00 5   0.01    2
10  05/01/2017 10:08:00 5   0.40    1
14  03/02/2017 09:31:00 6   0.80    3
13  03/02/2017 09:15:00 6   0.50    2
12  03/02/2017 08:55:00 6   3.00    1
16  19/01/2017 16:34:00 7   0.10    2
15  09/01/2017 15:42:00 7   0.90    1

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

df1 = df.sort_values(['id', 'date'], ascending=[True, False])
df1['date_rank'] = df1.groupby(['id'])['date'].transform(lambda x: list(map(lambda y: dict(map(reversed, dict(enumerate(x.unique())).items()))[y]+1,x)) )

Out:

                date    id  value   date_rank
0   10/01/2017 15:45:00 1   0.01    1
1   10/01/2017 15:45:00 1   0.40    1
2   05/01/2017 15:56:00 1   0.50    2
3   11/01/2017 15:22:00 2   0.70    1
4   11/01/2017 15:22:00 2   0.77    1
5   06/01/2017 11:02:00 3   0.10    1
6   05/01/2017 09:37:00 3   0.20    2
7   05/01/2017 09:37:00 3   0.30    2
8   05/01/2017 09:55:00 4   0.11    1
9   05/01/2017 09:55:00 4   0.21    1
11  05/01/2017 10:09:00 5   0.01    1
10  05/01/2017 10:08:00 5   0.40    2
14  03/02/2017 09:31:00 6   0.80    1
13  03/02/2017 09:15:00 6   0.50    2
12  03/02/2017 08:55:00 6   3.00    3
16  19/01/2017 16:34:00 7   0.10    1
15  09/01/2017 15:42:00 7   0.90    2
...