我有两个数据集作为列表,例如:
xa = [1, 2, 3, 10, 1383, 0, 12, 9229, 2, 494, 10, 49]
xb = [1, 1, 4, 12, 1100, 43, 9, 4848, 2, 454, 6, 9]
系列是可能包含数万个数字的市场数据,其长度相同。
我需要在百分比中找到“差异”,这表示“百分比系列之间有多少相似/不相似”。
目前我有一个想法是为每个列表构建图表(xa,xb为 Y ax,范围(1,len(xa))为 X ax)。插入xa,xb的函数,然后计算xa,xb(带积分)的面积和xa和xb之间的差异面积。此后,不相似度为(差异区域)* 100%/(xa面积+ xb面积)。
我想知道这个问题是否有更简单的解决方案。 如果不是 - 我怎样才能计算xa,xb的差异面积?图表是用scipy,numpy,matplotlib构建的。
更新:我正在寻找代表集合之间差异的一个数字。百分之是优选的。
答案 0 :(得分:5)
如果你想要比较两个1D向量的相似性度量,并且最好返回0到1(或0到100%)之间的值, 余弦相似度 满足那些标准(最后的条件)。 (考虑到问题的背景,我不知道是否合适,但你知道背景,所以你当然可以做出决定。)
import numpy as NP
import numpy.linalg as LA
# generate some data
fnx = lambda : NP.random.randint(0, 10, 10)
s1, s2 = fnx(), fnx()
# a function to calculate cosine similarity
cx = lambda a, b : round(NP.inner(a, b)/(LA.norm(a)*LA.norm(b)), 2)
cx(s1, s2)
# returns 0.85
如果您有许多1D向量,那么一种方法可能是测量每个向量与中值向量的余弦相似性。
在一般情况下,余弦相似度返回介于-1和1之间的值,但在使用它的许多(大多数?)实际情况中,可能的值约束在0和1之间。
其次,余弦相似度的公式是点(a,b)/(范数(a)x范数(b)); NumPy有一个点函数,但是,inner是实现点积的NumPy函数。
答案 1 :(得分:3)
这在很大程度上取决于你所寻求的“相似性”的性质。
我想到了两个措施。
sqrt((X[i]-Y[i])^2)
或abs(X[i]-Y[i])
的总和,归一化为X和Y的范围,即从min(X,Y)到max(X,Y)。越接近0,数据集越相似。 sqrt版本对小差异更敏感。答案 2 :(得分:2)
这很大程度上取决于你想要做什么。例如,给出一个给定的例子,你可以想象计算一个但不是两个集合中的元素(两个集合的对称差异的长度) - 如果数字对应于测量,那么显然非常糟糕。
你说时间序列,我们可以假设订单很重要吗?
对于时间序列,计算频谱域中的事物通常是有益的,这是另外需要考虑的事情。只有一个数字的东西不太可能给你提供太多信息
答案 3 :(得分:1)
这是你在寻找什么?
xa = [1, 2, 3, 10, 1383, 0, 12, 9229, 2, 494, 10, 49]
xb = [1, 1, 4, 12, 1100, 43, 9, 4848, 2, 454, 6, 9]
xc = []
for i in range(0, len(xa)-1):
xc.append(xa[i] - xb[i])
print xc
输出:
[0, 1, -1, -2, 283, -43, 3, 4381, 0, 40, 4]
编辑:
为什么不采用每个值的百分比差异,然后平均全部:
from statlib import stats
xa = [1, 2, 3, 10, 1383, 0, 12, 9229, 2, 494, 10, 49]
xb = [1, 1, 4, 12, 1100, 43, 9, 4848, 2, 454, 6, 9]
xc = []
for i in range(0, len(xa)-1):
xc.append(abs(float(xa[i] - xb[i])/(xa[i] + xb[i])/2))
print stats.mean(xc)*100
如果你没有statlib,你可以得到它here
答案 4 :(得分:0)
from __future__ import division
from itertools import izip, repeat
import math
def weighted_mean(values, weights=None):
total = 0
number = 0
if weights is None:
weights = repeat(1)
for weight, value in izip(weights, values):
total += weight * value
number += weight
return number and total / number
xa = [1, 2, 3, 10, 1383, 0, 12, 9229, 2, 494, 10, 49]
xb = [1, 1, 4, 12, 1100, 43, 9, 4848, 2, 454, 6, 9]
print "Option 1, if you want bigger numbers to have a bigger effect on the score"
weights = (math.sqrt(abs(a) * abs(b)) for a, b in izip(xa, xb))
scores = (abs(a) + abs(b) and abs(a - b) / (abs(a) + abs(b)) for a, b in izip(xa, xb))
final_score = weighted_mean(scores, weights)
print "%.02f%%" % (final_score * 100)
print "Option 2, if you want to have all numbers have the same effect on the score"
scores = (abs(a) + abs(b) and abs(a - b) / (abs(a) + abs(b)) for a, b in izip(xa, xb))
final_score = weighted_mean(scores)
print "%.02f%%" % (final_score * 100)
当然,您也可以使用其他类型的权重,例如(abs(a) + abs(b)) / 2
,具体取决于您希望如何解释给定的差异。
第二个无环版:
xan = numpy.array(xa)
xbn = numpy.array(xb)
error_threshold = 0.000001
final_score = numpy.mean((abs(xan - xbn) + error_threshold) / (abs(xan) + abs(xbn) + error_threshold))
或者第一个:
scores = (abs(xan - xbn) + error_threshold) / (abs(xan) + abs(xbn) + error_threshold)
weights = numpy.sqrt(abs(xan) * abs(xbn))
final_score = numpy.sum(scores * weights) / numpy.sum(weights)