#python #pandas
#python #pandas
Вопрос:
Я использую библиотеку pandas для чтения данных из файла .json. У меня есть следующий пример набора данных:
import pandas as pd
df = pd.DataFrame([['1', 'book1'],
['1', 'book2'],
['1', 'book6'],
['2', 'book1'],
['2', 'book6'],
['2', 'book3'],
['3', 'book4'],
['3', 'book2'],
['4', 'book3'],
],
columns=['visitor_id', 'bookid'])
Этот набор данных показывает идентификатор пользователя и какую книгу прочитал этот пользователь. Мой вопрос в том, возможно ли отфильтровать список книг, которые прочитали другие пользователи, на основе заданной балансовой стоимости? Например, какие другие книги прочитали другие пользователи, которые также прочитали книгу 1. Таким образом, результат должен иметь ‘book6’, ‘book3’ и ‘book2’, если бы я искал ‘book1’.
Возможно ли сделать это напрямую, используя любую функцию pandas? Ближайшим, что я смог найти в документации, была функция groupby(), но я не смог заставить ее работать. Я хочу избежать прохождения каждого значения с помощью цикла, поскольку мой набор данных довольно большой.
Ответ №1:
Вы можете отфильтровать все visitor_id
, где есть маска соответствия m
для сравнения Series.eq
, затем отфильтровать оригинал visitor_id
с Series.isin
помощью и, наконец, отфильтровать все группы без m
маски, инвертировав их ~
на Series, а затем на unique list:
m = df['bookid'].eq('book1')
a = df.loc[df['visitor_id'].isin(df.loc[m, 'visitor_id']) amp; ~m, 'bookid'].unique().tolist()
print (a)
['book2', 'book6', 'book3']
Или вы можете использовать GroupBy.transform
with GroupBy.any
для проверки хотя бы одного совпадения для каждой группы:
m = df['bookid'].eq('book1')
a = df.loc[m.groupby(df['visitor_id']).transform('any') amp; ~m, 'bookid'].unique().tolist()
print (a)
['book2', 'book6', 'book3']
Объяснение:
Сначала сравните значения с логической маской:
m = df['bookid'].eq('book1')
print (m)
0 True
1 False
2 False
3 True
4 False
5 False
6 False
7 False
8 False
Name: bookid, dtype: bool
Затем отфильтруйте visitor_id
его комбинацию boolean indexing
:
print (df[m])
visitor_id bookid
0 1 book1
3 2 book1
с DataFrame.loc
помощью фильтра по маске и имени столбца здесь, visitor_id
чтобы Series
:
print (df.loc[m, 'visitor_id'])
0 1
3 2
Name: visitor_id, dtype: object
Теперь снова фильтруйте по значениям из Series
для получения всех строк по группам:
print (df['visitor_id'].isin(df.loc[m, 'visitor_id']))
0 True
1 True
2 True
3 True
4 True
5 True
6 False
7 False
8 False
Name: visitor_id, dtype: bool
Но поскольку вы хотите удалить строки с маской m
, сначала инвертируйте маску для отображения True-> False, False-> True:
print (~m)
0 False
1 True
2 True
3 False
4 True
5 True
6 True
7 True
8 True
Name: bookid, dtype: bool
И цепочка по amp;
для побитового AND
:
print (df['visitor_id'].isin(df.loc[m, 'visitor_id']) amp; ~m)
0 False
1 True
2 True
3 False
4 True
5 True
6 False
7 False
8 False
dtype: bool bookid
Эта маска используется для bookid
столбца фильтра:
print (df.loc[df['visitor_id'].isin(df.loc[m, 'visitor_id']) amp; ~m, 'bookid'])
1 book2
2 book6
4 book6
5 book3
Name: bookid, dtype: object
И последнее — преобразовать Series
в уникальный массив и в список:
print (df.loc[df['visitor_id'].isin(df.loc[m, 'visitor_id']) amp; ~m, 'bookid'].unique().tolist())
['book2', 'book6', 'book3']
Комментарии:
1. Большое вам спасибо. Можно ли объяснить, что это ~ делает? Я новичок в pandas, поэтому я не понимаю, что это значит.
2. @NaeemKhan — Добавлено объяснение