我试图在我的数据框中创建一个新变量,它返回满足条件的变量名称,但是我在数据集上也有一个chr变量,因此必须应用某种数字包装器。
数据集之前:
ChrV | V1 | V2 | V3 Obs 1 | chr1 | 0.65 | 0.30 | 0.40 Obs 2 | chr2 | 0.35 | 0.75 | 0.42 Obs 3 | chr3 | 0.10 | 0.43 | 0.80
我的解决方案
ChrV <- ds$ChrV
ds$ChrV <- NULL
ds$V4 <- apply(ds, 1, function(x) paste(names(which(abs(x) >= 0.5))))
ds <- cbind(ChrV, ds)
输出:
ChrV | V1 | V2 | V2 | V4 Obs 1 | chr1 | 0.65 | 0.30 | 0.40 | Var 1 Obs 2 | chr2 | 0.35 | 0.75 | 0.42 | Var 2 Obs 3 | chr3 | 0.10 | 0.43 | 0.80 | Var 3
我的问题:
虽然我的解决方案有效,但我需要找到一个忽略chr变量的更优雅的解决方案(因此它只考虑数值变量,我不需要删除变量并在以后再次绑定它们),这也适用于任何数据集,无论列数和行数。
dput(DS)
structure(list(
ChrV = c("chr1", "chr2", "chr3"),
V1 = c(3, 2, 1),
V2 = c(1, 3, 2),
V3 = c(1, 2, 3)),
row.names = c(NA, -6L),
class = c("data.table", "data.frame"),
.internal.selfref = <pointer: 0x0000000002541ef0>)
如果tidyverse
解决方案可以接受,您可以按以下方式执行:
library(tidyverse)
df %>%
rownames_to_column() %>%
gather(cname, val, V1:V3) %>%
group_by(ChrV) %>%
mutate(V4 = cname[abs(as.numeric(val)) >= .5] %>% str_c(collapse = ' ')) %>%
spread(cname, val)
你仍然可以用max.col
做到这一点
ds$V4 <- paste("Var", max.col(abs(ds[2:4]) > 0.5))
df
# ChrV V1 V2 V3 V4
#Obs1 chr1 0.65 0.30 0.40 Var 1
#Obs2 chr2 0.35 0.75 0.42 Var 2
#Obs3 chr3 0.10 0.43 0.80 Var 3
或者,如果您想要列名称
ds$V4 <- names(ds)[2:4][max.col(abs(ds[2:4]) > 0.5)]
如果您想以动态方式仅选择数字列,我们可以使用@markus建议的Filter
new_ds <- Filter(is.numeric, ds)
ds$V4 <- names(new_ds)[max.col(abs(new_ds) > 0.5)]
您可以在apply函数中对数据框进行子集化:
ds$V4 <- apply(ds[colnames(ds) != "ChrV"], 1, function(x)
paste(names(which(abs(x) >= 0.5))))
编辑
对于类data.frame,删除粘贴并对apply的输出进行子集化:
> ds <- data.frame(
+ ChrV = c("chr1", "chr2", "chr3"),
+ V1 = c(3, 2, 1),
+ V2 = c(1, 3, 2),
+ V3 = c(1, 2, 3))
>
>
> ds$V4 <- apply(ds[colnames(ds) != "ChrV"], 1, function(x) {
+ names(which(abs(x) >= 0.5))
+ })[,1]
>
> ds
ChrV V1 V2 V3 V4
1 chr1 3 1 1 V1
2 chr2 2 3 2 V2
3 chr3 1 2 3 V3
>
再见!