[英]R: Calculate distance between consecutive points per group and group them
我在這方面遇到了困難...因此,我試圖在每個組中找到彼此接近的點,然后對它們進行分組。 讓我根據以下示例數據向您解釋:
Group X Y Z
1 110 3762 431 10
2 112 4950 880 10
3 113 5062 873 20
4 113 5225 874 30
5 113 5262 875 10
6 113 5300 874 20
structure(list(Group = c(110, 112, 113, 113, 113, 113), X = c(3762,
4950, 5062, 5225, 5262, 5300), Y = c(431, 880, 873, 874, 875,
874), Z = c(10, 10, 20, 30, 10, 20)), row.names = c(NA, -6L), class = "data.frame")
正如我們看到的,我們將分組列Group , X和Y列作為我們的坐標,並且在將點定義為“關閉”(歐幾里得距離<100)時, Z列應該進一步匯總。
我嘗試過的
我已經使用此函數成功計算了點之間的歐幾里得距離:
for(i in 1:nrow(test)) {
if(i > 1 && test$Group[i] == test$Group[i-1]) {
test$Distance[i] <- sqrt(((test$X[i] - test$X[i-1]) ^ 2) + ((test$Y[i] - test$Y[i-1]) ^ 2))
} else {
test$Distance[i] <- NA
}
}
這給了我這個:
Group X Y Z Distance
1 110 3762 431 10 NA
2 112 4950 880 10 NA
3 113 5062 873 20 NA
4 113 5225 874 30 163.00307
5 113 5262 875 10 37.01351
6 113 5300 874 20 38.01316
這里的一切都變得復雜,因為每個組的第一行都有NA。
我想實現的目標:
我想找到每個組的距離不大於100 ( 距離 <100)的點,並在此基礎上對其進行匯總( Z列的簡單總和)。 所以手動完成:
Group Z Grouped
1 110 10 no
2 112 10 no
3 113 20 no
4 113 60 yes
感謝幫助!
那很難。 我不確定我是否已經完全弄清楚了。
#get data and libraries
library(tidyverse)
df <- read.table(text = "
Group X Y Z Distance
1 110 3762 431 10 NA
2 112 4950 880 10 NA
3 113 5062 873 20 NA
4 113 5225 874 30 163.00307
5 113 5262 875 10 37.01351
6 113 5300 874 20 38.01316", header = T, stringsAsFactors = F)
df %>%
group_by(Group) %>%
do(melt(outer(.$Distance, .$Distance, `-`))) %>%
filter(between(value, -100, 0) | between(value, 0, 100)) %>%
distinct(Var1) %>%
mutate(grouped = 1) %>%
rename(row = Var1) -> rows
df %>%
group_by(Group) %>%
mutate(row = row_number()) %>%
left_join(rows, by = c("row", "Group")) %>%
mutate(grouped = ifelse(is.na(grouped), "no", "yes")) %>%
group_by(Group, grouped) %>%
mutate(Z = ifelse(!is.na(grouped), sum(Z), Z)) %>%
distinct(Group, Z, grouped)
# A tibble: 4 x 3
# Groups: Group, grouped [4]
Group Z grouped
<int> <int> <chr>
1 110 10 no
2 112 10 no
3 113 20 no
4 113 60 yes
希望這就是您要尋找的東西,如果沒有,也許它給了您一些新的想法。
更新 :現在,我希望能對您有所幫助:
df %>%
group_by(Group) %>%
mutate(int1 = lead(Distance) < 100 | Distance < 100,
int1 = replace(int1, is.na(int1), FALSE),
int2 = rleid(int1),
int2 = replace(int2, !int1 | is.na(int1), NA)) -> df2
df2 %>%
filter(int1) %>%
group_by(Group, int2) %>%
summarise(Z = sum(Z),
Grouped = "yes") %>%
select(Group, Z, Grouped) %>%
bind_rows(df2 %>%
filter(!int1) %>%
mutate(Grouped = "no") %>%
select(Group, Z, Grouped)) %>%
arrange(Group)
# A tibble: 4 x 3
# Groups: Group [3]
Group Z Grouped
<int> <int> <chr>
1 110 10 no
2 112 10 no
3 113 60 yes
4 113 20 no
我制定了一些用例,可以幫助您入門。 這是一種基於列向量的for循環和聚合的基本方法,您可以將成對的函數向量應用於列進行聚合。
df <- read.table(text = "
Group X Y Z Distance
1 110 3762 431 10 NA
2 112 4950 880 10 NA
3 113 5062 873 20 NA
4 113 5225 874 30 163.00307
5 113 5262 875 10 37.01351
6 113 5300 874 20 38.01316
7 114 5300 874 30 NA
8 114 5300 874 20 38.01316", header = T, stringsAsFactors = F)
aggregateIt <- function(df = data, #data.frame
returnRaw = F, #to get the raw unaggregted df (only first case from column `grouped` by `subgroup` usable in this application)
colsToAgg = c("Z1", "Z2", "Z3"), #cols to aggregate
how = c("sum", "sum", "max")) #how to aggregate the columns, `Z1` by sum, `Z2` by sum and `Z3` by max
{
count <- 1L
result <- vector("integer", nrow(df))
grouped <- vector("character", nrow(df))
for(i in seq_len(length(result)-1L)){
if(df$Group[i] != df$Group[i+1L]) {
result[i] <- count
grouped[i] <- "no"
count <- count + 1L
if((i+1L) == length(result)) {
result[i+1L] <- count
grouped[i+1L] <- "no"
}
} else {
if(df$Distance[i+1L] > 100L) {
result[i] <- count
grouped[i] <- "no"
count <- count + 1L
if((i+1L) == length(result)) {
result[i+1L] <- count
grouped[i+1L] <- "no"
}
} else {
result[i] <- count
grouped[i] <- "yes"
if((i+1L) == length(result)) {
result[i+1L] <- count
grouped[i+1L] <- "yes"
}
}
}
}
df <- within(df, {subgroup <- result; grouped <- grouped})
if(returnRaw) return(df)
A <- Reduce(function(a, b) merge(a, b, by = "subgroup"),
lapply(seq_along(how), function(x) aggregate(.~subgroup, df[, c(colsToAgg[x], "subgroup")], how[x])))
B <- df[!duplicated(df$subgroup, fromLast = F), c("Group", "subgroup", "grouped")]
out <- merge(A, B, by = "subgroup")
return(out[, c("Group", colsToAgg, "grouped")])
}
aggregateIt(df = df, colsToAgg = "Z", how = "sum")
# Group Z grouped
#1 110 10 no
#2 112 10 no
#3 113 20 no
#4 113 60 yes
#5 114 50 yes
並不是說這是最有效的解決方案,而是指出了解決方案。 希望這可以幫助!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.