Linked Questions

Popular Questions

I am attempting to fit a plane using numpy's SVD method np.linalg.svd(). As a test, I will use two sets of points in R3. In both cases, all points have value 100 in the 3rd dimension. Since the set of points I created is perfectly within the Z=100 plane, I expect that:

  1. The third singular value will be 0 (within machine-precision).
  2. The third column of vh will be [0, 0, 1] (within machine-precision).

Set 1

For some points in this set, the first and second values have magnitudes much larger than the third value.

pts = [[2345,-124, 100], [981, -123, 100], [4987,12345, 100], [-1324, 0, 100]]
svd = np.linalg.svd(pts)

The result here is roughly as-expected:

svd[1] produces array([13349.56221861, 2705.21722461, 158.26983058]). I would expect the third singular value to be closer to 0, since my points fit perfectly into a plane, but it's at least clear enough to indicate that the third column of svd[2] will be my plane normal vector.

svd[2] produces the following:

array([[-0.38833201, -0.92148669, -0.00778029],
       [-0.92117922,  0.38840419, -0.02389612],
       [ 0.02504185, -0.00211259, -0.99968417]])

Again, it's close. I would expect the first two dimensions of the 3rd column to be closer to zero (more like within machine-precision) but this is workable for my fitting application.

Set 2

For all points in this set, the first and second values have magnitudes smaller than the third value.

pts = [[57, 37, 100], [34, 37, 100], [11, -37, 100], [-11, 38, 100]]
svd = np.linalg.svd(pts)

This is where things started to look pretty weird.

svd[1] produces array([209.35774076, 64.78329726, 46.58820429]). This is surprising. The third singular value should be closer to 0.

svd[2] produces the following:

array([[-0.23396901, -0.2018738 , -0.95105493],
       [ 0.31100035,  0.91126958, -0.26993803],
       [-0.92116084,  0.35893555,  0.15042602]])

This is extremely unexpected. The third column of vh is quite far from [0, 0, 1]. Certainly well outside machine precision. It's actually closer to [1, 0, 0].

What is going on here? Is there something about how the SVD is implemented in numpy that does not give higher precision results? Am I just not using it right or misinterpreting the results?

Related Questions