我希望使用奇异值分解来估计eliptoid数据的标准偏差。我不确定这是否是最好的方法,我可能会过度思考整个过程,所以我需要一些帮助。
我使用以下脚本模拟了一些数据......
from matplotlib import pyplot as plt
import numpy
def svd_example():
# simulate some data...
# x values have standard deviation 3000
xdata = numpy.random.normal(0, 3000, 5000).reshape(-1, 1)
# y values standard deviation 300
ydata = numpy.random.normal(0, 300, 5000).reshape(-1, 1)
# apply some rotation
ydata_rotated = ydata + (xdata * 0.5)
data = numpy.hstack((xdata, ydata_rotated))
# get singular values
left_singular_matrix, singular_values, right_singular_matrix = numpy.linalg.svd(data)
print 'singular values', singular_values
# plot data....
plt.scatter(data[:, 0], data[:, 1], s=5)
plt.ylim(-15000, 15000)
plt.show()
svd_example()
我得到奇异的......
>>> singular values [ 234001.71228678 18850.45155942]
我的数据看起来像这样......
我假设奇异值会给我一些数据传播的指示,无论它的轮换如何,对吧?但这些价值观[234001.71228678 18850.45155942]对我来说毫无意义。我的标准偏差是3000和300.这些奇异值是否代表方差?我该如何转换它们?
答案 0 :(得分:1)
奇异值确实给出了传播的一些指示。实际上,它们与这些方向的标准偏差有关。但是,它们没有正常化。如果除以数字样本的平方根,您将得到与用于创建数据的标准偏差非常相似的值:
singular_values / np.sqrt(5000)
# array([ 3398.61320614, 264.00975837])
为什么你得到3400和264而不是3000和300?这是因为ydata + (xdata * 0.5)
不是旋转而是剪切操作。真正的旋转将保留原始的标准偏差。
例如,以下代码将数据旋转40度:
# apply some rotation
s = numpy.sin(40 * numpy.pi / 180)
c = numpy.cos(40 * numpy.pi / 180)
data = numpy.hstack((xdata, ydata)).dot([[c, s], [-s, c]])
通过这样的旋转,您将获得与原始标准偏差非常接近的标准化奇异值。
修改强> 关于规范化
我不得不承认,规范化可能不适合在这里适用。它并不一定意味着将值缩放到特定范围。正如我所说,归一化是将值带入一个定义的范围,与样本数量无关。
为了理解除sqrt(5000)
之间的除法,让我们来谈谈标准偏差。设x
为n
样本的数据向量,均值为零。然后标准偏差计算为sqrt(sum(x**2)/n)
或sqrt(sum(x**2)) / sqrt(n)
。现在,你可以想到奇异值分解只计算sqrt(sum(x**2))
部分,所以我们必须自己除sqrt(n)
。
我担心,这不是一个非常数学的解释,但希望它传达了这个想法。