从同一矩阵中的所有其他行值中减去行值
Substract row-values from all other row-values in same matrix
我有一个包含地理位置(两列)和 presence/abstinence 数据 (0/1) 的数据框。我需要找出的是,有多少其他位置位于其附近且值为 1。然后应将该数字附加到第四列中。
xcoords <- c(4487754, 4488111, 4487598, 4487417, 4487949, 4487802, 4488011, 4487638, 4487455, 4487478, 4487141, 4487550, 4487547, 4488010, 4487271, 4487170)
ycoords <- c(5294654, 5294706, 5295490, 5293859, 5295313, 5294910, 5294668, 5295399, 5294537, 5294408, 5294927, 5294617, 5294727, 5294953, 5294168, 5295142)
yesno <- round(runif(16, 0, 1),0)
df <- cbind(xcoords, ycoords, yesno)
我将附近设置为500米(地理数据在投影坐标系中,因此单位对应),并使用毕达哥拉斯定理进行计算。
buffer <- 500
我所知道的是如何构建嵌套的 for 循环。但我不希望我的函数看起来像这样:
count.in.buffer <- function(df, buffer){
lon <- df$xcoords
lat <- df$ycoords
count <- rep(0, length(lon))
for(i in 1:length(lon)){ # for every row...
for(j in 1:length(lon) - 1){ # ... check all other rows
nolon <- lon[-i]
nolat <- lat[-i]
ifelse(sqrt((abs(lon[i] - nolon[j]))^2 + (abs(lat[i] - nolat[j]))^2) < buffer, ifelse(df$yesno == 1, count[i] <- count[i] + 1, count[i] <- count[i] + 0), count[i] <- count[i] + 0)
}
}
result <- cbind(data, count)
return(result)
}
这需要很长时间才能计算出来,因为我的数据框实际上有 67000 行。
相反,我想要更高效的东西,但我不明白如何将内部 for 循环转换为我可以在整个数据框的应用函数中逐行使用的函数。但我确实怀疑,应用函数是可行的方法,对吧?
P.S.: 我已经使用适当的 GIS 解决了这个问题,方法是在每个数据点周围创建缓冲区多边形并将其他数据点链接到每个缓冲区多边形的属性 table,如果它们位于在该缓冲区内。但我认为在 R 中做起来应该快得多。
您可以尝试将其移动到应用语句中,并将您的数据子集化为具有值的数据。
首先,制作一个新的 df,只有那些在 yesno 中有 1s 的 df(没有计算那些不求和的距离):
df1 <- df[df[ ,'yesno'] == 1,]
然后,我们以向量化的方式将 df 的每一行与 df1 的所有行进行比较,并对计数求和(减去我们的初始计数,因此我们不会计数两次):
apply(df, 1, function(x){
sum(sqrt((x[1] - df1[ ,1])^2 +
(x[2] - df1[ ,2])^2) < buffer) - x[3]
})
我有一个包含地理位置(两列)和 presence/abstinence 数据 (0/1) 的数据框。我需要找出的是,有多少其他位置位于其附近且值为 1。然后应将该数字附加到第四列中。
xcoords <- c(4487754, 4488111, 4487598, 4487417, 4487949, 4487802, 4488011, 4487638, 4487455, 4487478, 4487141, 4487550, 4487547, 4488010, 4487271, 4487170)
ycoords <- c(5294654, 5294706, 5295490, 5293859, 5295313, 5294910, 5294668, 5295399, 5294537, 5294408, 5294927, 5294617, 5294727, 5294953, 5294168, 5295142)
yesno <- round(runif(16, 0, 1),0)
df <- cbind(xcoords, ycoords, yesno)
我将附近设置为500米(地理数据在投影坐标系中,因此单位对应),并使用毕达哥拉斯定理进行计算。
buffer <- 500
我所知道的是如何构建嵌套的 for 循环。但我不希望我的函数看起来像这样:
count.in.buffer <- function(df, buffer){
lon <- df$xcoords
lat <- df$ycoords
count <- rep(0, length(lon))
for(i in 1:length(lon)){ # for every row...
for(j in 1:length(lon) - 1){ # ... check all other rows
nolon <- lon[-i]
nolat <- lat[-i]
ifelse(sqrt((abs(lon[i] - nolon[j]))^2 + (abs(lat[i] - nolat[j]))^2) < buffer, ifelse(df$yesno == 1, count[i] <- count[i] + 1, count[i] <- count[i] + 0), count[i] <- count[i] + 0)
}
}
result <- cbind(data, count)
return(result)
}
这需要很长时间才能计算出来,因为我的数据框实际上有 67000 行。
相反,我想要更高效的东西,但我不明白如何将内部 for 循环转换为我可以在整个数据框的应用函数中逐行使用的函数。但我确实怀疑,应用函数是可行的方法,对吧?
P.S.: 我已经使用适当的 GIS 解决了这个问题,方法是在每个数据点周围创建缓冲区多边形并将其他数据点链接到每个缓冲区多边形的属性 table,如果它们位于在该缓冲区内。但我认为在 R 中做起来应该快得多。
您可以尝试将其移动到应用语句中,并将您的数据子集化为具有值的数据。
首先,制作一个新的 df,只有那些在 yesno 中有 1s 的 df(没有计算那些不求和的距离):
df1 <- df[df[ ,'yesno'] == 1,]
然后,我们以向量化的方式将 df 的每一行与 df1 的所有行进行比较,并对计数求和(减去我们的初始计数,因此我们不会计数两次):
apply(df, 1, function(x){
sum(sqrt((x[1] - df1[ ,1])^2 +
(x[2] - df1[ ,2])^2) < buffer) - x[3]
})