Python Numpy,其中等效
我正在尝试从numpy ndarray中为我的协作过滤项目选择一个子集 我的阵列具有以下形状:Python Numpy,其中等效,python,arrays,performance,numpy,Python,Arrays,Performance,Numpy,我正在尝试从numpy ndarray中为我的协作过滤项目选择一个子集 我的阵列具有以下形状: ratings = np.array( [ (1, 2, 3.0), (2, 2, 3.0), (4, 1, 2.0), (1, 2, 1.0), ], dtype=[ ('user_id', np.uint32), ('item_id', np.uint32), (
ratings = np.array(
[
(1, 2, 3.0),
(2, 2, 3.0),
(4, 1, 2.0),
(1, 2, 1.0),
],
dtype=[
('user_id', np.uint32),
('item_id', np.uint32),
('score', np.float32)
]
)
现在,我想选择一个子集的评级,其中用户_id属于一个数组。类似于SQL的“WHERE IN”功能
我能够使用np.INAD实现这一点:
subset_of_users = [1, 2]
ratings[np.in1d(ratings['user_id'], subset_of_users)]
我的分析总是显示使用in1d的块是最慢的,这让我想到也许有一种更快的替代方法
非常感谢您的时间。如果您的最大用户id不是太大,您可以使用查找表:
mask_of_users = np.zeros(shape=max(ratings['user_id'])+1, dtype=bool)
mask_of_users[subset_of_users] = True
selected_ratings = ratings[mask_of_users[ratings['user_id']]]
这似乎是一个瓶颈,它是
np.inad
,所以让我们试着加快这一部分的速度。现在,根据我到目前为止的NumPy经验,我发现了一种替代方法,可以用来替代第二个数组是排序的、唯一的数组或列表,并且要与第一个数组中的元素进行匹配的情况。下面列出的是实现-
def in1d_replacement(A,B):
""" in1d replacement using searchsorted with optional 'left', 'right' args.
"""
# Get left and right sorted indices for A in B
idx_l = np.searchsorted(B,A,'left')
idx_r = np.searchsorted(B,A,'right')
# Look for switching indices between the left and right ones
# indicating the matches
return idx_l != idx_r
运行时测试-
In [195]: # Random arrays of decent sizes
...: nA = 10000
...: nB = 1000
...: max_num = 100000
...: A = np.random.randint(0,max_num,(nA))
...: B = np.unique(np.random.randint(0,max_num,(nB)))
...:
In [196]: np.allclose(np.in1d(A,B),in1d_replacement(A,B))
Out[196]: True
In [197]: %timeit np.in1d(A,B)
100 loops, best of 3: 2.73 ms per loop
In [198]: %timeit in1d_replacement(A,B)
100 loops, best of 3: 2.14 ms per loop
因此,即使不是很大的提升,也会有一些性能提升。您可以尝试使用该软件包(免责声明:我是它的作者)
受您问题的启发,我对API做了一些更改,这样我们可以从重复查询中获益:
import numpy_indexed as npi
npi.contains(subset_of_users, ratings['user_id'])
应该从左到右读取;'子集包含user_id'的元素,并返回子集中存在的user_id'的索引
但是,计算中最昂贵的部分是为用户id集建立“索引”,这可以通过预计算实现:
index = npi.as_index(ratings['user_id'])
npi.contains(subset_of_users, index)
npi.contains(some_other_subset_of_users, index)
我希望在每个查询的基础上,速度会快一点
Ive还集成了一个npi.in_函数,灵感来自Divakar的答案,它允许你编写npi.in_(ratings['user_id',subset_of_users]),再次从左到右阅读;子集中存在的用户标识的元素。但我希望它的效率比使用contains要低一些。不过这都是猜测;很高兴看到一些实际数据的比较 谢谢你的回答。最大值(用户id)约为150k。使用此代码,我的函数从0.04s变为0.17s:-(