Фильтровать панды столбец списков на основе списка - PullRequest
0 голосов
/ 01 ноября 2018

Имея большое DataFrame следующим образом:

userid    user_mentions
1         [2, 3, 4]
1         [3]
2         NaN
2         [1,3]
3         [1,4,5]
3         [4]

Столбцы user_mentions представляют собой список userid с, которые были упомянуты каждым пользователем. Например, первая строка означает:

пользователь 1 упомянул пользователей 2, 3 и 4.

Мне нужно создать сеть упоминаний среди пользователей в столбце userid. То есть я хочу, чтобы число раз, когда каждый пользователь в столбце userid упоминалось другими пользователями в столбце userid. В общем, сначала мне нужно что-то вроде этого:

filtered = df[df['user_mentions'].isin(df['userid'].unique())]

Но это не работает для столбца списков.

Если я решу вышеуказанную проблему, тогда смогу groupby['userid','user_mentions'].

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

Окончательный результат должен быть:

Source    Target    Number
1         2         1
1         3         2
2         1         1
2         3         1
3         1         1
3         5         1

Ответы [ 3 ]

0 голосов
/ 02 ноября 2018

Эта задача не подходит для Pandas / NumPy. Поэтому я предлагаю вам использовать collections.defaultdict для создания словаря подсчетов, а затем построить кадр данных из словаря:

from collections import defaultdict

dd = defaultdict(lambda: defaultdict(int))

for row in df.itertuples(index=False):
    vals = row.user_mentions
    if vals == vals:
        for val in vals:
            dd[row.userid][val] += 1

df = pd.DataFrame([(k, w, dd[k][w]) for k, v in dd.items() for w in v],
                  columns=['source', 'target', 'number'])

print(df)

   source  target  number
0       1       2       1
1       1       3       2
2       1       4       1
3       2       1       1
4       2       3       1
5       3       1       1
6       3       4       2
7       3       5       1

Конечно, вы не должны ставить списки в серии Pandas на первое место. Это вложенный слой указателей, которых следует избегать, если это вообще возможно.

0 голосов
/ 02 ноября 2018

Вот один из способов.

# Remove the `NaN` rows
df = df.dropna()

# Construct a new DataFrame
df2 = pd.DataFrame(df.user_mentions.tolist(), 
                   index=df.userid.rename('source')
                  ).stack().astype(int).to_frame('target')

# Groupby + size
df2.groupby(['source', 'target']).size().rename('counts').reset_index()

   source  target  counts
0       1       2       1
1       1       3       2
2       1       4       1
3       2       1       1
4       2       3       1
5       3       1       1
6       3       4       2
7       3       5       1
0 голосов
/ 02 ноября 2018

После твоего редактирования я бы согласился с @ jpp.

На ваш (неотредактированный) оригинальный вопрос, с точки зрения сбора количества упоминаний каждого пользователя, вы можете сделать:

df['counts'] = df['userid'].apply(lambda x: df['user_mentions'].dropna().sum().count(x))

df[['userid','counts']].groupby('userid').first()

Урожайность:

        counts
userid        
1            2
2            1
3            3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...