处理 R 中的列表 - 合并两个数据框并计算大小不匹配的值

Dealing with Lists in R - combine two data frames and calculate values with mismatched sizes

我在 R 中有两个 data.frame,我需要根据两个数据帧中每个列的子集计算值。

这是地理定位数据,所以我一直在使用 geosphere 进行一些计算。这是两个数据框。 dat1 仅包含地球表面随机数据点的 lat/long 坐标列表。 dat2 是地球上的一组物体,具有 lat/long 位置和与之关联的 speed/size .

library(geosphere)
set.seed(1)
dat1 <- data.frame( long = runif( n = 10, min = -180, max = 180 ),
                lat = runif( n = 10, min = -90, max = 90 ) )

dat2 <- data.frame( long = runif( n = 10, min = -180, max = 180 ),
                lat = runif( n = 10, min = -90, max = 90 ),
                size = runif( n = 10, min = 0, max = 1500 ),
                speed = rnorm( n = 10, mean = 100, sd = 30 ) )

我需要计算 dat1 中每个点到 dat2 中所有对象的距离,同时保持 大小 速度 数据。我一直在通过创建所有 dat1 位置的列表来做到这一点:

list.dat1   <- split( dat1, 1:nrow( dat1 ) )

并使用双 for 循环(我知道 R 中的错​​误形式),但它工作正常。

for( i in 1:length( list.dat1 ) ){
  for( j in 1:nrow( dat2 ) ) {
two.points = matrix( c( dat2[ j, 'long'], dat2[j,'lat'], # create matrix 
           dat1[ i, 'long' ], dat1[ i,'lat' ] ), # column 1 and 2 is long lat 
           nrow = 2, ncol = 2, byrow = T )     # make a matrix of these two locations

    ## now add the data from the objects
    list.dat1[[i]][j,3] = dat2[ j, 'long' ]  # add impactor long
    list.dat1[[i]][j,4] = dat2[ j, 'lat' ]  # add impactor lat

    ## calculate distance
    list.dat1[[i]][j,5] = distGeo( two.points )[1] / 1000  # distance kilometers
    list.dat1[[i]][j,6] = dat2[ j, 'size' ]   # add size of object
    list.dat1[[i]][j,7] = dat2[ j, 'speed' ]  # add speed of object
  }
}

然后我只是重命名列

for( i in 1:length( list.dat1) ) {
   colnames( list.dat1[[i]]) = c( "point.long", "point.lat", 
                                      "object.long", "object.lat",
                                      "distance.to.object", "object.size", 
                                      "object.speed" )
}

这是非常低效的,因为 dat1 有 1000 行,而 dat2 有 100 到 100,000 行。

我想我可以制作 list.dat1 长度为 nrow(dat2) 的数据帧列表,但我不确定如何实现。

然后我可以使用 lapply?

cbind 数据简单地 list.dat1list.dat1 中的每个列表元素中

然后,最后,对每个列表的每一行进行distGeo()计算?

我仍在学习如何有效地使用 R 列表和 apply() 套件函数,因此非常感谢任何有助于提高效率的帮助!

您可以创建一个新的数据框,使用 tidyr::crossing 创建 dat1 和 dat2 中所有点的组合,然后在生成的数据框上调用 distGeo 函数。

library(dplyr)
library(tidyr)
dat1 %>% 

    # rename dat1 long,lat to distinguish between dat1,dat2
    rename(dat1_long = long, dat1_lat = lat) %>% 

    # create all combinations
    tidyr::crossing(dat2) %>%

    # compute the distance between points 
    mutate(dist = distGeo(p1 = cbind(dat1_long, dat1_lat), 
                          p2 = cbind(long, lat)))

这是一个 data.table 方法,可能对您的大型数据集有帮助:

library(data.table)

setDT(dat1)[, `:=`(d1_id=.I, id=1)]
setDT(dat2)[, `:=`(d2_id=.I, id=1)]
dat1[dat2,on=.(id),allow.cartesian=T] %>% 
.[, dist:=distGeo(cbind(long,lat), cbind(i.long,i.lat))] %>% 
.[,.(d1_id, long, lat, d2_id, size, speed, dist)]

输出:(前六行)

     d1_id       long         lat d2_id      size     speed     dist
  1:     1  -84.41688 -52.9245765     1 1231.4194  98.31614 11610004
  2:     2  -46.03540 -58.2197845     1 1231.4194  98.31614 12903703
  3:     3   26.22721  33.6641124     1 1231.4194  98.31614 13868897
  4:     4  146.95480 -20.8613307     1 1231.4194  98.31614  2208091
  5:     5 -107.39450  48.5714556     1 1231.4194  98.31614 10727196
  6:     6  143.42029  -0.4141364     1 1231.4194  98.31614  1487321