简体   繁体   English

在R中为3d点云拟合一条线

[英]Fit a line to 3d point cloud in R

I have point clouds (xyz-coordinates) that I need to fit a linear model to. 我有点云(xyz坐标),我需要适合线性模型。 I thought I'd use lm() for that. 我以为我会用lm()。

This is what I tried: 这是我试过的:

library(scatterplot3d)

# example points
x <- c(1,4,3,6,2,5)
y <- c(2,2,4,3,5,9)
z <- c(1,3,5,9,2,2)

# plot    
s <- scatterplot3d(x,y,z, type="b")

# fit the model
ff = lm(z ~ x + y) ## in ff$coefficients are the line paramters z, mx, ny

# create coordinates for a short line (the fit) to plot
llx = c(min(x), max(x))
lly = c(min(y), max(y))
llz = c(
  ff$coefficients[[1]] + llx[1] * ff$coefficients[[2]] + lly[1] * ff$coefficients[[3]],
  ff$coefficients[[1]] + llx[2] * ff$coefficients[[2]] + lly[2] * ff$coefficients[[3]]
)

## create 2d coordinates to place in scatterplot
p0 <- s$xyz.convert(llx[1],lly[1],llz[1])
p1 <- s$xyz.convert(llx[2],lly[2],llz[2])

# draw line
segments(p0$x,p0$y,p1$x,p1$y,lwd=2,col=2)  

Although, the red line looks convincingly like a fit I'm not sure it is. 虽然,红线看起来令人信服,但我不确定它是否合适。 If you rotate the plot, it doesn't look very good. 如果旋转绘图,它看起来不太好。

for(i in seq(from=30, to=60, by=1)){
  s <- scatterplot3d(x,y,z, type="b", angle=i)
  segments(p0$x,p0$y,p1$x,p1$y,lwd=2,col=2)  
  Sys.sleep(0.1)
}

Is this just due to 2d projection of the line?!? 这只是由于线的2d投影?!? Can you somehow update the coordinates? 你能以某种方式更新坐标吗? I tried to give the $xyz.convert() function an "angle" attribute, without luck. 我试图给$ xyz.convert()函数一个“角度”属性,没有运气。

Also, when I use only two example points the fit fails. 此外,当我仅使用两个示例点时,拟合失败。

x <- c(1,4)
y <- c(2,5)
z <- c(1,3)

I'd appreciate a confirmation whether I use lm() correctly. 我很欣赏确认我是否正确使用lm()。 Thanks! 谢谢!

[EDIT] [编辑]

I learned that lm() fitted a plane to the data based on the model I gave it (z~x+y). 我了解到lm()根据我给出的模型(z~x + y)为数据拟合了一个平面。 This was not what I wanted. 这不是我想要的。 In fact, I misunderstood lm() entirely. 事实上,我完全误解了lm()。 Also for 2d data. 也适用于2d数据。 Eg lm(y~x) tries to minimize the vertical space between fit and data. 例如,lm(y~x)试图最小化拟合和数据之间的垂直空间。 But, I wanted the data to be treated as completely independent (spatial data) and minimize the perpendiculars between fit and data (as first paragraph here: http://mathpages.com/home/kmath110.htm ). 但是,我希望将数据视为完全独立(空间数据)并最小化拟合和数据之间的垂直(如第一段所述: http//mathpages.com/home/kmath110.htm )。

The answer marked as correct does exactly this. 标记为正确的答案就是这样。 The principle is called "principal component analysis". 该原理称为“主成分分析”。

lm(z ~ x + y) 's fit points make not a line but a plane. lm(z ~ x + y)的拟合点不是一条线而是一条平面。 Your segment indeed belongs to the plane. 您的细分确实属于飞机。

s <- scatterplot3d(x,y,z, type="b")
s$plane3d(ff)
segments(p0$x,p0$y,p1$x,p1$y,lwd=2,col=2) 

# rgl
library(rgl)
plot3d(x, y, z, type="s", rad=0.1)
planes3d(ff$coef[2], ff$coef[3], -1, ff$coef[1], col = 4, alpha = 0.3)
segments3d(llx, lly, llz, lwd=2, col=2) 

在此输入图像描述

[EDITED] [EDITED]

What you want is to fit a line to 3-dimensional data, in other words, summarize 3-dim into 1-dim. 你想要的是将一条线拟合到三维数据,换句话说,将三维变为1-dim。 I think the line consists of principal component analyze's 1st component (ie, mean + t * PC1 , this line minimizes total least squares). 我认为该线由主成分分析的第一个成分组成(即, 平均值+ t * PC1 ,该线最小化总最小平方)。 I referred to " R mailing help: Fit a 3-Dimensional Line to Data Points " and " MathWorks: Fitting an Orthogonal Regression Using Principal Components Analysis ". 我提到“ R邮件帮助:为数据点 拟合 三维线 ”和“ MathWorks:使用主成分分析拟合正交回归 ”。

x <- c(1,4,3,6,2,5)
y <- c(2,2,4,3,5,9)
z <- c(1,3,5,9,2,2)

xyz <- data.frame(x = x, y = y, z = z)
N <- nrow(xyz) 

mean_xyz <- apply(xyz, 2, mean)
xyz_pca   <- princomp(xyz) 
dirVector <- xyz_pca$loadings[, 1]   # PC1

xyz_fit <- matrix(rep(mean_xyz, each = N), ncol=3) + xyz_pca$score[, 1] %*% t(dirVector) 

t_ends <- c(min(xyz_pca$score[,1]) - 0.2, max(xyz_pca$score[,1]) + 0.2)  # for both ends of line
endpts <- rbind(mean_xyz + t_ends[1]*dirVector, mean_xyz + t_ends[2]*dirVector)

library(scatterplot3d) 
s3d <- scatterplot3d(xyz, type="b")
s3d$points3d(endpts, type="l", col="blue", lwd=2)
for(i in 1:N) s3d$points3d(rbind(xyz[i,], xyz_fit[i,]), type="l", col="green3", lty=2)

library(rgl)
plot3d(xyz, type="s", rad=0.1)
abclines3d(mean_xyz, a = dirVector, col="blue", lwd=2)     # mean + t * direction_vector
for(i in 1:N) segments3d(rbind(xyz[i,], xyz_fit[i,]), col="green3")

在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM