for循环内部mutate并追加结果

时间:2019-03-26 10:11:21

标签: r for-loop mutate

我有一个简单的for-loop,它可以像矢量一样工作,我想在for-loop的一列上使用我的dataframe,该列由{{ 1}},例如:

dataframe

这是伪代码尝试在数据帧的列上执行此操作:

# here is my for-loop working as expected on a simple vector:

vect <- c(0.5, 0.7, 0.1) 
res <- vector(mode = "numeric", length = 3) 

for (i in 1:length(vect)) {
  res[i] <- sum(exp(-2 * (vect[i] - vect[-i])))
}

res
[1] 1.9411537 0.9715143 5.5456579

结果应该是什么样子(但是我上面的伪代码不起作用):

#Example data
my.df <- data.frame(let = rep(LETTERS[1:3], each = 3), 
    num1 = 1:3, vect = c(0.5, 0.7, 0.1), num3 = NA)

 my.df
   let num1 vect num3
1   A    1  0.5   NA
2   A    2  0.7   NA
3   A    3  0.1   NA
4   B    1  0.5   NA
5   B    2  0.7   NA
6   B    3  0.1   NA
7   C    1  0.5   NA
8   C    2  0.7   NA
9   C    3  0.1   NA

# My attempt:

require(tidyverse)

  my.df <- my.df %>%
      group_by(let) %>%
      mutate(for (i in 1:length(vect)) {
        num3[i] <- sum(exp(-4 * (vect[i] - vect[-i])))
  })

我觉得我没有通过尝试在 let num1 vect num3 1 A 1 0.5 1.9411537 2 A 2 0.7 0.9715143 3 A 3 0.1 5.5456579 4 B 1 0.5 1.9411537 5 B 2 0.7 0.9715143 6 B 3 0.1 5.5456579 7 C 1 0.5 1.9411537 8 C 2 0.7 0.9715143 9 C 3 0.1 5.5456579 中使用tidyverse来使用for-loop逻辑,因此非常感谢任何建议。

4 个答案:

答案 0 :(得分:2)

简单的解决方案是创建一个自定义函数并将其传递给mutate。一个可行的解决方案:

custom_func <- function(vec) {
  res <- vector(mode = "numeric", length = 3)
  for (i in 1:length(vect)) {
    res[i] <- sum(exp(-2 * (vect[i] - vect[-i])))
  }
  res
}

library(tidyverse)

my.df %>%
  group_by(let) %>%
  mutate(num3 = custom_func(vect))

#> # A tibble: 9 x 4
#> # Groups:   let [3]
#>   let    num1  vect  num3
#>   <fct> <int> <dbl> <dbl>
#> 1 A         1   0.5 1.94 
#> 2 A         2   0.7 0.972
#> 3 A         3   0.1 5.55 
#> 4 B         1   0.5 1.94 
#> 5 B         2   0.7 0.972
#> 6 B         3   0.1 5.55 
#> 7 C         1   0.5 1.94 
#> 8 C         2   0.7 0.972
#> 9 C         3   0.1 5.55 

我想知道自定义功能的更优雅版本是否可行-也许比我聪明的人可以告诉您purrr::map是否可以提供替代方案。

答案 1 :(得分:2)

我们可以使用map_dbl中的purrr并应用公式进行计算。

library(dplyr)
library(purrr)

my.df %>%
  group_by(let) %>%
  mutate(num3 = map_dbl(seq_along(vect), ~ sum(exp(-2 * (vect[.] - vect[-.])))))


#   let    num1  vect  num3
#  <fct> <int> <dbl> <dbl>
#1  A         1   0.5 1.94 
#2  A         2   0.7 0.972
#3  A         3   0.1 5.55 
#4  B         1   0.5 1.94 
#5  B         2   0.7 0.972
#6  B         3   0.1 5.55 
#7  C         1   0.5 1.94 
#8  C         2   0.7 0.972
#9  C         3   0.1 5.55 

答案 2 :(得分:1)

您可以将for循环转换为sapply呼叫,然后在mutate中使用它。 sapply接受一个函数并将其应用于每个列表元素。在这种情况下,我要遍历每个组(n())中的元素数量。

my.df %>% 
  group_by(let) %>% 
  mutate(num3 = sapply(1:n(), function(i) sum(exp(-2 * (vect[i] - vect[-i])))))

# A tibble: 9 x 4
# Groups:   let [3]
#   let    num1  vect  num3
#   <fct> <int> <dbl> <dbl>
# 1 A         1   0.5 1.94 
# 2 A         2   0.7 0.972
# 3 A         3   0.1 5.55 
# 4 B         1   0.5 1.94 
# 5 B         2   0.7 0.972
# 6 B         3   0.1 5.55 
# 7 C         1   0.5 1.94 
# 8 C         2   0.7 0.972
# 9 C         3   0.1 5.55 

这基本上等效于for调用中看起来非常错误的mutate循环。但是,在这种情况下,我更喜欢A. Stam提供的自定义功能。

my.df %>%
  group_by(let) %>%
  mutate(num3 = {
    res <- numeric(length = n())
    for (i in 1:n()) {
      res[i] <- sum(exp(-2 * (vect[i] - vect[-i])))
    }
    res
  })

您也可以将sapply替换为purrr的{​​{1}}。

答案 3 :(得分:1)

或使用mean_by_trial

data.table