我有两个大型稀疏矩阵:
In [3]: trainX
Out[3]:
<6034195x755258 sparse matrix of type '<type 'numpy.float64'>'
with 286674296 stored elements in Compressed Sparse Row format>
In [4]: testX
Out[4]:
<2013337x755258 sparse matrix of type '<type 'numpy.float64'>'
with 95423596 stored elements in Compressed Sparse Row format>
总共需要加载5 GB RAM。请注意,这些矩阵非常稀疏(占用0.0062%)。
对于testX
中的每一行,我想在trainX
中找到 最近邻,并返回trainY
中找到的相应标签。 1}}。 trainY
是一个与trainX
长度相同的列表,并且有许多类。 (一个类由1-5个单独的标签组成,每个标签是20,000个中的一个,但是类的数量与我现在尝试做的无关。)
我正在使用sklearn
的KNN算法来执行此操作:
from sklearn import neighbors
clf = neighbors.KNeighborsClassifier(n_neighbors=1)
clf.fit(trainX, trainY)
clf.predict(testX[0])
即使预测testX
的1项也需要一段时间(例如30-60秒,但如果你乘以200万,则几乎不可能)。我的16GB RAM的笔记本电脑开始交换了一下,但确实设法完成了testX
中的1项。
我的问题是,我怎么能这样做才能在合理的时间内完成?在大型EC2实例上说一晚?只是拥有更多的内存并防止交换速度足够快(我的猜测是否定的)。也许我可以以某种方式利用稀疏性来加速计算?
谢谢。
答案 0 :(得分:8)
当数据维度增加时,sklearn
中使用的经典kNN数据结构(例如KD树)变得非常慢。对于非常高维的问题,建议切换算法类并使用近似最近邻(ANN)方法,遗憾的是sklearn
似乎缺乏这些方法。有关算法和理论的论文,请参阅下面的链接。在这些情况下,为什么近似最近邻居的速度要快得多。
C ++世界中一个着名的ANN库,在计算机视觉中广泛用于特征描述符空间中的最近邻居,是FLANN
。主页说它包含Python绑定(我从未使用过)。
另请参阅this answer(但有些链接已失效)。
一个警告:您的数据似乎非常高维 - 我不知道这些库如何为您执行。他们仍然应该击败sklearn
。
答案 1 :(得分:4)
即使预测1项testX需要一段时间(例如30-60秒,但如果你乘以200万,则几乎不可能)。
这正是所有scikit-learn估算器在predict
方法中采用批次样本的原因。如果在一次调用中传递多个样本,则输入验证和Python的慢循环的成本会变小,因此每个样本的时间会比一个样本的成本乘以样本数少得多。
>>> from sklearn.datasets import fetch_20newsgroups_vectorized
>>> from sklearn.decomposition import TruncatedSVD
>>> from sklearn.neighbors import KNeighborsClassifier
>>> data = fetch_20newsgroups_vectorized()
>>> X, y = data['data'], data['target']
>>> X = TruncatedSVD(n_components=100).fit_transform(X)
>>> clf = KNeighborsClassifier(n_neighbors=1).fit(X, y)
>>> %timeit clf.predict(X[0])
1000 loops, best of 3: 766 us per loop
>>> %timeit clf.predict(X[0:10])
100 loops, best of 3: 2.44 ms per loop
>>> %timeit clf.predict(X[0:100])
100 loops, best of 3: 14.2 ms per loop
>>> %timeit clf.predict(X[0:1000])
10 loops, best of 3: 117 ms per loop
也许我可以以某种方式利用稀疏性来加速计算?
您可以从训练集中进行采样,而不是全部使用。 k-NN的性能取决于训练集的大小,这就是为什么vanilla k-NN算法不是文本分类的一个很好的选择。
(文本处理领域最喜欢的技巧是使用磁盘索引来构建k-NN分类器,例如Lucene:使用整个文档作为查询,检索顶部 k 文件,从那些文件中确定标签。)
答案 2 :(得分:2)
据我所知,FLANN和ANN都不能很好地处理稀疏数据。我刚刚在www.kgraph.org上发布了一个新的C ++库,用于K-NN搜索通用数据类型和通用相似性度量。您所要做的就是插入计算对象i和对象j之间相似性的功能,并且库将完成其余的魔法。缺点是您可能无法通过使用python获得更多收益。由于相似性计算代码将被频繁调用,因此为用户提供的度量标准添加python API没有多大意义。
答案 3 :(得分:0)
如果您正在寻找可扩展的人工神经网络算法,另一种途径是地点 - 敏感散列(LSH)方法,如ITQ(http://www.cs.unc.edu/~lazebnik/publications/cvpr11_small_code.pdf)。除了论文是一些MATLAB代码,但我之前已经将它翻译成python。请参阅:https://github.com/Kitware/SMQTK/blob/master/python/smqtk/algorithms/nn_index/lsh/functors/itq.py