【问题标题】:How to set multiple conditions for multiple values in a row in R?如何为R中的一行中的多个值设置多个条件?
【发布时间】:2020-06-22 06:49:33
【问题描述】:

我有一个遗传数据集,其中每一行描述一个基因,并且有一个包含多个 beta 值的 beta 列,我已将其压缩到一个行/单元格中(从一个基因中的多个变体给出多个 beta 的变体级别)。 β 是基因在某种条件下可能产生的影响大小,因此大的负值和大的正值一样重要。我正在尝试编写代码来选择基因的最大负或最大正 beta 值,在 -0.5 和 0.5 处截断。

我要编写的规则如下:

如果一个基因/行的值小于 -0.5 且没有值高于 0.5,则只保留最大的负值。

如果它有一个大于 0.5 的值并且没有小于 -0.5 的值,则只保留最大的正值。

如果没有小于 -0.5 或大于 0.5 的值,则保留最大值。

如果它的两个值都小于 -0.5 和大于 0.5,则保留最大值。

例如我的数据如下所示:

Gene    Beta(s)
ACE     0.01, -0.6, 0.4
BRCA    0.7, -0.2, 0.2 
ZAP70   0.001, 0.02, -0.003
P53     0.8, -0.6, 0.001

预期输出(根据设定条件选择最大的负值或正值):

Gene    Beta(s)
ACE     -0.6  
BRCA     0.7
ZAP70    0.02
P53      0.8   

我来自生物学背景,刚接触 R,所以不知道如何编码。目前我正在使用函数来选择基因的最大或最小 beta 值,但我不知道如何在进一步的条件下修改它:

max2 = function(x) if(all(is.na(x))) NA else max(x,na.rm = T)
getmax = function(col) str_extract_all(col,"[0-9\\.-]+") %>%
  lapply(.,function(x)max2(as.numeric(x)) ) %>%
  unlist() 

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() 

test <- df %>%
  mutate_at(names(df)[2],getmax)

对于如何设置多个条件语句的正确方向的任何帮助,我们将不胜感激。

示例数据:

 dput(df)
structure(list(Gene = c("ACE", "BRCA", "ZAP70", "P53"), `Beta(s)` = c("0.01, -0.6, 0.4", 
"0.7, -0.2, 0.2", "0.001, 0.02, -0.003", "0.8, -0.6, 0.001")), row.names = c(NA, 
-4L), class = c("data.table", "data.frame"))

【问题讨论】:

  • 所以它们都是根据最小值和最大值分组的(针对-0.5和+0.5)?

标签: r dplyr conditional-statements bioinformatics


【解决方案1】:

虽然逻辑对我来说并不完全清楚,但很可能是这样的:

library(tidyverse)
library(stringr)

df %>%
  separate("Beta(s)", sep = ",", into = str_c("v", 1:3)) %>%
  mutate_at(vars(starts_with("v")), as.numeric) %>%
  mutate(vmax = pmax(v1, v2, v3), vmin = pmin(v1, v2, v3)) %>%
  mutate(want = case_when(vmax > 0.5 & vmin > -0.5 ~ vmax, # if vmax is > 0.5, it is always positive ..
                          abs(vmax) > abs(vmin) ~ vmax, # get largest absolute value ??
                          TRUE ~ vmin)) %>%
  select(Gene, want)


# Gene  want
# 1   ACE -0.60
# 2  BRCA  0.70
# 3 ZAP70  0.02
# 4   P53  0.80

## edited (handling multiple columns and NA):

df %>%
  bind_cols(df %>% 
              pull("Beta(s)") %>%
              str_split(",", simplify = TRUE) %>%
              `colnames<-`(str_c("v", 1:NCOL(.))) %>%
              as_tibble() %>%
              mutate_all(~str_remove_all(., "\\s") %>%
                           str_remove_all(., "NA") %>%
                           as.numeric) %>%
              mutate(vmax = pmap_dbl(., pmax, na.rm = T),
                     vmin = pmap_dbl(., pmin, na.rm = T))) %>%
  mutate(want = case_when(vmax > 0.5 & vmin > -0.5 ~ vmax, 
                          abs(vmax) > abs(vmin) ~ vmax, 
                          TRUE ~ vmin)) %>%
  select(Gene, want)

【讨论】:

  • 谢谢你,这运行得非常高效。在我的实际数据集中,我的行中有超过 3 个值,或者一些只有 NA - 不确定这是否重要,但有没有办法扩展它以考虑所有值,尽管每行有多少值?
  • 是的,但它越来越乱了。 :-)
【解决方案2】:

这是一个 data.table 解决方案,它应该可以快速运行并且与所提供的 beta 数量无关。

library( data.table )
library( matrixStats ) 
#set df as data.table
setDT( df )
#split Beta(s) to columns (dynamically)
df[, paste0( "Beta", 
             1:length( tstrsplit( df$`Beta(s)`, "," ) ) ) := 
     lapply( tstrsplit( `Beta(s)`, "," ), as.numeric ) ][]
#     Gene             Beta(s) Beta1 Beta2  Beta3
# 1:   ACE     0.01, -0.6, 0.4 0.010 -0.60  0.400
# 2:  BRCA      0.7, -0.2, 0.2 0.700 -0.20  0.200
# 3: ZAP70 0.001, 0.02, -0.003 0.001  0.02 -0.003
# 4:   P53    0.8, -0.6, 0.001 0.800 -0.60  0.001


#now, using rowMINs ans RowMAxs from the matrixStats-package (=FAST!!)
# get the filtering (and updating) done by reference.

#If a gene/row has a value less than -0.5 and no values higher than 0.5 then keep only the largest negative value.
df[ df[, rowMins( as.matrix(.SD), na.rm = TRUE ), .SDcols = patterns("^Beta[0-9]") ] < -0.5 &
      df[, rowMaxs( as.matrix(.SD), na.rm = TRUE ), .SDcols = patterns("^Beta[0-9]") ] <= 0.5,
    Beta.final := rowMins( as.matrix(.SD), na.rm = TRUE ), .SDcols = patterns("^Beta[0-9]") ]
#If it has a value higher than 0.5 and no values less than -0.5 keep only the largest positive value.
df[ df[, rowMaxs( as.matrix(.SD), na.rm = TRUE ), .SDcols = patterns("^Beta[0-9]") ] > 0.5 &
      df[, rowMins( as.matrix(.SD), na.rm = TRUE ), .SDcols = patterns("^Beta[0-9]") ] >= -0.5,
    Beta.final := rowMaxs( as.matrix(.SD), na.rm = TRUE ), .SDcols = patterns("^Beta[0-9]") ]
#If it has no values less than -0.5 or more than 0.5 keep the largest value.
df[ df[, rowMins( as.matrix(.SD), na.rm = TRUE ), .SDcols = patterns("^Beta[0-9]") ] >= -0.5 &
      df[, rowMaxs( as.matrix(.SD), na.rm = TRUE ), .SDcols = patterns("^Beta[0-9]") ] <= 0.5,
    Beta.final := rowMaxs( as.matrix(.SD), na.rm = TRUE ), .SDcols = patterns("^Beta[0-9]") ]
#If it has both values less than -0.5 and more than 0.5 keep the largest value.
df[ df[, rowMins( as.matrix(.SD), na.rm = TRUE ), .SDcols = patterns("^Beta[0-9]") ] < -0.5 &
      df[, rowMaxs( as.matrix(.SD), na.rm = TRUE ), .SDcols = patterns("^Beta[0-9]") ] > 0.5,
    Beta.final := rowMaxs( as.matrix(.SD), na.rm = TRUE ), .SDcols = patterns("^Beta[0-9]") ]

*输出

#final output
df[, .(Gene, `Beta(s)` = Beta.final )][]
#     Gene Beta(s)
# 1:   ACE   -0.60
# 2:  BRCA    0.70
# 3: ZAP70    0.02
# 4:   P53    0.80

【讨论】:

  • 谢谢你,这看起来会很好用。我只是有一个错误Error: Pattern not found: [^Beta[0-9]]。我有一些基因只有 NA 作为他们的 beta,这个错误是因为这个吗? [0-9] 是否需要考虑这一点?在此期间,我会努力让它发挥作用。
  • 正则表达式 "^Beta[0-9]" 正在查找名称以 Beta 开头的列,后跟数字 0 - 9。检查您的列名以查看是否存在与此模式匹配的任何列..
  • 谢谢,原来我有一些错别字,现在可以了。它用 -Inf 替换了 NA,但我会尝试将它们切换回 NA,其他一切都按预期工作,感谢您的帮助。
  • 正确...因为设置了na.rm = TRUE,它在确定最大值和/或最小值时忽略了NA。见输出:rowMaxs( matrix( c(1, NA, 3, 2, NA, NA), ncol = 2 ), na.rm = TRUE )。但是如果不设置na.rm = TRUE,输出将不会如预期的那样,见:rowMaxs( matrix( c(1, NA, 3, 2, NA, NA), ncol = 2 ) )。所以之后替换-Inf确实是要走的路。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-01
  • 2021-10-18
  • 2017-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多