Pandas — группировка сообщений в виде диалогов путем связывания нескольких строк на основе идентификаторов из двух столбцов

#python #pandas #dataframe

#python #pandas #фрейм данных

Вопрос:

У меня есть некоторые данные, которые отслеживают твиты и ответы на основе source_id и response_id. source_id может быть связан с исходным сообщением или ответом, который имеет свой собственный ответ. Если имеется несколько ответов, то каждый ответ будет иметь source_id, и этот source_id будет отображаться в response_id соответствующего ответа.

Возьмем, к примеру, этот фрейм данных:

 df = pd.DataFrame({
'date': ['2018-10-02', '2018-10-03', '2018-10-03', '2018-10-03', '2018-10-03', '2018-10-03', '2018-10-03', '2018-10-03', '2018-10-03'],
'id': ['334', '335', '336', '337', '338', '340', '341', '343', '358'],
'source_id': ['830', '636', '657', '569', '152', '975', '984', '720', '524'],
'reply_id': [np.nan, '495', '636', '657', '569', '830', '152', np.nan, np.nan]
})
  

И его выходные данные:

          date   id source_id reply_id
0  2018-10-02  334       830      NaN
1  2018-10-03  335       636      495
2  2018-10-03  336       657      636
3  2018-10-03  337       569      657
4  2018-10-03  338       152      569
5  2018-10-03  340       975      830
6  2018-10-03  341       984      152
7  2018-10-03  343       720      NaN
8  2018-10-03  358       524      NaN
  

Каждая строка содержит данные для одного сообщения. Для сообщения существует уникальный идентификатор, будь то твит или ответ на твит. В этом примере есть два «диалога» с одним или несколькими ответами на исходное сообщение и два отдельных твита без ответов. Твиты без ответов являются, df.iloc[7] и df.iloc[8] оба из которых имеют NAN в reply_id и их source_ids не отображаются в reply_ids других строк. Хотя df.iloc[0] в reply_id есть NaN, его source_id отображается в reply_id df.iloc[5] . Таким образом, это будет считаться одним разговором.

С чем я действительно борюсь, так это с тем, как объединить в цепочку серию твитов / ответов, таких как df.iloc[1] , df.iloc[2] , df.iloc[3] , df.iloc[4] df.iloc[6] ,,и, , и считать все это одним разговором. И для этого конкретного разговора нет доступных данных для исходного сообщения, поэтому нет строки с source_id = 495.

У кого-нибудь есть идеи о том, как подойти к этому?

Ответ №1:

Насколько я понимаю, это больше похоже на сетевую проблему, поэтому мы используем networkx

 import networkx as nx 
G=nx.from_pandas_edgelist(df.dropna(), 'reply_id', 'source_id')
l=list(nx.connected_components(G))
newdf=pd.DataFrame(l)
newdf
Out[334]: 
     0    1     2     3     4     5
0  975  830  None  None  None  None
1  984  495   636   152   569   657 
# here you saw all the value belong to one group, they are in the same line 
  

Более подробно, прямо сейчас одна и та же группа индексов будет иметь одинаковый идентификатор

 d=[dict.fromkeys(y,x)for x , y in enumerate(list(nx.connected_components(G)))]
d={k:v for element in d for k,v in element.items()}
ids=df.reply_id.dropna().map(d)
ids
Out[344]: 
1    1
2    1
3    1
4    1
5    0
6    1
Name: reply_id, dtype: int64
  

Комментарии:

1. Это именно то, что я ищу! Спасибо за вашу помощь!! Фрейм данных, который вы создали из списка edge, имеет смысл. Я не уверен, что следую второй части. Похоже, что идентификатор группы может быть добавлен к исходному фрейму данных в качестве нового столбца, чтобы каждое сообщение в диалоге имело одинаковый идентификатор?

2. @ren_he да, вы поняли, просто назначьте его