处理 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.dat1
到 list.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
我在 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.dat1
到 list.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