【问题标题】:How to calculate euclidian distance within group in R如何在R中计算组内的欧几里得距离
【发布时间】:2017-08-10 17:26:29
【问题描述】:

如果我有这样的数据框:

ID GroupID X  Y
1   a      772.7778 226.5
1   a      806.5645 35.3871
1   a      925.5714 300.9286
1   b      708.0909 165.5455
1   b      630.8235 167.4118
2   a      555.3333 151.875
2   a      732.8947 462.3158

这是我想要的结果:

ID GroupID X        Y        Distance
1   a      772.7778 226.5    NA
1   a      806.5645 35.3871  dist between((772.7778,226.5),(806.5645,35.3871))
1   a      925.5714 300.9286 dist between((925.5714,300.9286),(806.5645,35.3871))
1   b      708.0909 165.5455 NA
1   b      630.8235 167.4118 dist between((708.0909,165.5455),(630.8235,167.4118))
2   a      555.3333 151.875  NA
2   a      732.8947 462.3158 dist between((732.8947,462.3158),(555.3333,151.875))

基本上是ID和GroupID之间的距离。这里的 NA 表示在每个子组中(例如 ID=1;GroupID=a),第一个距离是 NA。有没有人可以帮助我?谢谢!!!

【问题讨论】:

  • dist 很好。
  • @ycw,它们是数值,这里的 x1 x2 只是为了表明它们是不同的值。
  • @ycw 已更改,感谢提示
  • @StevenBeaupré 我试过 dplyr
  • @alistaire 谢谢,我试过了,它有效,但我需要用子组计算值。

标签: r euclidean-distance


【解决方案1】:

以前从未使用过dist,但这里有一个可能对您有用的for 循环:

> for(i in 1:nrow(df)) {
  if(i > 1 && df$GroupID[i] == df$GroupID[i-1]) {
   df$Distance[i] <- sqrt(((df$X[i] - df$X[i-1]) ^ 2) + ((df$Y[i] - df$Y[i-1]) ^ 2))
  } else {
     df$Distance[i] <- NA
    }
  }

> df
  ID GroupID        X        Y  Distance
1  1       a 772.7778 226.5000        NA
2  1       a 806.5645  35.3871 194.07648
3  1       a 925.5714 300.9286 290.98957
4  1       b 708.0909 165.5455        NA
5  1       b 630.8235 167.4118  77.28994
6  2       a 555.3333 151.8750        NA
7  2       a 732.8947 462.3158 357.63325

【讨论】:

  • 感谢您的解决方案。但如果是欧几里得距离,它应该类似于 sqrt((df$X[i] - df$X[i-1])^2 + (df$Y[i] - df$Y[i-1) ^2)。对于 NA 值,我尝试将其放在每个子组中的第一个距离,而不是偶数行。你能帮我改变这部分吗?
  • @ycw, coco - 我的错。我应该研究欧几里得距离。我采用了简单的数字并将其应用于问题前面发布的示例数据框。一旦我弄清楚了,我会编辑我的答案。
  • @ycw, coco - 更新后的loop 返回正确的距离。
【解决方案2】:

这是使用dplyr 并使用dist 计算欧式距离的解决方案:

library(dplyr)

df <- read.table(text = "
  ID  GroupID X        Y
  1   a      772.7778 226.5
  1   a      806.5645 35.3871
  1   a      925.5714 300.9286
  1   b      708.0909 165.5455
  1   b      630.8235 167.4118
  2   a      555.3333 151.875
  2   a      732.8947 462.3158", header = T, stringsAsFactors = F)

df %>%
  group_by(ID, GroupID) %>%
  mutate(rows = row_number()) %>%
  left_join(df, by = c('ID', 'GroupID')) %>%
  rowwise() %>%
  mutate(Distance = ifelse(dist(rbind(c(X.x, Y.x), c(X.y, Y.y))) != 0,
                           dist(rbind(c(X.x, Y.x), c(X.y, Y.y))),
                           NA)) %>%
  filter(rows == 1) %>%
  select(ID, GroupID, X = X.y, Y= Y.y, Distance)

##      ID GroupID        X        Y  Distance
##   <int>   <chr>    <dbl>    <dbl>     <dbl>
## 1     1       a 772.7778 226.5000        NA
## 2     1       a 806.5645  35.3871 194.07648
## 3     1       a 925.5714 300.9286 169.95735
## 4     1       b 708.0909 165.5455        NA
## 5     1       b 630.8235 167.4118  77.28994
## 6     2       a 555.3333 151.8750        NA
## 7     2       a 732.8947 462.3158 357.63325

【讨论】:

  • 谢谢!我刚刚更新了我的问题描述,这里的 NA 不是每个偶数行,它是每个子组的值,比如 id=1 和 groupid = a。你能帮我修复这部分吗?
  • 我根据新信息进行了更改。如果这仍然不是您想要的,请告诉我。
  • X栏数据有误,还是谢谢大家帮忙!
  • 你是对的!错误地抓住了错误的列。刚刚在最后一行更改了它,select。而不是将X.x 作为X 列,它实际上是X.y。我想现在你得到了你想要的。
【解决方案3】:

为什么不试试这样的:

根据 ID 的组合拆分数据,应用距离函数,然后取消拆分?

splitted <- split(dat[,c("X","Y")], paste(dat$ID,dat$GroupID))

distances <- lapply(splitted, function(x) {
 if(nrow(x) > 2){ # diag() is useless for <= 2x2 matrix
   c(NA,diag(as.matrix(dist(x))[,-1]))
 } else {
   c(NA,dist(x)[1])
 }
})

dat$distances <- unsplit(distances, paste(dat$ID,dat$GroupID))

dat
  ID GroupID        X        Y distances
1  1       a 772.7778 226.5000        NA
2  1       a 806.5645  35.3871 194.07648
3  1       a 925.5714 300.9286 290.98957
4  1       b 708.0909 165.5455        NA
5  1       b 630.8235 167.4118  77.28994
6  2       a 555.3333 151.8750        NA
7  2       a 732.8947 462.3158 357.63325

旁注:如果每组超过 10k 行,dist 会变慢。

【讨论】:

    猜你喜欢
    • 2021-01-31
    • 1970-01-01
    • 1970-01-01
    • 2021-02-28
    • 1970-01-01
    • 2018-08-26
    • 1970-01-01
    • 1970-01-01
    • 2014-11-03
    相关资源
    最近更新 更多