我正在玩熊猫,我有一个问题,弄清楚如何解决以下问题。给定一个由bookId和readerId组成的数据框,我想获得对于给定的读者a来说,阅读过a所读过的任何一本书的其他读者的数量。
这是一个示例数据框架
import pandas as pd
df = pd.DataFrame({'bookId': [1,1,2,2,3,3,3,4,4,4,4,4],
'readerId': [1,2,1,3,1,3,4,1,3,4,5,6]})
有人能帮我解决这个问题吗?或者给我一些使用熊猫时解决这个问题的直觉?输出一个带有readerId和count列的新数据帧。
更新:
实际上,与其得到每本书的读者数量,我更想得到所有读过我读过的书的读者数量。因此,如果一个读者读了3本书,另外20个人读了其中的任何一本书,那么我真的想要20个作为答案,如果这20个读者都是不同的,并且不一定读了给定读者的所有书单。
要获取每个阅读器的计数,应该这样做:
In [1]: import pandas as pd
In [2]: df = pd.DataFrame({'bookId': [1,1,2,2,3,3,3,4,4,4,4,4],
...: 'readerId': [1,2,1,3,1,3,4,1,3,4,5,6]})
In [3]: res = pd.DataFrame(np.unique(df.readerId)).reset_index(drop=True)
In [4]: def get_readers(reader, df=df):
...: return len(set(df.readerId[df.bookId.isin(df.bookId[
...: df.readerId==reader])]))-1
In [5]: res['Count'] = res.readerId.apply(get_readers)
In [6]: res
Out[6]:
readerId Count
0 1 5
1 2 1
2 3 4
3 4 4
4 5 4
5 6 4
In [7]: timeit get_readers(1)
1000 loops, best of 3: 387 us per loop
应该有很多方法可以解决你的问题。这是我的,可能不是最好的:
首先,获取reader1
的bookIdsIn [99]: bookIds = df[df['readerId']==1]['bookId'].values
In [100]: bookIds
Out[100]: array([1, 2, 3, 4])
如果您熟悉SQL,您可以将其视为:SELECT bookId FROM df WHERE readerId == 1
其次,选择readerId == 1和bookId在上述bookIds
数组
In [101]: df2 = df[df['readerId'] != 1 & df['bookId'].isin(bookIds)]
In [102]: df2
Out[102]:
bookId readerId
1 1 2
3 2 3
5 3 3
6 3 4
8 4 3
9 4 4
10 4 5
11 4 6
SQL: SELECT bookId, readerId FROM df WHERE readerId != 1 and bookId in bookIds
最后,按readerId分组并计数
In [103]: df2.groupby('readerId').size()
Out[103]:
readerId
2 1
3 3
4 2
5 1
6 1
dtype: int64
SQL: SELECT COUNT(bookId) FROM df2 GROUP BY readerId
希望它能帮助你更容易地了解熊猫
[编辑],回答你在评论中提出的问题:
创建另一个数据框(只更改列)
In [114]: df2 = df.rename(columns={'readerId': 'otherReaderId'})
通过bookId
将它们连接,然后通过readerId
和otherReaderId
将它们分组
In [115]: pd.merge(df, df2, on='bookId').groupby(['readerId', 'otherReaderId']).size()
Out[115]:
readerId otherReaderId
1 1 4
2 1
3 3
4 2
5 1
6 1
2 1 1
2 1
3 1 3
3 3
4 2
5 1
6 1
4 1 2
3 2
4 2
5 1
6 1
5 1 1
3 1
4 1
5 1
6 1
6 1 1
3 1
4 1
5 1
6 1
dtype: int64