R语言 我怎样才能循环一个函数通过一个因子的每一个水平组合?

zi8p0yeb  于 2023-07-31  发布在  其他
关注(0)|答案(1)|浏览(85)

我有一个数据集,其中包含一组变量和描述它们在地理空间中分布的坐标:

set.seed(123)

#example dataset:

d <- data.frame(var=as.factor(rep(LETTERS[1:5],each=6)),x=runif(30),y=runif(30))

head(d)

  var         x          y
1   A 0.2875775 0.96302423
2   A 0.7883051 0.90229905
3   A 0.4089769 0.69070528
4   A 0.8830174 0.79546742
5   A 0.9404673 0.02461368
6   A 0.0455565 0.47779597

字符串
我想测量Bhattacharyya对每个变量组合的亲和力,如下所示:

library(dplyr)
library(adehabitatHR)

a <- d %>%
  filter(var %in% c("A","B")) %>%
  dplyr::select(x,y)
b <- d %>%
  filter(var %in% c("A","B")) %>%
  dplyr::select(var)

sp_df <- SpatialPointsDataFrame(a, b)

kerneloverlap(sp_df, method='BA')[1,2]

[1] 0.7217199


最终目标是将这些值存储在对称矩阵中,并将它们用作变量之间的各种距离度量。
不幸的是,kerneloverlap()函数只适用于SpatialPointsDataFrame对象,并且一次只能处理两个变量,所以我尝试将其烘焙到this post之后的循环中:

distmat <- as.data.frame(matrix(ncol=5,nrow=5))
colnames(distmat) <- levels(d$var)
rownames(distmat) <- levels(d$var)

for (i in seq_along(levels(d$var))) {
  if(i != length(levels(d$var))){
a <- d %>%
  filter(var %in% c(levels(d$var)[i], levels(d$var)[i+1])) %>%
  dplyr::select(x,y)
b <- d %>%
  filter(var %in% c(levels(d$var)[i], levels(d$var)[i+1])) %>%
  dplyr::select(var)

sp_df <- SpatialPointsDataFrame(a, b)

distmat [i,(i+1)] <- kerneloverlap(sp_df, method='BA')[1,2]
  }
}


但是,当我运行这个函数时,它返回Error in kernelUD(xy, same4all = TRUE, ...) : At least 5 relocations are required to fit an home range。这是因为要使kerneloverlap()函数工作,两个分布中至少需要有五个观测值;然而,示例数据集中的每个变量都有6个观测值,所以这应该不是问题。我发现如果var不是一个因子而是一个字符向量,这个错误就不会发生,但是当然,函数的其余部分不起作用,距离矩阵保持为空。我真的被卡住了,不知道从这里去哪里,所以任何建议都非常感谢。

编辑

我找到了一个用combn迭代的解决方案:

combos =as.data.frame(combn(unique(d$var),2))
distmat <- as.data.frame(matrix(ncol=5,nrow=5))

for (i in 1:ncol(combos)) {
    a <- d %>%
      filter(var %in% c(combos[1:2,i])) %>%
      dplyr::select(x,y)
    b <- d %>%
      filter(var %in% c(combos[1:2,i])) %>%
      dplyr::select(var)
    
    sp_df <- SpatialPointsDataFrame(a, b)
    
    kerneloverlap(sp_df, method='BA')[1,2] %>% print()
  
}


这正确地打印出了Bhattacharyya的亲和度的值,但是我仍然试图弄清楚如何将这些值保存到一个维度等于变量数量的对称矩阵中,以便它们对应于正确的对。有什么想法吗?先谢了。

syqv5f0l

syqv5f0l1#

经过大量的尝试和错误,我最终得到了这个:

功能:

for (i in 1:ncol(combos)) {
    a <- d %>%
      filter(var %in% c(combos[1:2,i])) %>%
      dplyr::select(x,y)
    b <- d %>%
      filter(var %in% c(combos[1:2,i])) %>%
      dplyr::select(var)
    
    sp_df <- SpatialPointsDataFrame(a, b)

    #append to combos a row with the values for the corresponding pairs:
    combos[3,i] <- round(kerneloverlap(sp_df, method='BA')[1,2],3) 
}

字符串

重塑组合数据框

diff <- as.data.frame(t(comb)) %>%
  pivot_wider(names_from = 2,values_from = 3,values_fill = NA) %>%
  tibble::column_to_rownames('1') %>%
  as.matrix()

**注意:**这最后一段是有问题的,因为列名和行名将分别缺少第一个和最后一个字母,所以矩阵是不对称的。我不知道如何解决这个问题,它需要我将其保存到csv文件,并手动添加缺少的列和行。由于我的原始数据不是很大,这不是太麻烦,但我想修复它无论如何。
使矩阵对称

bhatt <- read.csv("bhatt.csv") #cleaned up version of the matrix with only the upper triangle filled up.

bhatt[lower.tri(bhatt,diag=F)] <- t(bhatt)[lower.tri(bhatt,diag=F)]


这仍然需要一个函数来从1中减去矩阵中的值,使其成为一个真实的距离矩阵,但这超出了本文的范围。这个解决方案对我来说很有效,但我觉得它太黑客了,可以做得更好,而不必手动修复数据集。如果有人知道怎么做,请告诉我。

相关问题