计算对数和平均值,将结果添加到 R

时间:2021-07-10 19:15:13

标签: r logging mean

在以下数据集中

  code test1 ref1 test2 ref2
1    A  19.0 19.5  31.8   33
2    B  17.6 19.5  29.1   33
3    C  19.6 19.5  31.4   33
4    D  20.0 19.5  33.5   33
5    E  17.8 19.5  30.5   33
6    F  18.6 19.5  31.7   33
7    G  19.0 19.5  31.2   33
8    H  18.2 19.5  29.6   33
9    I  18.3 19.5  30.3   33

我想计算“test”和“ref”列的日志之间的差异。

log(test1)- log(ref1) = a
log(test2)- log(ref2) = b

然后我想计算每行 a 和 b 的平均值,并将结果保存在数据集中的新列中。

我试过这个功能:

f <- function(x) {
  x[paste0(x, sep = "_log")] <<- log(x[x]) 
}

sapply(names(x)[-1], f)

但我只能计算每列的日志并将结果添加到新列中。

如果我继续这样,我的数据集会太长。 谁能帮我创建一个代码来执行所有计算并添加一列作为最终结果?

非常感谢

3 个答案:

答案 0 :(得分:2)

我们可以使用

library(dplyr)
df1 %>%
    mutate(a = log(test1)- log(ref1), b = log(test2)- log(ref2),
       Mean = rowMeans(cbind(a, b), na.rm = TRUE))

-输出

 code test1 ref1 test2 ref2            a           b        Mean
1    A  19.0 19.5  31.8   33 -0.025975486 -0.03704127 -0.03150838
2    B  17.6 19.5  29.1   33 -0.102515564 -0.12576939 -0.11414248
3    C  19.6 19.5  31.4   33  0.005115101 -0.04969967 -0.02229228
4    D  20.0 19.5  33.5   33  0.025317808  0.01503788  0.02017784
5    E  17.8 19.5  30.5   33 -0.091216008 -0.07878088 -0.08499844
6    F  18.6 19.5  31.7   33 -0.047252885 -0.04019088 -0.04372188
7    G  19.0 19.5  31.2   33 -0.025975486 -0.05608947 -0.04103248
8    H  18.2 19.5  29.6   33 -0.068992871 -0.10873320 -0.08886304
9    I  18.3 19.5  30.3   33 -0.063513406 -0.08535985 -0.07443663

或者如果有很多对,自动执行

library(stringr)
df1 %>%
     mutate(Mean = rowMeans(across(starts_with('test'), 
    ~ log(.) - log(get(str_replace(cur_column(), "test", "ref")))), na.rm = TRUE))

-输出

code test1 ref1 test2 ref2        Mean
1    A  19.0 19.5  31.8   33 -0.03150838
2    B  17.6 19.5  29.1   33 -0.11414248
3    C  19.6 19.5  31.4   33 -0.02229228
4    D  20.0 19.5  33.5   33  0.02017784
5    E  17.8 19.5  30.5   33 -0.08499844
6    F  18.6 19.5  31.7   33 -0.04372188
7    G  19.0 19.5  31.2   33 -0.04103248
8    H  18.2 19.5  29.6   33 -0.08886304
9    I  18.3 19.5  30.3   33 -0.07443663

数据

df1 <- structure(list(code = c("A", "B", "C", "D", "E", "F", "G", "H", 
"I"), test1 = c(19, 17.6, 19.6, 20, 17.8, 18.6, 19, 18.2, 18.3
), ref1 = c(19.5, 19.5, 19.5, 19.5, 19.5, 19.5, 19.5, 19.5, 19.5
), test2 = c(31.8, 29.1, 31.4, 33.5, 30.5, 31.7, 31.2, 29.6, 
30.3), ref2 = c(33L, 33L, 33L, 33L, 33L, 33L, 33L, 33L, 33L)),
 class = "data.frame", row.names = c("1", 
"2", "3", "4", "5", "6", "7", "8", "9"))

答案 1 :(得分:2)

实际上,paste 将数字转换为名称很酷。这是适合您示例的解决方案。如果您有四对,只需在 1:4 中使用 sapply

rowMeans(sapply(1:2, \(i) 
                log(dat[[paste0('test', i)]]) - log(dat[[paste0('ref', i)]])), 
         na.rm=TRUE)
# [1] -0.03150838 -0.11414248 -0.02229228  0.02017784 -0.08499844 -0.04372188
# [7] -0.04103248 -0.08886304 -0.07443663

注意: \(i) 在 R4.1.0 之前的 R 版本中表示 function(i)

答案 2 :(得分:2)

如果你经常对数据做这样的事情,你可能会发现以“长”格式存储数据更方便,因为这样的操作可以更自然地完成

做成长格式

df1_long <- 
  df1 %>% 
    pivot_longer(names_pattern = '(test|ref)(\\d+)',
                 names_to = c('name', 'num'),
                 cols = -1) %>% 
    group_by(code, num) %>% 
    arrange(name, .by_group = TRUE)
# # A tibble: 36 x 4
# # Groups:   code, num [18]
# code  name  num   value
# <chr> <chr> <chr> <dbl>
#   1 A     ref   1      19.5
#   2 A     test  1      19  
#   3 A     ref   2      33  
#   4 A     test  2      31.8
#   5 B     ref   1      19.5
#   6 B     test  1      17.6
#   7 B     ref   2      33  
#   8 B     test  2      29.1
#   9 C     ref   1      19.5
#   10 C     test  1      19.6
#   # … with 26 more rows

有了这种形状的数据,如何按组获取摘要就更明显了

df1_long %>% 
  summarise(dlog = diff(log(value))) %>% 
  summarise(mean_dlog = mean(dlog))
# # A tibble: 9 x 2
# code  mean_dlog
# <chr>     <dbl>
#   1 A       -0.0315
#   2 B       -0.114 
#   3 C       -0.0223
#   4 D        0.0202
#   5 E       -0.0850
#   6 F       -0.0437
#   7 G       -0.0410
#   8 H       -0.0889
#   9 I       -0.0744

您也可以使用此方法,同时仍将数据保持为相同格式,但在这种情况下,您也可以在其他答案中使用该方法

df1 %>% 
  pivot_longer(names_pattern = '(test|ref)(\\d+)',
               names_to = c('name', 'num'),
               cols = -1) %>% 
  group_by(code, num) %>% 
  arrange(name) %>% 
  summarise(dlog = diff(log(value))) %>% 
  summarise(mean_dlog = mean(dlog)) %>% 
  mutate(.data = df1, mean_dlog = .$mean_dlog)
# code test1 ref1 test2 ref2   mean_dlog
# 1    A  19.0 19.5  31.8   33 -0.03150838
# 2    B  17.6 19.5  29.1   33 -0.11414248
# 3    C  19.6 19.5  31.4   33 -0.02229228
# 4    D  20.0 19.5  33.5   33  0.02017784
# 5    E  17.8 19.5  30.5   33 -0.08499844
# 6    F  18.6 19.5  31.7   33 -0.04372188
# 7    G  19.0 19.5  31.2   33 -0.04103248
# 8    H  18.2 19.5  29.6   33 -0.08886304
# 9    I  18.3 19.5  30.3   33 -0.07443663