Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
R 循环并查找子组的最近数据点_R_Dplyr_Distance - Fatal编程技术网

R 循环并查找子组的最近数据点

R 循环并查找子组的最近数据点,r,dplyr,distance,R,Dplyr,Distance,我试图复制在中所做的工作,但实际上是针对数据帧中的每个区域而不是整个组 我的数据(不要问)如下所示: id printid areaname latitude longitude 1 7912048 233502729 073 36.06241 -80.44229 2 735253 171241999 Area 12-06 35.54452 -78.75388 3 4325564 85564887 Area 12-04 35.49328 -78

我试图复制在中所做的工作,但实际上是针对数据帧中的每个区域而不是整个组

我的数据(不要问)如下所示:

     id      printid     areaname latitude longitude
1  7912048 233502729     073    36.06241 -80.44229
2   735253 171241999 Area 12-06 35.54452 -78.75388
3  4325564  85564887 Area 12-04 35.49328 -78.73756
4  4222241  85461255 Area 12-06 35.53621 -78.75553
5 11997754 356053648 Area 12-04 35.49328 -78.73756
6 13444458 536073775 Area 12-06 35.53987 -78.74922
我想为每个区域名运行函数。我尝试调用split,但distance函数无法调用列表

splitfile <- split(ncbaby, ncbaby$precinctname)

c <- gDistance(splitfile, byid=TRUE)

Error in (function (classes, fdef, mtable)  : 
unable to find an inherited method for function ‘is.projected’ for signature ‘"list"’

splitfile我查看了链接的帖子,并对想法做了一些修改。我认为对于大型数据集,使用
apply()
可能不是一个好主意。所以我采用了数据表相关的方法。首先,我将示例数据转换为空间点数据帧。然后,我用一个组变量(即group)拆分数据。正如Eddie所建议的,我将
lappy()
与data.table函数结合使用。使用
gDistance()
时,将二维向量作为输出。我将其转换为data.table对象,以便后续的数据处理可能会更快。我用
melt()
重塑了dt对象的形状,并删除了距离为0的所有数据点。最后,我为每个
Var1
取第一行。请注意,
Var1
这里表示样本数据的每一行,
mydf
。最后一项工作是将新的距离向量添加到原始数据帧中。我希望这对你有帮助

资料

代码

库(sp)
图书馆(rgeos)
库(数据表)
#复制原件

temp这里有一个解决方案,它将链接帖子中的解决方案调整为按区域分开的组。首先,我们定义两个函数:

library(sp)
library(rgeos)

nearest.neighbor <- function(lon,lat) {
  df <- data.frame(lon,lat)
  coordinates(df) <- ~lon+lat
  d <- gDistance(df, byid=TRUE)
  # remove the self distance from being considered and use which.min to find the nearest neighbor
  d[cbind(1:nrow(d),1:nrow(d))] <- NA
  min.d <- rbind(apply(d,1,function(x) {ind <- which.min(x); list(ind=ind,distance=x[ind])}))
}

order.by.ind <- function (x,ind) x[ind]
注:

  • 第一个
    mutate
    创建一个临时列
    min.d
    ,其中包含
    ind
    distance
    到最近邻居的列表。这是该地区最近的邻居,因为我们是
    groupby
    areaname
  • 第二个
    mutate\u each
    vars
    中的每个变量创建一个新列,方法是根据
    ind
    对该列重新排序。请注意,我们从
    min.d
    中提取
    ind
    ,方法是取消列出,然后使用
    [c(TRUE,FALSE)]
    提取奇数元素
  • 第三个
    mutate
    通过从
    min.d
    中提取
    distance
    来创建
    distance
    列。同样,这是通过取消列表,然后使用
    [c(FALSE,TRUE)]
    提取偶数元素
  • 实际上不需要第四个
    mutate
    ,因为
    .Areaname
    列对于结果中的
    Areaname
    是多余的
  • 最后,我们从结果中删除
    min.d
    列,并根据需要设置结果数据帧的列名
  • 使用您的数据得出的结果是:

    print(result)
    ##Source: local data frame [7 x 11]
    ##Groups: areaname [3]
    ##
    ##        id   printid   areaname latitude longitude     n.ID n.printid n.latitude n.longitude    distance  .Areaname
    ##     <int>     <int>     <fctr>    <dbl>     <dbl>    <int>     <int>      <dbl>       <dbl>       <dbl>     <fctr>
    ##1  7912048 233502729        073 36.06241 -80.44229  7912049 233502730   36.06251   -80.44329 0.001004988        073
    ##2   735253 171241999 Area 12-06 35.54452 -78.75388 13444458 536073775   35.53987   -78.74922 0.006583168 Area 12-06
    ##3  4325564  85564887 Area 12-04 35.49328 -78.73756 11997754 356053648   35.49328   -78.73756 0.000000000 Area 12-04
    ##4  4222241  85461255 Area 12-06 35.53621 -78.75553 13444458 536073775   35.53987   -78.74922 0.007294635 Area 12-06
    ##5 11997754 356053648 Area 12-04 35.49328 -78.73756  4325564  85564887   35.49328   -78.73756 0.000000000 Area 12-04
    ##6 13444458 536073775 Area 12-06 35.53987 -78.74922   735253 171241999   35.54452   -78.75388 0.006583168 Area 12-06
    ##7  7912049 233502730        073 36.06251 -80.44329  7912048 233502729   36.06241   -80.44229 0.001004988        073
    
    打印(结果)
    ##来源:本地数据帧[7 x 11]
    ##分组:区域名称[3]
    ##
    ##id printid AREA名称纬度经度id printid纬度经度距离AREA名称
    ##                                                          
    ##1  7912048 233502729        073 36.06241 -80.44229  7912049 233502730   36.06251   -80.44329 0.001004988        073
    ##2 735253 171241799区域12-06 35.54452-78.75388 13444458 536073775 35.53987-78.74922 0.006583168区域12-06
    ##3 4325564 85564887区域12-04 35.49328-78.73756 11997754 356053648 35.49328-78.73756 0.000000000区域12-04
    ##4 4222241 85461255区域12-06 35.53621-78.75553 13444458 536073775 35.53987-78.74922 0.007294635区域12-06
    ##5 11997754 356053648区域12-04 35.49328-78.73756 4325564 85564887 35.49328-78.73756 0.000000000区域12-04
    ##6 13444458 536073775区域12-06 35.53987-78.74922 735253 171241395.54452-78.75388 0.006583168区域12-06
    ##7  7912049 233502730        073 36.06251 -80.44329  7912048 233502729   36.06241   -80.44229 0.001004988        073
    

    其中,我为
    areaname=“073”
    添加了一个新行,以便每个区域至少有两行。

    请指定使用的库。gDistance不是base R的一部分。添加了,抱歉遗漏,感谢编辑帮助/建议。我很困惑。您说函数不会调用列表,但这里的问题是它只会抛出最后一个返回的值。那是哪一个呢?功能不工作吗?还是会产生不想要的结果?立即,可以看到您的
    for
    循环每次都会覆盖数据帧。感谢@Parfait提出问题并指出for循环项。我添加了失败的函数调用。您是否有关于使for循环附加而不是覆盖的指导?您需要使用lappy或tapply函数而不是循环。看看这个,你说gDistance是一个二维向量,也就是矩阵(?),有一种方法可以直接在Reforme2中熔化矩阵。@Frank你是说
    melt(gDistance(x,byid=TRUE)
    就够了吗?是的,我想可以,但只有安装了Reforme2才能工作(我从加载data.table时的
    melt
    源代码中收集的信息)。@Frank谢谢你的帮助。我修改了上面的代码。@akrun听到这个消息我很高兴,谢谢你的鼓励。
    library(sp)
    library(rgeos)
    library(data.table)
    
    # Copy the original
    temp <- mydf
    
    #DF to SPDF
    coordinates(temp) <- ~longitude+latitude
    
    # Split the data by a group variable
    mylist <- split(temp, f = temp$group)
    
    #For each element in mylist, apply gDistance, reshape the output of
    # gDistance and create a data.table. Then, reshape the data, remove
    # rows with distance = 0. Finally, choose the first row for each 
    # variable. levels in variable represents rows in mydf.
    
    out <- rbindlist(
            lapply(mylist, function(x){
    
               d <- setDT(melt(gDistance(x, byid = TRUE)))
               setorder(d, Var1, value)
               d <- d[value > 0]
               d <- d[, .SD[1], by = Var1]
               d 
    
            })
        )
    
    out <- cbind(mydf, distance = out$value)
    
    #   group user_id  latitude longitude     distance
    #1    B23   85553 -34.44011  172.6954 1.743945e-03
    #2    B23   85553 -34.43929  172.6939 1.661118e-03
    #3    B23   85553 -34.43929  172.6939 1.661118e-03
    #4    B23   85553 -34.43851  172.6924 1.661118e-03
    #5    B23   57357 -34.42747  172.6778 1.836642e-02
    #6    B23   57357 -34.42747  172.6778 1.836642e-02
    #7    B23   57357 -34.42747  172.6778 1.836642e-02
    #8    B23   98418 -34.43119  172.7014 1.369100e-03
    #9    B23   98418 -34.43225  172.7023 1.456022e-05
    #10   B23   98418 -34.43224  172.7023 1.456022e-05
    #11   B23   98418 -34.43224  172.7023 1.456022e-05
    #12   B24   57357 -34.43647  172.7141 3.862696e-03
    #13   B24   57357 -34.43647  172.7141 3.862696e-03
    #14   B24   57357 -34.43647  172.7141 3.862696e-03
    #15   B24   98418 -34.43904  172.7172 3.245705e-04
    #16   B24   98418 -34.43904  172.7172 3.245705e-04
    #17   B24   98418 -34.43904  172.7172 3.245705e-04
    #18   B24   98418 -34.43925  172.7168 1.393162e-04
    #19   B24   98418 -34.43915  172.7169 1.393162e-04
    #20   B24   98418 -34.43915  172.7169 1.393162e-04
    #21   B24   98418 -34.43915  172.7169 1.393162e-04
    #22   B24   98418 -34.43915  172.7169 1.393162e-04
    
    mydf <- structure(list(group = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("B23", 
    "B24"), class = "factor"), user_id = c(85553L, 85553L, 85553L, 
    85553L, 57357L, 57357L, 57357L, 98418L, 98418L, 98418L, 98418L, 
    57357L, 57357L, 57357L, 98418L, 98418L, 98418L, 98418L, 98418L, 
    98418L, 98418L, 98418L), latitude = c(-34.440114, -34.43929, 
    -34.43929, -34.438507, -34.427467, -34.427467, -34.427467, -34.431187, 
    -34.432254, -34.43224, -34.43224, -34.436472, -34.436472, -34.436472, 
    -34.439038, -34.439038, -34.439038, -34.439246, -34.439149, -34.439149, 
    -34.439149, -34.439149), longitude = c(172.695443, 172.693906, 
    172.693906, 172.692441, 172.677763, 172.677763, 172.677763, 172.701413, 
    172.702284, 172.702288, 172.702288, 172.71411, 172.71411, 172.71411, 
    172.717203, 172.717203, 172.717203, 172.716798, 172.716898, 172.716898, 
    172.716898, 172.716898)), .Names = c("group", "user_id", "latitude", 
    "longitude"), row.names = c(NA, -22L), class = "data.frame")
    
    library(sp)
    library(rgeos)
    
    nearest.neighbor <- function(lon,lat) {
      df <- data.frame(lon,lat)
      coordinates(df) <- ~lon+lat
      d <- gDistance(df, byid=TRUE)
      # remove the self distance from being considered and use which.min to find the nearest neighbor
      d[cbind(1:nrow(d),1:nrow(d))] <- NA
      min.d <- rbind(apply(d,1,function(x) {ind <- which.min(x); list(ind=ind,distance=x[ind])}))
    }
    
    order.by.ind <- function (x,ind) x[ind]
    
    library(dplyr)
    
    result <- ncbaby %>% group_by(areaname) %>%
                         mutate(min.d=nearest.neighbor(longitude, latitude)) %>%
                         mutate_each(vars=c(id, printid, latitude, longitude),
                                     funs(order.by.ind, "order.by.ind", order.by.ind(.,ind=unlist(min.d)[c(TRUE,FALSE)]))) %>%
                         mutate(distance=unlist(min.d)[c(FALSE,TRUE)]) %>%
                         mutate(.Areaname=areaname) %>%
                         select(-min.d)
    
    newvars <- c('n.ID', 'n.printid', 'n.latitude', 'n.longitude', 'distance', '.Areaname')
    colnames(result) <- c(colnames(ncbaby), newvars)
    
    print(result)
    ##Source: local data frame [7 x 11]
    ##Groups: areaname [3]
    ##
    ##        id   printid   areaname latitude longitude     n.ID n.printid n.latitude n.longitude    distance  .Areaname
    ##     <int>     <int>     <fctr>    <dbl>     <dbl>    <int>     <int>      <dbl>       <dbl>       <dbl>     <fctr>
    ##1  7912048 233502729        073 36.06241 -80.44229  7912049 233502730   36.06251   -80.44329 0.001004988        073
    ##2   735253 171241999 Area 12-06 35.54452 -78.75388 13444458 536073775   35.53987   -78.74922 0.006583168 Area 12-06
    ##3  4325564  85564887 Area 12-04 35.49328 -78.73756 11997754 356053648   35.49328   -78.73756 0.000000000 Area 12-04
    ##4  4222241  85461255 Area 12-06 35.53621 -78.75553 13444458 536073775   35.53987   -78.74922 0.007294635 Area 12-06
    ##5 11997754 356053648 Area 12-04 35.49328 -78.73756  4325564  85564887   35.49328   -78.73756 0.000000000 Area 12-04
    ##6 13444458 536073775 Area 12-06 35.53987 -78.74922   735253 171241999   35.54452   -78.75388 0.006583168 Area 12-06
    ##7  7912049 233502730        073 36.06251 -80.44329  7912048 233502729   36.06241   -80.44229 0.001004988        073