使用dplyr对sapply结果进行处理

3
在下面的示例中,我试图确定每个vals_int最接近哪个value,通过id。我可以使用类似下面的方法使用sapply()解决这个问题,但我想知道是否可以使用dplyr中的其他函数来完成sapply()部分。
我只是想知道是否可以使用dplyr包中的一些函数来复制sapply方法和输出。我曾经认为do()可能有效,但我很难确定如何做到这一点。
library(tidyverse)

df <- data_frame(
  id = rep(1:10, 10) %>% 
    sort,
  visit = rep(1:10, 10),
  value = rnorm(100)
)

vals_int <- c(1, 2, 3)

tmp <- sapply(vals_int,
              function(val_i) abs(df$value - val_i))
2个回答

4

是的,你可以使用dplyr中的rowwise()do()函数来对每一行执行相同的操作,例如:

df %>% rowwise %>% do(diffs = abs(.$value - vals_int))

这将在一个新的tibble中创建一个名为diffs的列,它是一个长度为3的向量列表。如果你强制将do()返回的输出转换为数据框,它将创建一个有三列的tibble,每一列代表被减数的值。
df %>% rowwise %>% do(as.data.frame(t(abs(.$value - vals_int))))

2

@qdread的回答可以满足你的需求,但是如果你很在意,tidyverse已经开始逐渐放弃使用do()函数。这里提供一种使用purrr包中的map函数的替代方法。

df %>%
  mutate(closest = map(value, function(x){
    abs(x - vals_int) %>%
      t() %>%
      as.tibble()
  })) %>%
  unnest()

这将为您提供以下内容:
# A tibble: 100 x 6
      id visit       value         V1       V2       V3
   <int> <int>       <dbl>      <dbl>    <dbl>    <dbl>
 1     1     1  0.91813183 0.08186817 1.081868 2.081868
 2     1     2 -1.68556173 2.68556173 3.685562 4.685562
 3     1     3 -0.05984289 1.05984289 2.059843 3.059843
 4     1     4  0.40128729 0.59871271 1.598713 2.598713
 5     1     5 -0.09995526 1.09995526 2.099955 3.099955
 6     1     6  0.81802663 0.18197337 1.181973 2.181973
 7     1     7 -1.49244225 2.49244225 3.492442 4.492442
 8     1     8 -0.74256185 1.74256185 2.742562 3.742562
 9     1     9 -0.43943907 1.43943907 2.439439 3.439439
10     1    10  0.54985857 0.45014143 1.450141 2.450141
# ... with 90 more rows

感谢您的评论,我也很欣赏这个解决方案。事实上,我一直在试图回想起之前见过的一个函数(map),但是我忘记它叫什么了。感谢@tbradley指出这一点。 - Steve Reno
1
是的,我强烈推荐使用purrr包。虽然map函数更像lapply,但map_dblmap_chr函数则像sapply一样返回向量而不是列表。purrr包的设计考虑到了一致性,因此在不同函数之间切换时更加方便,因为它们都按照相同的顺序接受相同的参数,并且在返回值方面具有较少的变异性(尤其是与sapply相比)。 - tbradley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接