2016-04-24 45 views
0

我想要計算三維點之間的歐幾里得距離,並將該距離作爲附加列添加。我試圖遍歷行,像這樣:在數據框中的相鄰行之間執行計算

df1 <- as.data.frame(list('x'=1:5,'y'=(1:5)^2,'z'=6:10)) 

for (i in 2:nrow(df1)) { 
    df1$diff <- sqrt((df1$x[i,]-df1$x[i-1,])^2 - 
        (df1$y[i,]-df1$y[i-1,])^2 - 
        (df1$z[i,]-df1$z[i-1,])^2) 
} 

,但我得到的錯誤:

Error in df1$x[i, ] : incorrect number of dimensions 

我要去哪裏錯了?

+0

也許'sqrt(abs(Reduce(' - ',lapply(df1,function(x)(x-lag(x,default = x [1]))^ 2))))'或'c(0,sqrt (abs(Reduce(' - ',as.data.frame((sapply(df1,diff))^ 2)))))' – akrun

回答

2

的主要問題是,你是治療x當索引時是一個類似數組的對象。即您正在使用x[row, col]索引,您應該使用x[element]

將結果插入到df1$diff時,還需要編入索引。你有歐幾里得距離方程是錯誤的;你需要加起來的平方差,而不是減去它們。

df1 <- data.frame(list(x = 1:5, y = (1:5)^2, z = 6:10)) 
df1$diff <- NA 

for (i in 2:nrow(df1)) { 
    df1$diff[i] <- with(df1, sqrt((x[i] - x[i-1])^2 + 
           (y[i] - y[i-1])^2 + 
           (z[i] - z[i-1])^2)) 
} 

> df1 
    x y z  diff 
1 1 1 6  NA 
2 2 4 7 3.316625 
3 3 9 8 5.196152 
4 4 16 9 7.141428 
5 5 25 10 9.110434 

你並不需要爲這個循環,雖然,你可以依靠R上做元素乘元素的操作,因此這樣做在一個單一的步驟:

df1 <- data.frame(list(x = 1:5, y = (1:5)^2, z = 6:10)) 
df1$diff <- c(NA, sqrt(rowSums((df1[-1, 1:3] - df1[-5, 1:3])^2))) 

df1 

> df1 
    x y z  diff 
1 1 1 6  NA 
2 2 4 7 3.316625 
3 3 9 8 5.196152 
4 4 16 9 7.141428 
5 5 25 10 9.110434 

你可能會如果你真正的問題很大,想要用df1強制執行此操作,因爲數據幀非常慢。

m1 <- as.matrix(df1[, 1:3]) 
m1 <- cbind(m1, diff = c(NA, sqrt(rowSums((m1[-1, 1:3] - m1[-5, 1:3])^2)))) 

> m1 
    x y z  diff 
[1,] 1 1 6  NA 
[2,] 2 4 7 3.316625 
[3,] 3 9 8 5.196152 
[4,] 4 16 9 7.141428 
[5,] 5 25 10 9.110434 

你可以用這個進入使用head()tail()所以你do't功能需要擔心的原始數據有多少行有:

myEuc <- function(x) { 
    if (isdf <- is.data.frame(x)) { 
    x <- data.matrix(x) 
    } 
    dij <- c(NA, sqrt(rowSums((tail(x, -1) - head(x, -1))^2))) 
    x <- cbind(x, diff = dij) 
    if (isdf) { 
    x <- as.data.frame(x) 
    } 
    x 
} 

df1 <- data.frame(list(x = 1:5, y = (1:5)^2, z = 6:10)) 
myEuc(df1) 

> myEuc(df1) 
    x y z  diff 
    1 1 6  NA 
[2,] 2 4 7 3.316625 
[3,] 3 9 8 5.196152 
[4,] 4 16 9 7.141428 
[5,] 5 25 10 9.110434 
+0

謝謝你,謝謝你在這個等式中捕捉到我非常愚蠢的錯誤。 –

+1

謝謝。你可以做到這一點沒有循環。給我一秒鐘,我會發布更簡單的代碼。 –

0

您的新變量有一個比你少data.frame的意見,所以你需要添加一個NA到頂部或載體的底部:

df1 <- as.data.frame(list('x'=1:5,'y'=(1:5)^2,'z'=6:10)) 

myVec <- numeric(nrow(df1)) 
myVec[1] <- NA 
for (i in 2:nrow(df1)) { 
myVec[i] <- sqrt((df1[i,"x"]-df1[i-1,"x"])^2 + 
       (df1[i,"y"]-df1[i-1,"y"])^2 + 
       (df1[i,"z"]-df1[i-1,"z"])^2) 
} 

df1$diff <- myVec 
+0

我在第一部分出現錯誤myVec < - ... '。我將「df」更改爲「df1」,但得到錯誤「向量中的錯誤(nrow(df1)):vector:無法創建模式'​​5'的向量。」 –

+0

@Adam_G我認爲我從第一輪的草率修改了「許多」錯別字。 – lmo

1

這裏是另一種選擇

sqrt(Reduce('+',lapply(df1, function(x) (x- lag(x, default=x[1]))^2))) 
#[1] 0.000000 3.316625 5.196152 7.141428 9.110434 

c(0,sqrt(rowSums((sapply(df1, diff))^2))) 
#[1] 0.000000 3.316625 5.196152 7.141428 9.110434