使用NearestNeighbors和word2vec来检测句子相似性。

4

我使用Python和gensim计算了一个word2vec模型,用于我的语料库。

随后,我计算了每个句子的平均word2vec向量(对句子中所有单词的向量求平均),并将其存储在pandas数据框中。该数据框df的列包括:

  • 句子
  • 书名(句子所在的书名)
  • 平均向量(句子中word2vec向量的平均值 - 大小为100)

我尝试使用scikit-learn NearestNeighbors检测句子相似性(我也可以使用doc2vec,但其中一个目标是将此方法与doc2vec进行比较)。

以下是我的代码:

X = df['mean_vector'].values
nbrs = NearestNeighbors(n_neighbors=2, algorithm='ball_tree').fit(X)

I get the following error:

ValueError: setting an array element with a sequence.

我认为我应该迭代这些向量,才能够基于“行==句子”的方式计算每行的最近邻居,但似乎这超出了我目前(有限的)Python技能。
这是df['mean_vector'][0]中第一个单元格的数据。它是一个全尺寸100的向量,平均值是由句子的向量得到的。
array([ -2.14208905e-02,   2.42093615e-02,  -5.78106642e-02,
     1.32915592e-02,  -2.43393257e-02,  -1.41872400e-02,
     2.83471867e-02,  -2.02910602e-02,  -5.49359620e-02,
    -6.70913085e-02,  -5.56188896e-02,  -2.95186806e-02,
     4.97652516e-02,   7.16793686e-02,   1.81338750e-02,
    -1.50108105e-02,   1.79438610e-02,  -2.41483524e-02,
     4.97504435e-02,   2.91026086e-02,  -6.87966943e-02,
     3.27585079e-02,   5.10644279e-02,   1.97029337e-02,
     7.73109496e-02,   3.23865712e-02,  -2.81659551e-02,
    -9.69715789e-03,   5.23059331e-02,   3.81100960e-02,
    -3.62489261e-02,  -3.40068117e-02,  -4.90736961e-02,
     8.72346922e-04,   2.27111522e-02,   1.06063476e-02,
    -3.93234752e-02,  -1.10617064e-01,   8.05142429e-03,
     4.56497036e-02,  -1.73281748e-02,   2.35153548e-02,
     5.13465842e-03,   1.88336968e-02,   2.40451116e-02,
     3.79024050e-03,  -4.83284928e-02,   2.10295208e-02,
    -4.92134318e-03,   1.01532964e-02,   8.02216958e-03,
    -6.74675079e-03,  -1.39653292e-02,  -2.07276996e-02,
     9.73508134e-03,  -7.37899616e-02,  -2.58320477e-02,
    -1.10700730e-05,  -4.53227758e-02,   2.31859135e-03,
     1.40053956e-02,   1.61973312e-02,   3.01702786e-02,
    -6.96818605e-02,  -3.47468331e-02,   4.79541793e-02,
    -1.78820305e-02,   5.99209731e-03,  -5.92620336e-02,
     7.34678581e-02,  -5.23381204e-05,  -5.07357903e-02,
    -2.55154949e-02,   5.06089740e-02,  -3.70467864e-02,
    -2.04878468e-02,  -7.62404222e-03,  -5.38200373e-03,
     7.68705690e-03,  -3.27000804e-02,  -2.18365286e-02,
     2.34392099e-03,  -3.02998684e-02,   9.42565035e-03,
     3.24523374e-02,  -1.10793915e-02,   3.06244520e-03,
    -1.82240941e-02,  -5.70741761e-03,   3.13486941e-02,
    -1.15621388e-02,   1.10221673e-02,  -3.55655849e-02,
    -4.56304513e-02,   5.54837054e-03,   4.38252240e-02,
     1.57828294e-02,   2.65670624e-02,   8.08797963e-03,
     4.55569401e-02], dtype=float32)

我也尝试过做以下操作:

for vec in df['mean_vector']:
X = vec
nbrs = NearestNeighbors(n_neighbors=2, algorithm='ball_tree').fit(X)

但是我只收到以下警告:
DeprecationWarning: Passing 1d arrays as data is deprecated in 0.17 and willraise ValueError in 0.19. Reshape your data either using X.reshape(-1, 1) if your data has a single feature or X.reshape(1, -1) if it contains a single sample.

如果有一个在github上使用word2vec和NearestNeighbors的类似场景的示例,我很想看看。

1
X长什么样?你能否更新问题并提供X的示例? - Abhishek Thakur
需要一些数据来进行最小化可行性实验。我刚刚使用了gensim中的数据测试了NearestNeighbors,对我来说效果很好。 - piman314
@Abhishek Thakur 我已经添加了一个示例向量(每个语料库中的句子都有一个,所以数量相当大)。 - Enzo
@ncfirth 如果有的话,我很想看看你的例子...谢谢。 - Enzo
嗨@Enzo,我目前正在开展一个类似的项目,其中我将句子存储为该句子中单词的w2v向量的平均值,然后使用KNN在输入关键字/短语时查找最接近的句子。你能告诉我评估这种模型的好方法是什么吗?因为我没有任何类别。我想尝试几种不同的距离度量(用于NN),以查看哪种方法最有效,但我希望有一种可靠的方法来知道每次更改后模型是否正在改进。 - Pawan Bhandarkar
1个回答

2
你的编辑出现错误的原因是因为 sklearn 期望一个二维输入,每个示例都在新行中。你可以使用 X.reshape(1, -1) 或者 [X],第一个更好一些。没有原始数据或适当的 MWE,很难确定出错的具体原因,但我猜测可能是将数据放入或取出 dataframe 时出了问题。请检查 X.shape 是否合理。
下面是我用来检查一切是否正常的示例:
from sklearn.neighbors import NearestNeighbors
from gensim.models import Word2Vec
import numpy as np

a = """Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea 
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla 
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est 
laborum."""
a = [x.split(' ') for x in a.split('\n') if len(x)]
model = Word2Vec(a, min_count=1)

# Get the average of all of the words to get data for a sentence
b = np.array([np.mean([model[xx] for xx in x], axis=0) for x in a])
# Check it's the correct shape
print b.shape

nbrs = NearestNeighbors(n_neighbors=2, algorithm='ball_tree').fit(b)

我想我的问题在于我正在使用一个pandas数据框来存储平均向量。 print(df['mean_vector'].shape) 给出(67680,),但是 X = df['mean_vector'].reshape(1, -1)nbrs = NearestNeighbors(n_neighbors=2, algorithm='ball_tree').fit(X) 仍然提示错误 setting an array element with a sequence. - Enzo
你的数据框中有多少个句子,是67680个吗?如果是,那么预计X的大小应该返回(67680,100) - piman314
看了你的例子(非常有用!),我有点觉得问题在于我的数据框的形状。不确定该如何解决... - Enzo
为了确保数据框的形状正确:print(df.shape)会返回(67680, 4),即行数和列数。在你的例子中,b.shape返回(5,100),非常不同!我有67680个句子,并且平均wordvec(一个包含100个条目的元组)存储在与句子相同的行中,这符合我的直觉。另一方面,我不清楚b.shape是什么意思。 - Enzo
b.shape 是句子数量 x 特征长度(100)的结果,所以如果我有和你一样多的例子,它会返回 (67680,100)df 的形状没问题,你需要关注的是 df['mean_vector'].shape,因为这是传递给 fit 函数的内容。 - piman314

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接