提问者:小点点

使用dplyr将数据帧中的值(基于特定分组)乘以单独的矩阵


我需要将数据帧中的值(基于特定分组)乘以一个单独的矩阵,该矩阵对这些值施加某种权重。乘法是我编写的函数的一部分。我知道如何以最基本的方式做到这一点。但我无法理解如何在更现实的设置中做到这一点。我希望我的例子能清楚地说明这个问题。

我有以下示例数据集:

set.seed(45)
tibble(site = rep(c(LETTERS[1:3]), each = 6),
       name = rep(c(letters[10:15]), 3),
       size = runif(18)) %>%
  arrange(site, name) -> d_tibble

我还有一个矩阵,可以表示某种权重:

d_matrix <- matrix(0, 6, 6)
diag(d_matrix) <- 1
rownames(d_matrix) <- letters[10:15]
colnames(d_matrix) <- letters[10:15]

d_matrix
##   j k l m n o
## j 1 0 0 0 0 0
## k 0 1 0 0 0 0
## l 0 0 1 0 0 0
## m 0 0 0 1 0 0
## n 0 0 0 0 1 0
## o 0 0 0 0 0 1

我还有一个函数,应该将向量p乘以矩阵b

test_fct <- function(a, b) {
  p <- a / sum(a)
  sum(p * (p %*% b))
}

然后我想做类似这样的事情,即在中使用我的函数来总结()

#d_tibble %>%
#  group_by(site) %>%
#  summarise(y = test_fct(size, b))

但是我不知道如何将b,即矩阵,放入我的自定义函数中,以便它的列名在按site分组时与name变量匹配。

我尝试的一种方法是将矩阵合并到数据帧中-这样我就可以在一个数据帧中包含所有内容:

d_tibble %>%
  left_join(d_matrix %>%
              as_tibble() %>%
              mutate(name = colnames(d_matrix))) -> tibble_matrix_join

但我需要在给定site分组的情况下以某种方式访问name变量的唯一值,以便在我的函数test_fct()中为向量/矩阵乘法选择正确的列(j, k,l,m,n,o):

#tibble_matrix_join %>%
#  group_by(site) %>%
#  summarise(result = test_fct(size, b))

我试图检查一般设置是否有效,即仅适用于一个站点,并将所有名称包含在矩阵中,它确实:

d_tibble %>% 
    filter(site == "A") %>% 
    pull(size) -> my_x 

test_fct(my_x, d_matrix)
## [1] 0.1858158

my_p <- my_x/sum(my_x)
sum(my_p * (my_p %*% d_matrix))
## [1] 0.1858158

共1个答案

匿名用户

在这个例子中,d_matrix中的所有列都可以在tibble的'name'列中找到。如果不是这样,我们可以这样做

library(dplyr)
d_tibble %>%
   group_by(site) %>% 
   summarise(out = test_fct(size, d_matrix[intersect(row.names(d_matrix), 
         name), intersect(colnames(d_matrix), 
         name), drop = FALSE]), .groups = "drop")

-输出

# A tibble: 3 × 2
  site    out
  <chr> <dbl>
1 A     0.186
2 B     0.264
3 C     0.218

-测试较小的数据

d_tibble %>% 
  slice_sample(n = 12) %>%
  arrange(site, name) %>% 
  group_by(site) %>% 
   summarise(out = test_fct(size, d_matrix[intersect(row.names(d_matrix), 
         name), intersect(colnames(d_matrix), 
         name), drop = FALSE]), .groups = "drop")

-输出

# A tibble: 3 × 2
  site    out
  <chr> <dbl>
1 A     0.227
2 B     0.416
3 C     0.481