Select 一个单元格内的最小值或最大值(分隔字符串)
Select min or max values within one cell (delimited string)
我有一个数据框,其中每个样本的列可以有多个值,例如:
Gene Pvalue1 Pvalue2 Pvalue3 Beta
Ace 0.0381, ., 0.00357 0.01755, 0.001385 0.0037, NA , 0.039 -0.03,1,15
NOS NA 0.02 0.001, 0.00067 0.00009,25,30
我想对每一列中的每个基因数据(我总共有数千个基因)应用 min()
和 max()
并获得 pvalues 的最小值,但列的最大值比如贝塔。所以输出数据看起来像这样:
Gene Pvalue1 Pvalue2 Pvalue3 Beta
Ace 0.00357 0.001385 0.0037 15
NOS NA 0.02 0.00067 30
我是 R 的新手,不确定我的问题是否可行,如果一个单元格中有多个值,它们是否被视为字符串?
使用 stringr
和 dplyr
的可能解决方案:
library(dplyr)
library(stringr)
getmin = function(col) str_extract_all(col,"[0-9\.-]+") %>%
lapply(.,function(x) min(as.numeric(x),na.rm = T) ) %>%
unlist()
df %>%
mutate_at(names(df)[-1],getmin)
Gene Pvalue1 Pvalue2 Pvalue3 Beta
1 Ace 0.00357 0.001385 0.00370 -3e-02
2 NOS Inf 0.020000 0.00067 9e-05
Warning messages:
1: In FUN(X[[i]], ...) : NAs introduced by coercion
2: In min(as.numeric(x), na.rm = T) :
no non-missing arguments to min; returning Inf
函数getmin
用str_extract_all
提取数字:
str_extract_all(df$Pvalue2,"[0-9\.-]+")
[[1]]
[1] "0.01755" "0.001385"
[[2]]
[1] "0.02"
它的优点是对space或其他字符不敏感,但只能提取一个点。然后我在这个列表上循环以在每个单元格中提取最小值,并将列表转换为具有 unlist
的向量。使用 as.numeric()
函数将可能提取的 .
转换为 NA
.
代码 df %>% mutate_at(names(df)[-1],getmin)
仅将此函数应用于除第一列以外的所有列
编辑:如果你想避免 inf 值,你可以使用这个稍微修改过的版本:
min2 = function(x) if(all(is.na(x))) NA else min(x,na.rm = T)
getmin = function(col) str_extract_all(col,"[0-9\.-]+") %>%
lapply(.,function(x)min2(as.numeric(x)) ) %>%
unlist()
df %>%
mutate_at(names(df)[-1],getmin)
Gene Pvalue1 Pvalue2 Pvalue3 Beta
1 Ace 0.00357 0.001385 0.00370 -3e-02
2 NOS NA 0.020000 0.00067 9e-05
数据:
df <- read.table(text = "
Gene Pvalue1 Pvalue2 Pvalue3 Beta
Ace 0.0381,.,0.00357 0.01755,0.001385 0.0037,NA,0.039 -0.03,1,15
NOS NA 0.02 0.001,0.00067 0.00009,25,30
",header = T)
这是大致的想法。
applyFunctionToString <- function(
string
, sep = ","
){
string <- gsub(" ", "", string)
string <- unlist(strsplit(string, sep))
string[string == "NA"] <- NA
numbers <- as.numeric(string)
min(numbers, na.rm = TRUE)
}
sapply(c("0.01755, 0.001385", "0.0037, NA , 0.039"), applyFunctionToString)
您实际上想要进行字符串运算,将每个字符串转换为数值向量,然后执行汇总函数(min
或max
)。
我在这里写的代码适用于这种情况,但你必须考虑更多因素:
- 您的字符串是否包含其他需要删除的字符?
- 缺失值代表什么?
你也可以传递你想要应用的函数(例如min
),但是你还有其他问题,比如你如何将额外的参数传递给那个函数(使用...
) - 这将超出范围。
希望,还是有点帮助。
这是一个基本的 R 解决方案,使用 regmatches
+ gregexpr
来排序数字,即
dPvalue <- t(apply(df[grep("Pvalue",names(df))], 1, function(v) {
unlist(Map(function(x) ifelse(length(x)>0, min(as.numeric(x)),NA), regmatches(v, gregexpr("-?\d+(\.\d+)?",v))))
}))
Beta <- apply(df[grep("Beta",names(df))], 1, function(v) {
unlist(Map(function(x) ifelse(length(x)>0, max(as.numeric(x)),NA), regmatches(v, gregexpr("-?\d+(\.\d+)?",v))))
})
dfout <- cbind(df["Gene"],Pvalue,Beta)
这样
> dfout
Gene Pvalue1 Pvalue2 Pvalue3 Beta
1 Ace 0.00357 0.001385 0.00370 15
2 NOS NA 0.020000 0.00067 30
数据
df <- structure(list(Gene = structure(1:2, .Label = c("Ace", "NOS"), class = "factor"),
Pvalue1 = structure(c(1L, NA), .Label = "0.0381,.,0.00357", class = "factor"),
Pvalue2 = structure(1:2, .Label = c("0.01755,0.001385", "0.02"
), class = "factor"), Pvalue3 = structure(2:1, .Label = c("0.001,0.00067",
"0.0037,NA,0.039"), class = "factor"), Beta = structure(1:2, .Label = c("-0.03,1,15",
"0.00009,25,30"), class = "factor")), class = "data.frame", row.names = c(NA,
-2L))
使用 data.table,将宽转换为长,以逗号分隔,得到 P 值的 min 和max for Betas,最后转回长宽。
library(data.table)
dt1 <- fread("
Gene Pvalue1 Pvalue2 Pvalue3 Beta
Ace 0.0381,.,0.00357 0.01755,0.001385 0.0037,NA,0.039 -0.03,1,15
NOS NA 0.02 0.001,0.00067 0.00009,25,30
")
dcast(
melt(dt1, id.vars = "Gene")[, paste0("col", 1:3) := lapply(tstrsplit(value, ","), as.numeric)
][, MinMax := ifelse(grepl("Pvalue", variable),
pmin(col1, col2, col3, na.rm = TRUE),
pmax(col1, col2, col3, na.rm = TRUE)) ],
Gene ~ variable, value.var = "MinMax")
# Gene Pvalue1 Pvalue2 Pvalue3 Beta
# 1: Ace 0.00357 0.001385 0.00370 15
# 2: NOS NA 0.020000 0.00067 30
# Warning message:
# In lapply(tstrsplit(value, ","), as.numeric) : NAs introduced by coercion
注意: 可以使用 dplyr/tidyr
应用相同的步骤。
另一个选项是使用 data.table and matrixstats:
library(data.table)
library(matrixStats)
pval_cols <- grep("Pvalue", names(DT), fixed = TRUE, value = TRUE)
min_fun <- function(x) {
y <- tstrsplit(x, split = ",", fixed = TRUE)
y <- rowMins(sapply(y, as.numeric), na.rm = TRUE)
y <- replace(y, !is.finite(y), NA)
return(y)
}
DT[, (pval_cols) := lapply(.SD, min_fun)
, .SDcols = pval_cols][]
给出:
> DT
Gene Pvalue1 Pvalue2 Pvalue3 Beta
1: Ace 0.00357 0.001385 0.00370 -0.03,1,15
2: NOS NA 0.020000 0.00067 0.00009,25,30
对于 Beta
列,您可以创建一个类似的 max_fun
:只需将 rowMins
替换为 rowMaxs
。
我有一个数据框,其中每个样本的列可以有多个值,例如:
Gene Pvalue1 Pvalue2 Pvalue3 Beta
Ace 0.0381, ., 0.00357 0.01755, 0.001385 0.0037, NA , 0.039 -0.03,1,15
NOS NA 0.02 0.001, 0.00067 0.00009,25,30
我想对每一列中的每个基因数据(我总共有数千个基因)应用 min()
和 max()
并获得 pvalues 的最小值,但列的最大值比如贝塔。所以输出数据看起来像这样:
Gene Pvalue1 Pvalue2 Pvalue3 Beta
Ace 0.00357 0.001385 0.0037 15
NOS NA 0.02 0.00067 30
我是 R 的新手,不确定我的问题是否可行,如果一个单元格中有多个值,它们是否被视为字符串?
使用 stringr
和 dplyr
的可能解决方案:
library(dplyr)
library(stringr)
getmin = function(col) str_extract_all(col,"[0-9\.-]+") %>%
lapply(.,function(x) min(as.numeric(x),na.rm = T) ) %>%
unlist()
df %>%
mutate_at(names(df)[-1],getmin)
Gene Pvalue1 Pvalue2 Pvalue3 Beta
1 Ace 0.00357 0.001385 0.00370 -3e-02
2 NOS Inf 0.020000 0.00067 9e-05
Warning messages:
1: In FUN(X[[i]], ...) : NAs introduced by coercion
2: In min(as.numeric(x), na.rm = T) :
no non-missing arguments to min; returning Inf
函数getmin
用str_extract_all
提取数字:
str_extract_all(df$Pvalue2,"[0-9\.-]+")
[[1]]
[1] "0.01755" "0.001385"
[[2]]
[1] "0.02"
它的优点是对space或其他字符不敏感,但只能提取一个点。然后我在这个列表上循环以在每个单元格中提取最小值,并将列表转换为具有 unlist
的向量。使用 as.numeric()
函数将可能提取的 .
转换为 NA
.
代码 df %>% mutate_at(names(df)[-1],getmin)
仅将此函数应用于除第一列以外的所有列
编辑:如果你想避免 inf 值,你可以使用这个稍微修改过的版本:
min2 = function(x) if(all(is.na(x))) NA else min(x,na.rm = T)
getmin = function(col) str_extract_all(col,"[0-9\.-]+") %>%
lapply(.,function(x)min2(as.numeric(x)) ) %>%
unlist()
df %>%
mutate_at(names(df)[-1],getmin)
Gene Pvalue1 Pvalue2 Pvalue3 Beta
1 Ace 0.00357 0.001385 0.00370 -3e-02
2 NOS NA 0.020000 0.00067 9e-05
数据:
df <- read.table(text = "
Gene Pvalue1 Pvalue2 Pvalue3 Beta
Ace 0.0381,.,0.00357 0.01755,0.001385 0.0037,NA,0.039 -0.03,1,15
NOS NA 0.02 0.001,0.00067 0.00009,25,30
",header = T)
这是大致的想法。
applyFunctionToString <- function(
string
, sep = ","
){
string <- gsub(" ", "", string)
string <- unlist(strsplit(string, sep))
string[string == "NA"] <- NA
numbers <- as.numeric(string)
min(numbers, na.rm = TRUE)
}
sapply(c("0.01755, 0.001385", "0.0037, NA , 0.039"), applyFunctionToString)
您实际上想要进行字符串运算,将每个字符串转换为数值向量,然后执行汇总函数(min
或max
)。
我在这里写的代码适用于这种情况,但你必须考虑更多因素:
- 您的字符串是否包含其他需要删除的字符?
- 缺失值代表什么?
你也可以传递你想要应用的函数(例如min
),但是你还有其他问题,比如你如何将额外的参数传递给那个函数(使用...
) - 这将超出范围。
希望,还是有点帮助。
这是一个基本的 R 解决方案,使用 regmatches
+ gregexpr
来排序数字,即
dPvalue <- t(apply(df[grep("Pvalue",names(df))], 1, function(v) {
unlist(Map(function(x) ifelse(length(x)>0, min(as.numeric(x)),NA), regmatches(v, gregexpr("-?\d+(\.\d+)?",v))))
}))
Beta <- apply(df[grep("Beta",names(df))], 1, function(v) {
unlist(Map(function(x) ifelse(length(x)>0, max(as.numeric(x)),NA), regmatches(v, gregexpr("-?\d+(\.\d+)?",v))))
})
dfout <- cbind(df["Gene"],Pvalue,Beta)
这样
> dfout
Gene Pvalue1 Pvalue2 Pvalue3 Beta
1 Ace 0.00357 0.001385 0.00370 15
2 NOS NA 0.020000 0.00067 30
数据
df <- structure(list(Gene = structure(1:2, .Label = c("Ace", "NOS"), class = "factor"),
Pvalue1 = structure(c(1L, NA), .Label = "0.0381,.,0.00357", class = "factor"),
Pvalue2 = structure(1:2, .Label = c("0.01755,0.001385", "0.02"
), class = "factor"), Pvalue3 = structure(2:1, .Label = c("0.001,0.00067",
"0.0037,NA,0.039"), class = "factor"), Beta = structure(1:2, .Label = c("-0.03,1,15",
"0.00009,25,30"), class = "factor")), class = "data.frame", row.names = c(NA,
-2L))
使用 data.table,将宽转换为长,以逗号分隔,得到 P 值的 min 和max for Betas,最后转回长宽。
library(data.table)
dt1 <- fread("
Gene Pvalue1 Pvalue2 Pvalue3 Beta
Ace 0.0381,.,0.00357 0.01755,0.001385 0.0037,NA,0.039 -0.03,1,15
NOS NA 0.02 0.001,0.00067 0.00009,25,30
")
dcast(
melt(dt1, id.vars = "Gene")[, paste0("col", 1:3) := lapply(tstrsplit(value, ","), as.numeric)
][, MinMax := ifelse(grepl("Pvalue", variable),
pmin(col1, col2, col3, na.rm = TRUE),
pmax(col1, col2, col3, na.rm = TRUE)) ],
Gene ~ variable, value.var = "MinMax")
# Gene Pvalue1 Pvalue2 Pvalue3 Beta
# 1: Ace 0.00357 0.001385 0.00370 15
# 2: NOS NA 0.020000 0.00067 30
# Warning message:
# In lapply(tstrsplit(value, ","), as.numeric) : NAs introduced by coercion
注意: 可以使用 dplyr/tidyr
应用相同的步骤。
另一个选项是使用 data.table and matrixstats:
library(data.table)
library(matrixStats)
pval_cols <- grep("Pvalue", names(DT), fixed = TRUE, value = TRUE)
min_fun <- function(x) {
y <- tstrsplit(x, split = ",", fixed = TRUE)
y <- rowMins(sapply(y, as.numeric), na.rm = TRUE)
y <- replace(y, !is.finite(y), NA)
return(y)
}
DT[, (pval_cols) := lapply(.SD, min_fun)
, .SDcols = pval_cols][]
给出:
> DT Gene Pvalue1 Pvalue2 Pvalue3 Beta 1: Ace 0.00357 0.001385 0.00370 -0.03,1,15 2: NOS NA 0.020000 0.00067 0.00009,25,30
对于 Beta
列,您可以创建一个类似的 max_fun
:只需将 rowMins
替换为 rowMaxs
。