pandas groupby, когда групповые ключи нужно обрабатывать отдельно, если между ними изменился ключ - PullRequest
0 голосов
/ 22 апреля 2019

Я полагаю, что пример ввода и вывода даст лучшее объяснение.

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

user2.groupby('cluser')['time'].agg(['max', 'min']).reset_index()

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

Я пытался «пометить», когда произошло это изменение (сдвинуть столбец кластера и проверить, отличается ли он, и поставить «маркерный столбец» с 1 или 0 ...), но все еще не знаю, как действовать дальше.

data = [[39, 116, 492L, '2008-10-23 12:45:24', '002', 1],
       [39., 116., 673L, '2008-10-23 12:53:22', '002', 1],
       [39., 116., 129L, '2008-10-23 13:01:17', '002', 2],
       [39., 116., 905L, '2008-10-23 13:16:25','002', 2],
       [39., 116., 541L, '2008-10-23 13:28:30','002', 2],
       [39., 116., 233L, '2008-10-23 13:41:33','002', 1],
       [39., 116., 0L, '2008-10-23 13:55:02', '002',1],
       [39., 116., 333L, '2008-10-23 14:08:35','002', 3],
       [39., 116., 229L, '2008-10-23 14:22:06', '002', 3],
       [39., 116., 225L, '2008-10-23 14:33:10','002', 1],
       [39., 116., 190L, '2008-10-23 14:50:58', '002', 2],
       [39., 116., 232L, '2008-10-23 14:58:23','002', 2],
       [39., 116., 540L, '2008-10-23 15:25:14','002', 2]]
pd.DataFrame(data, columns=['lat', 'lon', 'alt','datetime','user', 'cluster'])



    lat lon alt datetime    user    cluster
0   39.0    116.0   492 2008-10-23 12:45:24 002 1
1   39.0    116.0   673 2008-10-23 12:53:22 002 1
2   39.0    116.0   129 2008-10-23 13:01:17 002 2
3   39.0    116.0   905 2008-10-23 13:16:25 002 2
4   39.0    116.0   541 2008-10-23 13:28:30 002 2
5   39.0    116.0   233 2008-10-23 13:41:33 002 1
6   39.0    116.0   0   2008-10-23 13:55:02 002 1
7   39.0    116.0   333 2008-10-23 14:08:35 002 3
8   39.0    116.0   229 2008-10-23 14:22:06 002 3
9   39.0    116.0   225 2008-10-23 14:33:10 002 1
10  39.0    116.0   190 2008-10-23 14:50:58 002 2
11  39.0    116.0   232 2008-10-23 14:58:23 002 2
12  39.0    116.0   540 2008-10-23 15:25:14 002 2


output = [['002', 1, '2008-10-23 12:45:24', '2008-10-23 12:53:22',2],
          ['002', 2, '2008-10-23 13:01:17', '2008-10-23 13:28:30',3],
          ['002', 1, '2008-10-23 13:41:33', '2008-10-23 13:55:02',2],
          ['002', 3, '2008-10-23 14:08:35', '2008-10-23 14:22:06',2],
          ['002', 1, '2008-10-23 14:33:10', '2008-10-23 14:33:10',1],
          ['002', 2, '2008-10-23 14:50:58', '2008-10-23 15:25:14',3]]
pd.DataFrame(output, columns=['user', 'cluster', 'min time','max time', '# num items'])



    user    cluster min time    max time    # num items
0   002 1   2008-10-23 12:45:24 2008-10-23 12:53:22 2
1   002 2   2008-10-23 13:01:17 2008-10-23 13:28:30 3
2   002 1   2008-10-23 13:41:33 2008-10-23 13:55:02 2
3   002 3   2008-10-23 14:08:35 2008-10-23 14:22:06 2
4   002 1   2008-10-23 14:33:10 2008-10-23 14:33:10 1
5   002 2   2008-10-23 14:50:58 2008-10-23 15:25:14 3

1 Ответ

1 голос
/ 22 апреля 2019

Попробуйте, создайте вспомогательный столбец, используя cumsum для получения различных групп кластеров, затем сгруппируйте этот новый столбец с помощью 'user' и 'cluster':

df.assign(clusterkey=df['cluster'].diff().ne(0).cumsum())\
  .groupby(['user', 'cluster', 'clusterkey'], sort=False)['datetime']\
  .agg(['min', 'max', 'count']).reset_index().drop('clusterkey', axis=1)

Вывод:

  user  cluster                  min                  max  count
0  002        1  2008-10-23 12:45:24  2008-10-23 12:53:22      2
1  002        2  2008-10-23 13:01:17  2008-10-23 13:28:30      3
2  002        1  2008-10-23 13:41:33  2008-10-23 13:55:02      2
3  002        3  2008-10-23 14:08:35  2008-10-23 14:22:06      2
4  002        1  2008-10-23 14:33:10  2008-10-23 14:33:10      1
5  002        2  2008-10-23 14:50:58  2008-10-23 15:25:14      3

Подробная информация о создании вспомогательного столбца 'clusterkey':

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

df['cluster'].diff()

0     NaN
1     0.0
2     1.0
3     0.0
4     0.0
5    -1.0
6     0.0
7     2.0
8     0.0
9    -2.0
10    1.0
11    0.0
12    0.0
Name: cluster, dtype: float64

Далее добавьте проверку, чтобы увидеть, гдезначения не равны нулю, поэтому текущее значение изменилось по сравнению с предыдущим значением.

df['cluster'].diff().ne(0)

0      True
1     False
2      True
3     False
4     False
5      True
6     False
7      True
8     False
9      True
10     True
11    False
12    False
Name: cluster, dtype: bool

Теперь значения True отмечают начало новой группировки cluster.Наконец, мы можем использовать cumsum для уникальной идентификации каждой группировки.

df['cluster'].diff().ne(0).cumsum()

0     1
1     1
2     2
3     2
4     2
5     3
6     3
7     4
8     4
9     5
10    6
11    6
12    6
Name: cluster, dtype: int32

И затем я использовал assign, чтобы создать столбец в кадре данных с именем clusterkeys, и добавил это в свой метод groupby.

...