查找列表中列表之间的相关性的效率问题

时间:2016-08-14 14:10:48

标签: python scipy correlation

如果我有两个小列表,并且我想找到 list1 中每个列表与 list2 中每个列表之间的相关性,我可以这样做

from scipy.stats import pearsonr

list1 = [[1,2,3],[4,5,6],[7,8,9],[10,11,12]]
list2 = [[10,20,30],[40,50,60],[77,78,79],[80,78,56]]

corrVal = []
for i in list1:
    for j in list2:
        corrVal.append(pearsonr(i,j)[0])

print(corrVal)

OUTPUT: [1.0, 1.0, 1.0, -0.90112711377916588, 1.0, 1.0, 1.0, -0.90112711377916588, 1.0, 1.0, 1.0, -0.90112711377916588, 1.0, 1.0, 1.0, -0.90112711377916588]

这很好......几乎就是这样。 (编辑:刚刚注意到我上面的相关输出似乎给出了正确的答案,但是他们重复了4次。不完全确定为什么会这样做)

但是对于列表中包含1000个值的较大数据集,我的代码会无限期冻结,不会输出任何错误,因此每次都会强行退出IDE。我在这里滑倒的想法?不确定pearsonr函数可以处理多少或者我的编码是否导致问题存在固有的限制。

2 个答案:

答案 0 :(得分:3)

scipy模块scipy.spatial.distance包含一个称为Pearson's distance的距离函数,它只是1减去相关系数。通过在scipy.spatial.distance.cdist中使用参数metric='correlation',您可以有效地计算两个输入中每对向量的Pearson相关系数。

这是一个例子。我将修改您的数据,以便系数更加多样化:

In [96]: list1 = [[1, 2, 3.5], [4, 5, 6], [7, 8, 12], [10, 7, 10]]

In [97]: list2 = [[10, 20, 30], [41, 51, 60], [77, 80, 79], [80, 78, 56]]

所以我们知道会发生什么,这里是使用scipy.stats.pearsonr计算的相关系数:

In [98]: [pearsonr(x, y)[0] for x in list1 for y in list2]
Out[98]: 
[0.99339926779878296,
 0.98945694873927104,
 0.56362148019067804,
 -0.94491118252306794,
 1.0,
 0.99953863896044937,
 0.65465367070797709,
 -0.90112711377916588,
 0.94491118252306805,
 0.93453339271427294,
 0.37115374447904509,
 -0.99339926779878274,
 0.0,
 -0.030372836961539348,
 -0.7559289460184544,
 -0.43355498476205995]

在数组中查看它们会更方便:

In [99]: np.array([pearsonr(x, y)[0] for x in list1 for y in list2]).reshape(len(list1), len(list2))
Out[99]: 
array([[ 0.99339927,  0.98945695,  0.56362148, -0.94491118],
       [ 1.        ,  0.99953864,  0.65465367, -0.90112711],
       [ 0.94491118,  0.93453339,  0.37115374, -0.99339927],
       [ 0.        , -0.03037284, -0.75592895, -0.43355498]])

这里使用cdist计算的结果相同:

In [100]: from scipy.spatial.distance import cdist

In [101]: 1 - cdist(list1, list2, metric='correlation')
Out[101]: 
array([[ 0.99339927,  0.98945695,  0.56362148, -0.94491118],
       [ 1.        ,  0.99953864,  0.65465367, -0.90112711],
       [ 0.94491118,  0.93453339,  0.37115374, -0.99339927],
       [ 0.        , -0.03037284, -0.75592895, -0.43355498]])

使用cdist 比在嵌套循环中调用pearsonr更快。在这里,我将使用两个数组data1data2,每个数组的大小(100,10000):

In [102]: data1 = np.random.randn(100, 10000)

In [103]: data2 = np.random.randn(100, 10000)

我会在%timeit中使用方便的ipython命令来衡量执行时间:

In [104]: %timeit c1 = [pearsonr(x, y)[0] for x in data1 for y in data2]
1 loop, best of 3: 836 ms per loop

In [105]: %timeit c2 = 1 - cdist(data1, data2, metric='correlation')
100 loops, best of 3: 4.35 ms per loop

嵌套循环为836 ms,cdist为4.35 ms。

答案 1 :(得分:0)

进行相同的计算,但收集4x4数组中的值:

var viewModel =
    (from Wh in db.Werehouses
     join WhK in db.WerehouseKeys on Wh.WhID equals WhK.WhID into keys
     join Itm in db.Items on Wh.WhID equals Itm.WhID into items
     where Wh.WhID == id
     select new WerehouseViewModel
     { 
         Werehouse = Wh,
         WerehouseKeys = keys.ToList(),
         Items = items.ToList()
     })
    .FirstOrDefault();

In [1791]: res=np.zeros((4,4)) In [1792]: for i in range(4): ...: for j in range(4): ...: res[i,j]=stats.pearsonr(list1[i],list2[j])[0] ...: In [1793]: res Out[1793]: array([[ 1. , 1. , 1. , -0.90112711], [ 1. , 1. , 1. , -0.90112711], [ 1. , 1. , 1. , -0.90112711], [ 1. , 1. , 1. , -0.90112711]]) 的最后一个元素外,所有子列表都是相关的(例如[1,2,3]*n)。

随着2个列表变长,我可以看到这会减慢的速度。我不知道list2计算对输入的长度有多敏感。

pearsonr代码看起来很直接,没有循环来减慢速度。如果你可以跳过pearsonr值,它可能会更快;事先将每个子列表转换为零均值数组也可能会减少计算时间。

更改p次迭代以避免重新计算下三角形也可能有所帮助

j