R 在一个单元格内选择最小值或最大值(分隔字符串)

R 在一个单元格内选择最小值或最大值(分隔字符串),r,dataframe,max,min,data.table,matrixstats,R,Dataframe,Max,Min,Data.table,Matrixstats,我有一个数据框,其中每个样本的列可以有多个值,例如: 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.

我有一个数据框,其中每个样本的列可以有多个值,例如:

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的最小值,但beta等列的最大值。因此,输出数据如下所示:

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\u extract\u all
提取数字:

 str_extract_all(df$Pvalue2,"[0-9\\.-]+")

[[1]]
[1] "0.01755"  "0.001385"

[[2]]
[1] "0.02"
它的优点是对空格或其他字符不敏感,但只能提取一个点。然后我在这个列表上循环,以提取每个单元格中的最小值,并将列表转换为一个带有
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这里是总体思路

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)

applyFunctionToString这里是一个基本的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)
数据

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))
df使用data.table,将宽转换为长,用逗号分割,得到p值的最小值和beta值的最大值,最后转换回长转换为宽

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
库(data.table)
dt1另一个选项是使用和:


对于
Beta
-列,您可以创建一个类似的
max_-fun
:只需将
rowMins
替换为
rowMaxs
,您好!如果你能提供一个可以直接放入R中的样本,这会更容易。你的问题“它们是否被视为字符串”可以用这种方式得到最简单的回答,但我认为它们确实是一个字符串。因此,我会尝试使用apply函数,将函数的组合放在如下位置:(对于最小值)min(str_split())。您好,谢谢。我将立即研究apply函数和您建议的函数组合。我如何提供直接进入R的样品?抱歉,如果这是一个基本问题,那么这听起来非常有用。使用类似dput()的内容将给出结构/数据,前几行通常足以回答这样的问题(可以使用head()函数)这是可能的(有时非常有用)要在一个单元格中包含多个数值,您应该测试
str_extract
str_extract
中的
str_all
函数,这允许您自制函数的大部分功能感谢您,这几乎可以正常工作,但出于某种原因,它将我的负数值定为正数(因此选择了错误的最小值/最大值)。这是我最了解的解释,因此我将继续努力,看看是否可以解决此问题,谢谢您的帮助!我一直在尝试解决此问题,似乎我需要修改
“[0-9\\\.]+”
以某种方式解释负数,但我没有发现任何类似的问题。如果您知道此问题的解决方案,请告诉我。很抱歉,我没有看到负数。您可以使用
[0-9\\.-]
取而代之的是,请看我的编辑。谢谢你。这几乎可以工作,但会产生6000多个变量,你知道这是为什么吗?我会继续研究解决这个问题,因为除了代码运行之外。@DN1如果你想在全局环境中保持干净并且变量更少,你可以编写自定义函数来包装所有变量我有6000多个基因,它给了我想要的列的最小值和最大值,但它转换了结果,所以每个基因的pValue本身就变成了一行。我会研究转置这个,再次感谢你的帮助
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))
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
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