Pandas, поиск результатов в другом столбце на основе условия

#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 — Добавлено объяснение