Как использовать каждую пару значений в столбце и транспонировать их в строки внутри групп (groupby) - PullRequest
1 голос
/ 11 марта 2019

У меня есть данные, к которым я уже применил группу по пользователю и сортировку по времени (data.groupby('id').apply(lambda x: x.sort_values('time'))):

user     time     point_id
 1       00:00         1
 1       00:01         3
 1       00:02         4
 1       00:03         2

 2       00:00         1
 2       00:05         3
 2       00:15         1

 3       00:00         1
 3       01:00         2
 3       02:00         3

И после этого мне нужно внутри каждой группы сделать ссылки / транспонировать следующие 2 значенияв ряды.Для приведенного выше примера это должно выглядеть так:

user     start_point     end_point
 1           1               3
 1           3               4
 1           4               2

 2           1               3
 2           3               1

 3           1               2    
 3           2               3

Моя конечная цель - получить матрицу, которая покажет, сколько ссылок входит в каждую точку:

point_id |  1   |     2    |    3   |     4    |
    --------------------------------------------
   1         0        1         3          0
   2         1        0         0          1
   3         3        0         0          1
   4         0        1         1          0

Так что эта матрица означаетчто из пункта 2 одна ссылка переходит в пункт 1, из пункта 3 3 ссылки идут в точку один и т. д. Изображение выглядит следующим образом:

enter image description here

Ответы [ 2 ]

2 голосов
/ 11 марта 2019

Во-первых, вы можете использовать shift() для группировки point_id в строки.

df = df.assign(end_point=df['point_id'].shift(-1))[df['user']==df['user'].shift(-1)].rename(columns={'point_id':'start_point'}).astype(int)
print(df)

   user  start_point  end_point
0     1            1          3
1     1            3          4
2     1            4          2
4     2            1          3
5     2            3          1
7     3            1          2
8     3            2          3

Тогда вы можете использовать pd.crosstab для подсчета направленной ссылки.

u = pd.crosstab(df.start_point, df.end_point)
print(u)

end_point    1  2  3  4
start_point            
1            0  1  2  0
2            0  0  1  0
3            1  0  0  1
4            0  1  0  0

Согласно вашим результатам, вам нужен неориентированный подсчет графов, поэтому все, что нам нужно сделать, это транспонировать и добавить.

result = u + u.T
print(result)

end_point    1  2  3  4
start_point            
1            0  1  3  0
2            1  0  1  1
3            3  1  0  1
4            0  1  1  0

Окончательный код следующим образом:

df = df.assign(end_point=df['point_id'].shift(-1))[df['user']==df['user'].shift(-1)].rename(columns={'point_id':'start_point'}).astype(int)
u = pd.crosstab(df.start_point, df.end_point)
result = u + u.T
1 голос
/ 11 марта 2019

Я считаю, что это работает для вашего примера, взяв df = data.groupby('id').apply(lambda x: x.sort_values('time')) (ваш начальный пример):

groups = [(k, df.loc[v, 'point_id'].values) for k, v in df.groupby('user').groups.items()]

res = []
for g in groups:
    res.append([(g[0], i) for i in (zip(g[1], g[1][1:]))])

df1 = pd.DataFrame([item for sublist in res for item in sublist])
df2 = df1.copy()

df2.iloc[:,-1] = df2.iloc[:,-1].apply(lambda x: (x[1], x[0]))  # df2 swaps around the points

df_ = pd.concat([df1, df2]).sort_values(by=0)  

df_['1'], df_['2'] = df_.iloc[:,-1].apply(lambda x: x[0]), df_.iloc[:,-1].apply(lambda x: x[1])

df_ = df_.drop(columns=1)
df_.columns = ['user', 'start_point', 'end_point']  # your intermediate table

df_.pivot_table(index='start_point', columns='end_point', aggfunc='count').fillna(0)

Вывод:

           user
end_point   1   2       3       4

start_point                 
1          0.0  1.0     3.0     0.0
2          1.0  0.0     1.0     1.0
3          3.0  1.0     0.0     1.0
4          0.0  1.0     1.0     0.0
...