我有一个非常大的数据框,其中行是观察值,列是基因标记。我想使用R创建一个新列,该列包含每个观察值中选择的若干列的总和。
如果我有200列和100行,则希望创建一个新列,其中包含列43到167的总和,该列只包含1或0。通过包含每行总和的新列,我将能够对具有最多基因标记的个体进行排序。
我感觉应该差不多就是这样:
data$new=sum(data$[,43:167])
rowSums
。
rowSums(data)
可以给您想要的结果。rowSums函数(正如Greg所提到的那样)可以实现您想要的功能,但是您在回答中混合了子集技术,请勿在使用“[]”时使用“$”,您的代码应该看起来更像:
data$new <- rowSums( data[,43:167] )
如果你想使用除了 sum 以外的函数,可以查看 ?apply 函数来对行或列应用通用函数。
incomeData
不是数字。使用类似str(incomeData)
的方法查看它是什么,然后可能将其转换为数字矩阵。 - Greg Snow我来这里是希望找到一种方法来获取数据表中所有列的总和,但在实施上述解决方案时遇到了问题。使用cbind
函数添加一个包含所有列总和的列的方法:
cbind(data, total = rowSums(data))
这种方法会向数据添加一个total
列,并避免了使用以上解决方案对所有列进行求和时出现的对齐问题(有关此问题的讨论,请参见下面的帖子)。
为了完整性,我将列出其他方法,这些方法未在此处提到,使用矩阵的dplyr语法完成相同任务的不同方式:
mat = matrix(1:12, ncol = 3)
library(dplyr)
mat %>% as_tibble() %>%
mutate(sum = rowSums(across(where(is.numeric))))
# A tibble: 4 x 4
V1 V2 V3 sum
<int> <int> <int> <dbl>
1 1 5 9 15
2 2 6 10 18
3 3 7 11 21
4 4 8 12 24
mat %>% as_tibble() %>%
rowwise() %>%
mutate(sumrange = sum(c_across(), na.rm = T))
或者通过列名选择特定的列:
mat %>% as_tibble() %>%
mutate( 'B1' = V1, B2 = V2) %>%
rowwise() %>%
mutate(sum_startswithB =
sum(c_across(starts_with("B")), na.rm = T))
V1 V2 V3 B1 B2 sum_startswithx
<int> <int> <int> <int> <int> <int>
1 1 5 9 1 5 6
2 2 6 10 2 6 8
3 3 7 11 3 7 10
4 4 8 12 4 8 12
在此案例中,按列索引排序,从第一列到第四列:
mat %>% as_tibble() %>%
mutate( 'B1' = V1, B2 = V2) %>%
rowwise() %>%
mutate(SumByIndex = sum(c_across(c(1:4)), na.rm = T))
V1 V2 V3 B1 B2 SumByIndex
<int> <int> <int> <int> <int> <int>
1 1 5 9 1 5 16
2 2 6 10 2 6 20
3 3 7 11 3 7 24
4 4 8 12 4 8 28
使用正则表达式:
mat %>% as_tibble() %>%
mutate( 'B1' = V1, B2 = V2) %>%
mutate(sum_V = rowSums(.[grep("V[2-3]", names(.))], na.rm = TRUE),
sum_B = rowSums(.[grep("B", names(.))], na.rm = TRUE))
V1 V2 V3 B1 B2 sum_V sum_B
<int> <int> <int> <int> <int> <dbl> <dbl>
1 1 5 9 1 5 14 6
2 2 6 10 2 6 16 8
3 3 7 11 3 7 18 10
4 4 8 12 4 8 20 12
mat %>% as_tibble() %>%
mutate( 'B1' = V1, B2 = V2) %>%
mutate(sum = select(., V1:B1) %>% apply(1, sum, na.rm=TRUE)) %>%
mutate(mean = select(., V1:B1) %>% apply(1, mean, na.rm=TRUE)) %>%
mutate(max = select(., V1:B1) %>% apply(1, max, na.rm=TRUE)) %>%
mutate(min = select(., V1:B1) %>% apply(1, min, na.rm=TRUE)) %>%
mutate(var = select(., V1:B1) %>% apply(1, var, na.rm=TRUE)) %>%
mutate(sd = select(., V1:B1) %>% apply(1, sd, na.rm=TRUE))
V1 V2 V3 B1 B2 sum mean max min var sd
<int> <int> <int> <int> <int> <int> <dbl> <int> <int> <dbl> <dbl>
1 1 5 9 1 5 16 4 9 1 14.7 3.83
2 2 6 10 2 6 20 5 10 2 14.7 3.83
3 3 7 11 3 7 24 6 11 3 14.7 3.83
4 4 8 12 4 8 28 7 12 4 14.7 3.83
1:12
,您可以通过计算第一列的值来验证。> sd(c(1,5,9,1))
[1] 3.829708
> sd(c(2,6,10,2))
[1] 3.829708
我将通过一个例子尝试为您提供每个方法的经过时间支持:
mat = matrix(runif(4e6), ncol = 50)
apply函数与rowSums函数的比较:
apply_func <- function(x) {
apply(x, 1, sum)
}
r_sum <- function(x) {
rowSums(x)
}
# Compare the methods
microbenchmark(
apply_func = app(mat),
r_sum = r_sum(mat), times = 1e5
)
------ 输出 -- 毫秒为单位 --------
expr min lq mean median uq max neval
apply_func 207.84661 260.34475 280.14621 279.18782 294.85119 354.1821 100
r_sum 10.76534 11.53194 13.00324 12.72792 14.34045 16.9014 100
你会注意到,使用rowSums函数的平均时间比apply函数小21倍。如果矩阵有太多列,那么经过的时间差异可能更显著。
这也可能有所帮助,但毫无疑问最佳选择是使用rowSums
函数:
data$new <- Reduce(function(x, y) {
x + data[, y]
}, init = data[, 43], 44:167)
tibble::tibble(
a = 10:20,
b = 55:65,
c = 2010:2020,
d = c(LETTERS[1:11])) %>%
janitor::adorn_totals(where = "col") %>%
tibble::as_tibble()
结果:
# A tibble: 11 x 5
a b c d Total
<int> <int> <int> <chr> <dbl>
1 10 55 2010 A 2065
2 11 56 2011 B 2067
3 12 57 2012 C 2069
4 13 58 2013 D 2071
5 14 59 2014 E 2073
6 15 60 2015 F 2075
7 16 61 2016 G 2077
8 17 62 2017 H 2079
9 18 63 2018 I 2081
10 19 64 2019 J 2083
11 20 65 2020 K 2085
data$new <- rowSums(data[43:167])
,翻译为:将data数据中第43列到第167列的数据进行行求和,并将结果存入新的一列new中。 - Marekrowsum
函数混淆! - Augustin