使用 apply() 和具有多个参数的用户定义函数计算数据框中样本之间的距离
calculate distance between samples in dataframe with apply() and user-defined function with multiple args
我有一个非常大的样本数据集及其地理位置(>500 个样本)。我想使用两种不同的方法计算所有样本之间的距离(即制作距离矩阵):隔离物之间的大圆距离,以及使用 waypoints 人类迁移的大圆距离。前者使用 geosphere 包很简单,我已经使用示例数据集 (n = 10) 后列出的代码实现了它。
test <- structure(list(sample_lon = c(85.1, 101.65, 101.52, 100.5, 77.67,
78.01, 41.8376999, 136.3070068, 43.0671997, 33.6925011), sample_lat = c(20.95,
3.11, 3.07, 13.76, 27.49, 27.18, 56.2234001, 49.0937004, 52.3828011,
-12.3848), Cairo = c(5482676.53004203, 7979572.75185404, 7969372.29645241,
7300548.40307534, 4535773.29985337, 4577259.89703268, 3035531.48539288,
8559356.13799981, 2675638.0088102, 4698651.89376045), Istanbul = c(5775286.47479145,
8414621.15676231, 8406733.79230612, 7555850.43260897, 4744788.34257317,
4791494.45027787, 1968286.36800993, 7814352.55494176, 1704767.09047958,
5939243.14729151), PhnomPenh = c(2300013.05256412, 910323.277871997,
918740.411068992, 487913.521378381, 3302731.94513236, 3256808.88281153,
7291948.53468698, 5171445.2592504, 7089458.06789339, 8189260.33147658
), AddisAbada = c(5137690.28464086, 6987142.79928228, 6973508.88041575,
6744246.81620126, 4567281.84480851, 4588137.16563698, 5241878.016939,
9802623.85641921, 4823403.30909928, 2433156.16935115), UN = c("Southern-Asia",
"South-Eastern-Asia", "South-Eastern-Asia", "South-Eastern-Asia",
"Southern-Asia", "Southern-Asia", "Eastern-Europe", "Eastern-Europe",
"Eastern-Europe", "Eastern-Africa"), continent = c("Asia", "Asia",
"Asia", "Asia", "Asia", "Asia", "Europe", "Europe", "Europe",
"Africa")), .Names = c("sample_lon", "sample_lat", "Cairo", "Istanbul",
"PhnomPenh", "AddisAbada", "UN", "continent"), row.names = c(NA,
10L), class = "data.frame")
require(geosphere)
test.dvse <- apply(test[c("sample_lon", "sample_lat")], 1, FUN=function(X) distVincentyEllipsoid(X, test[c("sample_lon", "sample_lat")]))
这成功地 returns 所有分离物之间的距离矩阵。
对于路点分析,我创建了一个用户定义的函数,该函数查看样本来自的大陆,然后通过一系列规则计算分离物之间的距离。
dCI <- distVincentyEllipsoid(c(31,30), c(28,41)) #Cairo to Istanbul
dCP <- distVincentyEllipsoid(c(31,30), c(104,11)) #Cairo to Phnom Penh
dIP <- distVincentyEllipsoid(c(28,41), c(104,11)) #Istanbul Phnom Penh
calcWayDist <- function(lon1, lat1, con1, lon2, lat2, con2) {
if (con1 == con2) {
dd = distVincentyEllipsoid(c(lon1,lat1), c(lon2,lat2))
}
else{
if (setequal(c("Africa", "Europe"), c(con1, con2)) == TRUE) {
if (which("Africa" == c(con1, con2)) == 1) {
afr = distVincentyEllipsoid(c(lon1,lat1), c(31,30)) #dist from isolate to Cairo
eur = distVincentyEllipsoid(c(lon2,lat2), c(28,41)) #dist from isolate to Istanbul
dd = afr + dCI + eur
}
else {
afr = distVincentyEllipsoid(c(lon2,lat2), c(31,30)) #dist from isolate to Cairo
eur = distVincentyEllipsoid(c(lon1,lat1), c(28,41)) #dist from isolate to Istanbul
dd = afr + dCI + eur
}
}
else if (setequal(c("Africa", "Asia"), c(con1, con2)) == TRUE) {
s1 = distVincentyEllipsoid(c(lon1,lat1), c(31,30)) #dist from isolate to Cairo
s2 = distVincentyEllipsoid(c(lon2,lat2), c(31,30)) #dist from isolate to Cairo
dd = s1 + s2
}
else if (setequal(c("Africa", "Melanesia"), c(con1, con2)) == TRUE) {
if (which("Africa" == c(con1, con2)) == 1) {
afr = distVincentyEllipsoid(c(lon1,lat1), c(31,30)) #dist from isolate to Cairo
mel = distVincentyEllipsoid(c(lon2,lat2), c(104,11)) #dist from isolate to Phnom Penh
dd = afr + dCP + mel
}
else {
afr = distVincentyEllipsoid(c(lon2,lat2), c(31,30)) #dist from isolate to Cairo
mel = distVincentyEllipsoid(c(lon1,lat1), c(104,11)) #dist from isolate to Phnom Penh
dd = afr + dCP + mel
}
}
else if (setequal(c("Europe", "Asia"), c(con1, con2)) == TRUE) {
s1 = distVincentyEllipsoid(c(lon1,lat1), c(28,41)) #dist from isolate to Cairo
s2 = distVincentyEllipsoid(c(lon2,lat2), c(28,41)) #dist from isolate to Cairo
dd = s1 + s2
}
else if (setequal(c("Europe", "Melanesia"), c(con1, con2)) == TRUE) {
if (which("Europe" == c(con1, con2)) == 1) {
eur = distVincentyEllipsoid(c(lon1,lat1), c(28,41)) #dist from isolate to Istanbul
mel = distVincentyEllipsoid(c(lon2,lat2), c(104,11)) #dist from isolate to Phnom Penh
dd = eur + dIP + mel
}
else {
eur = distVincentyEllipsoid(c(lon2,lat2), c(28,41)) #dist from isolate to Istanbul
mel = distVincentyEllipsoid(c(lon1,lat1), c(104,11)) #dist from isolate to Phnom Penh
dd = eur + dIP + mel
}
}
else if (setequal(c("Asia", "Melanesia"), c(con1, con2)) == TRUE) {
s1 = distVincentyEllipsoid(c(lon1,lat1), c(104,11)) #dist from isolate to Phnom Penh
s2 = distVincentyEllipsoid(c(lon2,lat2), c(104,11)) #dist from isolate to Phnom Penh
dd = s1 + s2
}
}
return(dd)
}
这在手动输入值时可以正常工作。例如,
calcWayDist(3.6,15.6,"Africa",51.9,31.9,"Asia")
5225325
但是,当我尝试使用 apply 函数在所有可能的隔离对之间执行计算时,出现错误。
test.waypoint <- apply(test, 1, FUN=function(X) calcWayDist(X["sample_lon"], X["sample_lat"], X["continent"], test["sample_lon"], test["sample_lat"], test["continent"]))
Error in .pointsToMatrix(p1) : longitude > 360
In addition: Warning message:
In if (con1 == con2) { :
the condition has length > 1 and only the first element will be used
Called from: .pointsToMatrix(p1)
接下来我尝试 'vectorizing' 我的用户定义函数的输入参数:
calcWayDistbyVec <- function(s1, s2) {
if (s1[3] == s2[3]) {
dd = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(as.numeric(s2[1]),as.numeric(s2[2])))
}
else{
if (setequal(c("Africa", "Europe"), c(s1[3], s2[3])) == TRUE) {
if (which("Africa" == c(s1[3], s2[3])) == 1) {
afr = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(31,30)) #dist from isolate to Cairo
eur = distVincentyEllipsoid(c(as.numeric(s2[1]),as.numeric(s2[2])), c(28,41)) #dist from isolate to Istanbul
dd = afr + dCI + eur
}
else {
afr = distVincentyEllipsoid(c(as.numeric(s2[1]),as.numeric(s2[2])), c(31,30)) #dist from isolate to Cairo
eur = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(28,41)) #dist from isolate to Istanbul
dd = afr + dCI + eur
}
}
else if (setequal(c("Africa", "Asia"), c(s1[3], s2[3])) == TRUE) {
d1 = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(31,30)) #dist from isolate to Cairo
d2 = distVincentyEllipsoid(c(as.numeric(s2[1]),as.numeric(s2[2])), c(31,30)) #dist from isolate to Cairo
dd = d1 + d2
}
else if (setequal(c("Africa", "Melanesia"), c(s1[3], s2[3])) == TRUE) {
if (which("Africa" == c(s1[3], s2[3])) == 1) {
afr = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(31,30)) #dist from isolate to Cairo
mel = distVincentyEllipsoid(c(as.numeric(s2[1]),as.numeric(s2[2])), c(104,11)) #dist from isolate to Phnom Penh
dd = afr + dCP + mel
}
else {
afr = distVincentyEllipsoid(c(as.numeric(s2[1]),as.numeric(s2[2])), c(31,30)) #dist from isolate to Cairo
mel = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(104,11)) #dist from isolate to Phnom Penh
dd = afr + dCP + mel
}
}
else if (setequal(c("Europe", "Asia"), c(s1[3], s2[3])) == TRUE) {
d1 = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(28,41)) #dist from isolate to Cairo
d2 = distVincentyEllipsoid(c(as.numeric(s2[1]),as.numeric(s2[2])), c(28,41)) #dist from isolate to Cairo
dd = d1 + d2
}
else if (setequal(c("Europe", "Melanesia"), c(s1[3], s2[3])) == TRUE) {
if (which("Europe" == c(s1[3], s2[3])) == 1) {
eur = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(28,41)) #dist from isolate to Istanbul
mel = distVincentyEllipsoid(c(as.numeric(s2[1]),as.numeric(s2[2])), c(104,11)) #dist from isolate to Phnom Penh
dd = eur + dIP + mel
}
else {
eur = distVincentyEllipsoid(c(as.numeric(s2[1]),as.numeric(s2[2])), c(28,41)) #dist from isolate to Istanbul
mel = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(104,11)) #dist from isolate to Phnom Penh
dd = eur + dIP + mel
}
}
else if (setequal(c("Asia", "Melanesia"), c(s1[3], s2[3])) == TRUE) {
d1 = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(104,11)) #dist from isolate to Phnom Penh
d2 = distVincentyEllipsoid(c(as.numeric(s2[1]),as.numeric(s2[2])), c(104,11)) #dist from isolate to Phnom Penh
dd = d1 + d2
}
}
return(dd)
}
这适用于单个计算:
calcWayDistbyVec(c(3.6,15.6,"Africa"), c(41.8,56.2,"Europe"))
[1] 6435307
但是,当我尝试使用 apply 时再次出现错误。
test.waypoint <- apply(test[c("sample_lon", "sample_lat", "continent")], 1, FUN=function(X) calcWayDistbyVec(X, test[c("sample_lon", "sample_lat", "continent")]))
Error in inherits(p, "SpatialPoints") :
(list) object cannot be coerced to type 'double'
In addition: Warning message:
In if (s1[3] == s2[3]) { :
the condition has length > 1 and only the first element will be used
Called from: inherits(p, "SpatialPoints")
如果我只做一个点,它确实有效。
test.waypoint.ind <- apply(test[c("sample_lon", "sample_lat", "continent")], 1, FUN=function(X) calcWayDistbyVec(X, c(3.6,15.6,"Africa")))
8702972 11199869 11189668 10520844 7756069 7797556 6438793 12284859 6175273 4535197
如果有人能找出什么不起作用,我将不胜感激!我查看了 Apply User Defined Functions, 的帖子,这些帖子帮助我完成了第一次距离矩阵计算,但在这里似乎不太适用。
我将这个问题传递给了我大学的 R 研究小组,没有 Stack Overflow 帐户的人提供了解决方案。它不使用 apply()。
calcWayDistMODIFIED <- function(lon1, lat1, con1, lon2, lat2, con2) {
if (con1 == con2) {
dd = distVincentyEllipsoid(c(lon1,lat1), c(lon2,lat2))
} else if (con1 == "Africa" & con2 == "Europe") {
afr = distVincentyEllipsoid(c(lon1,lat1), c(31,30)) #dist from isolate to Cairo
eur = distVincentyEllipsoid(c(lon2,lat2), c(28,41)) #dist from isolate to Istanbul
dd = afr + dCI + eur
} else if (con1 == "Europe" & con2 == "Africa") {
afr = distVincentyEllipsoid(c(lon2,lat2), c(31,30)) #dist from isolate to Cairo
eur = distVincentyEllipsoid(c(lon1,lat1), c(28,41)) #dist from isolate to Istanbul
dd = afr + dCI + eur
} else if (setequal(c("Africa", "Asia"), c(con1, con2))) {
s1 = distVincentyEllipsoid(c(lon1,lat1), c(31,30)) #dist from isolate to Cairo
s2 = distVincentyEllipsoid(c(lon2,lat2), c(31,30)) #dist from isolate to Cairo
dd = s1 + s2
} else if (con1 == "Africa" & con2 == "Melanesia") {
afr = distVincentyEllipsoid(c(lon1,lat1), c(31,30)) #dist from isolate to Cairo
mel = distVincentyEllipsoid(c(lon2,lat2), c(104,11)) #dist from isolate to Phnom Penh
dd = afr + dCP + mel
} else if (con1 == "Melanesia" & con2 == "Africa") {
afr = distVincentyEllipsoid(c(lon2,lat2), c(31,30)) #dist from isolate to Cairo
mel = distVincentyEllipsoid(c(lon1,lat1), c(104,11)) #dist from isolate to Phnom Penh
dd = afr + dCP + mel
} else if (setequal(c("Europe", "Asia"), c(con1, con2))) {
s1 = distVincentyEllipsoid(c(lon1,lat1), c(28,41)) #dist from isolate to Cairo
s2 = distVincentyEllipsoid(c(lon2,lat2), c(28,41)) #dist from isolate to Cairo
dd = s1 + s2
} else if (con1 == "Europe" & con2 == "Melanesia") {
eur = distVincentyEllipsoid(c(lon1,lat1), c(28,41)) #dist from isolate to Istanbul
mel = distVincentyEllipsoid(c(lon2,lat2), c(104,11)) #dist from isolate to Phnom Penh
dd = eur + dIP + mel
} else if (con1 == "Melanesia" & con2 == "Europe") {
eur = distVincentyEllipsoid(c(lon2,lat2), c(28,41)) #dist from isolate to Istanbul
mel = distVincentyEllipsoid(c(lon1,lat1), c(104,11)) #dist from isolate to Phnom Penh
dd = eur + dIP + mel
} else if (setequal(c("Asia", "Melanesia"), c(con1, con2))) {
s1 = distVincentyEllipsoid(c(lon1,lat1), c(104,11)) #dist from isolate to Phnom Penh
s2 = distVincentyEllipsoid(c(lon2,lat2), c(104,11)) #dist from isolate to Phnom Penh
dd = s1 + s2
}
return(dd)
}
distance_function = function(d) {
mat = matrix(0, ncol = nrow(d), nrow = nrow(d))
for(i in 1:nrow(mat)) {
for(j in 1:nrow(mat)) {
mat[i,j] = calcWayDistMODIFIED(lon1 = d[i,'sample_lon'], lat1 = d[i,'sample_lat'], con1 = d[i,'continent'], lon2 = d[j,'sample_lon'], lat2 = d[j,'sample_lat'], con2 = d[j,'continent'])
}
}
return(mat)
}
我有一个非常大的样本数据集及其地理位置(>500 个样本)。我想使用两种不同的方法计算所有样本之间的距离(即制作距离矩阵):隔离物之间的大圆距离,以及使用 waypoints 人类迁移的大圆距离。前者使用 geosphere 包很简单,我已经使用示例数据集 (n = 10) 后列出的代码实现了它。
test <- structure(list(sample_lon = c(85.1, 101.65, 101.52, 100.5, 77.67,
78.01, 41.8376999, 136.3070068, 43.0671997, 33.6925011), sample_lat = c(20.95,
3.11, 3.07, 13.76, 27.49, 27.18, 56.2234001, 49.0937004, 52.3828011,
-12.3848), Cairo = c(5482676.53004203, 7979572.75185404, 7969372.29645241,
7300548.40307534, 4535773.29985337, 4577259.89703268, 3035531.48539288,
8559356.13799981, 2675638.0088102, 4698651.89376045), Istanbul = c(5775286.47479145,
8414621.15676231, 8406733.79230612, 7555850.43260897, 4744788.34257317,
4791494.45027787, 1968286.36800993, 7814352.55494176, 1704767.09047958,
5939243.14729151), PhnomPenh = c(2300013.05256412, 910323.277871997,
918740.411068992, 487913.521378381, 3302731.94513236, 3256808.88281153,
7291948.53468698, 5171445.2592504, 7089458.06789339, 8189260.33147658
), AddisAbada = c(5137690.28464086, 6987142.79928228, 6973508.88041575,
6744246.81620126, 4567281.84480851, 4588137.16563698, 5241878.016939,
9802623.85641921, 4823403.30909928, 2433156.16935115), UN = c("Southern-Asia",
"South-Eastern-Asia", "South-Eastern-Asia", "South-Eastern-Asia",
"Southern-Asia", "Southern-Asia", "Eastern-Europe", "Eastern-Europe",
"Eastern-Europe", "Eastern-Africa"), continent = c("Asia", "Asia",
"Asia", "Asia", "Asia", "Asia", "Europe", "Europe", "Europe",
"Africa")), .Names = c("sample_lon", "sample_lat", "Cairo", "Istanbul",
"PhnomPenh", "AddisAbada", "UN", "continent"), row.names = c(NA,
10L), class = "data.frame")
require(geosphere)
test.dvse <- apply(test[c("sample_lon", "sample_lat")], 1, FUN=function(X) distVincentyEllipsoid(X, test[c("sample_lon", "sample_lat")]))
这成功地 returns 所有分离物之间的距离矩阵。
对于路点分析,我创建了一个用户定义的函数,该函数查看样本来自的大陆,然后通过一系列规则计算分离物之间的距离。
dCI <- distVincentyEllipsoid(c(31,30), c(28,41)) #Cairo to Istanbul
dCP <- distVincentyEllipsoid(c(31,30), c(104,11)) #Cairo to Phnom Penh
dIP <- distVincentyEllipsoid(c(28,41), c(104,11)) #Istanbul Phnom Penh
calcWayDist <- function(lon1, lat1, con1, lon2, lat2, con2) {
if (con1 == con2) {
dd = distVincentyEllipsoid(c(lon1,lat1), c(lon2,lat2))
}
else{
if (setequal(c("Africa", "Europe"), c(con1, con2)) == TRUE) {
if (which("Africa" == c(con1, con2)) == 1) {
afr = distVincentyEllipsoid(c(lon1,lat1), c(31,30)) #dist from isolate to Cairo
eur = distVincentyEllipsoid(c(lon2,lat2), c(28,41)) #dist from isolate to Istanbul
dd = afr + dCI + eur
}
else {
afr = distVincentyEllipsoid(c(lon2,lat2), c(31,30)) #dist from isolate to Cairo
eur = distVincentyEllipsoid(c(lon1,lat1), c(28,41)) #dist from isolate to Istanbul
dd = afr + dCI + eur
}
}
else if (setequal(c("Africa", "Asia"), c(con1, con2)) == TRUE) {
s1 = distVincentyEllipsoid(c(lon1,lat1), c(31,30)) #dist from isolate to Cairo
s2 = distVincentyEllipsoid(c(lon2,lat2), c(31,30)) #dist from isolate to Cairo
dd = s1 + s2
}
else if (setequal(c("Africa", "Melanesia"), c(con1, con2)) == TRUE) {
if (which("Africa" == c(con1, con2)) == 1) {
afr = distVincentyEllipsoid(c(lon1,lat1), c(31,30)) #dist from isolate to Cairo
mel = distVincentyEllipsoid(c(lon2,lat2), c(104,11)) #dist from isolate to Phnom Penh
dd = afr + dCP + mel
}
else {
afr = distVincentyEllipsoid(c(lon2,lat2), c(31,30)) #dist from isolate to Cairo
mel = distVincentyEllipsoid(c(lon1,lat1), c(104,11)) #dist from isolate to Phnom Penh
dd = afr + dCP + mel
}
}
else if (setequal(c("Europe", "Asia"), c(con1, con2)) == TRUE) {
s1 = distVincentyEllipsoid(c(lon1,lat1), c(28,41)) #dist from isolate to Cairo
s2 = distVincentyEllipsoid(c(lon2,lat2), c(28,41)) #dist from isolate to Cairo
dd = s1 + s2
}
else if (setequal(c("Europe", "Melanesia"), c(con1, con2)) == TRUE) {
if (which("Europe" == c(con1, con2)) == 1) {
eur = distVincentyEllipsoid(c(lon1,lat1), c(28,41)) #dist from isolate to Istanbul
mel = distVincentyEllipsoid(c(lon2,lat2), c(104,11)) #dist from isolate to Phnom Penh
dd = eur + dIP + mel
}
else {
eur = distVincentyEllipsoid(c(lon2,lat2), c(28,41)) #dist from isolate to Istanbul
mel = distVincentyEllipsoid(c(lon1,lat1), c(104,11)) #dist from isolate to Phnom Penh
dd = eur + dIP + mel
}
}
else if (setequal(c("Asia", "Melanesia"), c(con1, con2)) == TRUE) {
s1 = distVincentyEllipsoid(c(lon1,lat1), c(104,11)) #dist from isolate to Phnom Penh
s2 = distVincentyEllipsoid(c(lon2,lat2), c(104,11)) #dist from isolate to Phnom Penh
dd = s1 + s2
}
}
return(dd)
}
这在手动输入值时可以正常工作。例如,
calcWayDist(3.6,15.6,"Africa",51.9,31.9,"Asia")
5225325
但是,当我尝试使用 apply 函数在所有可能的隔离对之间执行计算时,出现错误。
test.waypoint <- apply(test, 1, FUN=function(X) calcWayDist(X["sample_lon"], X["sample_lat"], X["continent"], test["sample_lon"], test["sample_lat"], test["continent"]))
Error in .pointsToMatrix(p1) : longitude > 360 In addition: Warning message: In if (con1 == con2) { : the condition has length > 1 and only the first element will be used Called from: .pointsToMatrix(p1)
接下来我尝试 'vectorizing' 我的用户定义函数的输入参数:
calcWayDistbyVec <- function(s1, s2) {
if (s1[3] == s2[3]) {
dd = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(as.numeric(s2[1]),as.numeric(s2[2])))
}
else{
if (setequal(c("Africa", "Europe"), c(s1[3], s2[3])) == TRUE) {
if (which("Africa" == c(s1[3], s2[3])) == 1) {
afr = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(31,30)) #dist from isolate to Cairo
eur = distVincentyEllipsoid(c(as.numeric(s2[1]),as.numeric(s2[2])), c(28,41)) #dist from isolate to Istanbul
dd = afr + dCI + eur
}
else {
afr = distVincentyEllipsoid(c(as.numeric(s2[1]),as.numeric(s2[2])), c(31,30)) #dist from isolate to Cairo
eur = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(28,41)) #dist from isolate to Istanbul
dd = afr + dCI + eur
}
}
else if (setequal(c("Africa", "Asia"), c(s1[3], s2[3])) == TRUE) {
d1 = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(31,30)) #dist from isolate to Cairo
d2 = distVincentyEllipsoid(c(as.numeric(s2[1]),as.numeric(s2[2])), c(31,30)) #dist from isolate to Cairo
dd = d1 + d2
}
else if (setequal(c("Africa", "Melanesia"), c(s1[3], s2[3])) == TRUE) {
if (which("Africa" == c(s1[3], s2[3])) == 1) {
afr = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(31,30)) #dist from isolate to Cairo
mel = distVincentyEllipsoid(c(as.numeric(s2[1]),as.numeric(s2[2])), c(104,11)) #dist from isolate to Phnom Penh
dd = afr + dCP + mel
}
else {
afr = distVincentyEllipsoid(c(as.numeric(s2[1]),as.numeric(s2[2])), c(31,30)) #dist from isolate to Cairo
mel = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(104,11)) #dist from isolate to Phnom Penh
dd = afr + dCP + mel
}
}
else if (setequal(c("Europe", "Asia"), c(s1[3], s2[3])) == TRUE) {
d1 = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(28,41)) #dist from isolate to Cairo
d2 = distVincentyEllipsoid(c(as.numeric(s2[1]),as.numeric(s2[2])), c(28,41)) #dist from isolate to Cairo
dd = d1 + d2
}
else if (setequal(c("Europe", "Melanesia"), c(s1[3], s2[3])) == TRUE) {
if (which("Europe" == c(s1[3], s2[3])) == 1) {
eur = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(28,41)) #dist from isolate to Istanbul
mel = distVincentyEllipsoid(c(as.numeric(s2[1]),as.numeric(s2[2])), c(104,11)) #dist from isolate to Phnom Penh
dd = eur + dIP + mel
}
else {
eur = distVincentyEllipsoid(c(as.numeric(s2[1]),as.numeric(s2[2])), c(28,41)) #dist from isolate to Istanbul
mel = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(104,11)) #dist from isolate to Phnom Penh
dd = eur + dIP + mel
}
}
else if (setequal(c("Asia", "Melanesia"), c(s1[3], s2[3])) == TRUE) {
d1 = distVincentyEllipsoid(c(as.numeric(s1[1]),as.numeric(s1[2])), c(104,11)) #dist from isolate to Phnom Penh
d2 = distVincentyEllipsoid(c(as.numeric(s2[1]),as.numeric(s2[2])), c(104,11)) #dist from isolate to Phnom Penh
dd = d1 + d2
}
}
return(dd)
}
这适用于单个计算:
calcWayDistbyVec(c(3.6,15.6,"Africa"), c(41.8,56.2,"Europe"))
[1] 6435307
但是,当我尝试使用 apply 时再次出现错误。
test.waypoint <- apply(test[c("sample_lon", "sample_lat", "continent")], 1, FUN=function(X) calcWayDistbyVec(X, test[c("sample_lon", "sample_lat", "continent")]))
Error in inherits(p, "SpatialPoints") : (list) object cannot be coerced to type 'double' In addition: Warning message: In if (s1[3] == s2[3]) { : the condition has length > 1 and only the first element will be used Called from: inherits(p, "SpatialPoints")
如果我只做一个点,它确实有效。
test.waypoint.ind <- apply(test[c("sample_lon", "sample_lat", "continent")], 1, FUN=function(X) calcWayDistbyVec(X, c(3.6,15.6,"Africa")))
8702972 11199869 11189668 10520844 7756069 7797556 6438793 12284859 6175273 4535197
如果有人能找出什么不起作用,我将不胜感激!我查看了 Apply User Defined Functions,
我将这个问题传递给了我大学的 R 研究小组,没有 Stack Overflow 帐户的人提供了解决方案。它不使用 apply()。
calcWayDistMODIFIED <- function(lon1, lat1, con1, lon2, lat2, con2) {
if (con1 == con2) {
dd = distVincentyEllipsoid(c(lon1,lat1), c(lon2,lat2))
} else if (con1 == "Africa" & con2 == "Europe") {
afr = distVincentyEllipsoid(c(lon1,lat1), c(31,30)) #dist from isolate to Cairo
eur = distVincentyEllipsoid(c(lon2,lat2), c(28,41)) #dist from isolate to Istanbul
dd = afr + dCI + eur
} else if (con1 == "Europe" & con2 == "Africa") {
afr = distVincentyEllipsoid(c(lon2,lat2), c(31,30)) #dist from isolate to Cairo
eur = distVincentyEllipsoid(c(lon1,lat1), c(28,41)) #dist from isolate to Istanbul
dd = afr + dCI + eur
} else if (setequal(c("Africa", "Asia"), c(con1, con2))) {
s1 = distVincentyEllipsoid(c(lon1,lat1), c(31,30)) #dist from isolate to Cairo
s2 = distVincentyEllipsoid(c(lon2,lat2), c(31,30)) #dist from isolate to Cairo
dd = s1 + s2
} else if (con1 == "Africa" & con2 == "Melanesia") {
afr = distVincentyEllipsoid(c(lon1,lat1), c(31,30)) #dist from isolate to Cairo
mel = distVincentyEllipsoid(c(lon2,lat2), c(104,11)) #dist from isolate to Phnom Penh
dd = afr + dCP + mel
} else if (con1 == "Melanesia" & con2 == "Africa") {
afr = distVincentyEllipsoid(c(lon2,lat2), c(31,30)) #dist from isolate to Cairo
mel = distVincentyEllipsoid(c(lon1,lat1), c(104,11)) #dist from isolate to Phnom Penh
dd = afr + dCP + mel
} else if (setequal(c("Europe", "Asia"), c(con1, con2))) {
s1 = distVincentyEllipsoid(c(lon1,lat1), c(28,41)) #dist from isolate to Cairo
s2 = distVincentyEllipsoid(c(lon2,lat2), c(28,41)) #dist from isolate to Cairo
dd = s1 + s2
} else if (con1 == "Europe" & con2 == "Melanesia") {
eur = distVincentyEllipsoid(c(lon1,lat1), c(28,41)) #dist from isolate to Istanbul
mel = distVincentyEllipsoid(c(lon2,lat2), c(104,11)) #dist from isolate to Phnom Penh
dd = eur + dIP + mel
} else if (con1 == "Melanesia" & con2 == "Europe") {
eur = distVincentyEllipsoid(c(lon2,lat2), c(28,41)) #dist from isolate to Istanbul
mel = distVincentyEllipsoid(c(lon1,lat1), c(104,11)) #dist from isolate to Phnom Penh
dd = eur + dIP + mel
} else if (setequal(c("Asia", "Melanesia"), c(con1, con2))) {
s1 = distVincentyEllipsoid(c(lon1,lat1), c(104,11)) #dist from isolate to Phnom Penh
s2 = distVincentyEllipsoid(c(lon2,lat2), c(104,11)) #dist from isolate to Phnom Penh
dd = s1 + s2
}
return(dd)
}
distance_function = function(d) {
mat = matrix(0, ncol = nrow(d), nrow = nrow(d))
for(i in 1:nrow(mat)) {
for(j in 1:nrow(mat)) {
mat[i,j] = calcWayDistMODIFIED(lon1 = d[i,'sample_lon'], lat1 = d[i,'sample_lat'], con1 = d[i,'continent'], lon2 = d[j,'sample_lon'], lat2 = d[j,'sample_lat'], con2 = d[j,'continent'])
}
}
return(mat)
}