如何基于df中的其他2列向R中的数据框添加多个新列

xtfmy6hx  于 2023-04-03  发布在  其他
关注(0)|答案(4)|浏览(271)

我想在我的数据框中每2列添加一个新列,基于这2列的值。数据框有70列和超过60k行。下面是一个小例子,其中样本作为列名(FF1,FFPE1等),基因在行中:

> gene<-c("gene1", "gene2", "gene3", "gene4")
> FF1<-c(10,20,30,40)
> FFPE1<-c(10,9,2,1)
> FF2<-c(0,2,50,60)
> FFPE2<-c(10,10,100,200)
> expression<-data.frame(gene, FF1, FFPE1, FF2, FFPE2)

> expression
   gene FF1 FFPE1 FF2 FFPE2
1 gene1  10    10   0    10
2 gene2  20     9   2    10
3 gene3  30     2  50   100
4 gene4  40     1  60   200

我想评估每个配对样本。如果该基因的两个样本的值都大于5,则新列在该点处将具有3。如果FF样本大于5但FFPE不大于5,则新列将获得1。如果FFPE样本大于5但FF样本不大于5,则新列将获得2。它看起来如下所示:

> group1<-c(3,3,1,1)
> group2<-c(2,2,3,3)
> expression<-data.frame(expression, group1, group2)

> expression
   gene FF1 FFPE1 FF2 FFPE2 group1 group2
1 gene1  10    10   0    10      3      2
2 gene2  20     9   2    10      3      2
3 gene3  30     2  50   100      1      3
4 gene4  40     1  60   200      1      3

但我不会手动添加新的组列。
有什么建议吗?我发现了基于多个条件的类似问题,但他们只创建了1个新列。或者相反,他们只基于df中已有的一个列创建了多个新列。我想过使用mutatecase_when,但我不知道如何为每2列执行此操作。

ccrfmcuu

ccrfmcuu1#

对于这样的问题,我们可以使用'dplyover'包。免责声明:我是维护者,它不在CRAN上。
一种方法是使用dplyover::across2来选择要循环的列对。为了选择列对,我们使用带有matches()的正则表达式。在.fns中的函数中,我们使用.x作为第一列,.y作为第二列。注意,列的顺序必须正确。

library(dplyr)
library(dplyover) # https://github.com/TimTeaFan/dplyover

expression %>% 
  mutate(across2(matches("^[F]+\\d+$"),
                 matches("^[F]+PE\\d+$"),
                 ~ case_when(
                  .x > 5   & .y > 5 ~ 3,
                  !(.x >5 )& .y > 5 ~ 2,
                  .x > 5   & !(.y > 5) ~ 1,
                 ),
                 .names = "{ycol}",
                 .names_fn = ~ gsub("FFPE", "group", .x)
                 )
         )

#>    gene FF1 FFPE1 FF2 FFPE2 group1 group2
#> 1 gene1  10    10   0    10      3      2
#> 2 gene2  20     9   2    10      3      2
#> 3 gene3  30     2  50   100      1      3
#> 4 gene4  40     1  60   200      1      3

dplyover::over()是一种更保存编程时间的方法,在这里我们循环一个字符串并动态地构造列名,所以列的顺序并不重要。
我们使用extract_names来获取结束列数字,然后我们可以在.()函数的字符串中构造列名,其中{.x}被计算为循环中的当前数字。

expression %>% 
  mutate(over(extract_names("\\d+$"), # <- gets us `c("1", "2")`
                 ~ case_when(
                   .("FF{.x}") > 5   & .("FFPE{.x}") > 5 ~ 3,
                   !(.("FF{.x}") >5 )& .("FFPE{.x}") > 5 ~ 2,
                   .("FF{.x}") > 5   & !(.("FFPE{.x}") > 5) ~ 1,
                 ),
                 .names = "group{x}"
  )
  )

#>    gene FF1 FFPE1 FF2 FFPE2 group1 group2
#> 1 gene1  10    10   0    10      3      2
#> 2 gene2  20     9   2    10      3      2
#> 3 gene3  30     2  50   100      1      3
#> 4 gene4  40     1  60   200      1      3

数据来自OP

gene<-c("gene1", "gene2", "gene3", "gene4")
FF1<-c(10,20,30,40)
FFPE1<-c(10,9,2,1)
FF2<-c(0,2,50,60)
FFPE2<-c(10,10,100,200)
expression<-data.frame(gene, FF1, FFPE1, FF2, FFPE2)

创建于2023-04-03带有reprex v2.0.2

yk9xbfzb

yk9xbfzb2#

下面是另一种实现你想要的东西的方法:

library(dplyr)
library(tidyr)

df <- expression %>%
  pivot_longer(cols= -gene, names_to = "sample", values_to = "val") %>%
  separate(sample, into = c("name", "id"), sep = "(?<=[A-Za-z])(?=[0-9])") %>%
  pivot_wider(names_from = "name", values_from = "val") %>%
  rowwise() %>%
  mutate(group = ifelse(FF > 5 && FFPE > 5, 3, 
                        ifelse(FF > 5, 1, 2))) %>%
  pivot_wider(names_from = "id", values_from = c("FF", "FFPE", "group")) %>%
  dplyr::select(ends_with("1"), ends_with("2"))

输出:

# A tibble: 4 x 6
   FF_1 FFPE_1 group_1  FF_2 FFPE_2 group_2
  <dbl>  <dbl>   <dbl> <dbl>  <dbl>   <dbl>
1    10     10       3     0     10       2
2    20      9       3     2     10       2
3    30      2       1    50    100       3
4    40      1       1    60    200       3
3zwjbxry

3zwjbxry3#

你可以试试这个:

expression$group1 = (expression$FF1>5) + 2*(expression$FFPE1>5)
expression$group2 = (expression$FF2>5) + 2*(expression$FFPE2>5)

我将使用与@asaei类似的方法。为了使pivot_longer更容易,我更改了一些名称,FF 1到FF_1.....区别在于mutate()的内部

gene <- c("gene1", "gene2", "gene3", "gene4")
FF_1 <- c(10, 20, 30, 40)
FFPE_1 <- c(10, 9, 2, 1)
FF_2 <- c(0, 2, 50, 60)
FFPE_2 <- c(10, 10, 100, 200)
expression <- data.frame(gene, FF_1, FFPE_1, FF_2, FFPE_2)

expression %>%
  pivot_longer(
    cols = -gene,
    names_to = c(".value", "set"),
    names_sep = "_"
  ) %>%
  mutate(group = (FF > 5) + 2 * (FFPE > 5)) %>%
  pivot_wider(
    names_from = "set",
    values_from = c("FF", "FFPE", "group")
  )
8ftvxx2r

8ftvxx2r4#

基R方法:
这通过split.default按列拆分data.frame,并使用apply函数进行一些值匹配。

cbind(expression, do.call(cbind, lapply(split.default(expression[-1], gsub(".+(\\d)", "\\1", names(expression[-1]))), \(x)
       apply(x, 1, \(x) if(all(x > 5)){
         return(3)
       } else if(x[1] > 5 &  x[2] < 5){
         return(1)
       } else if(x[2] > 5 & x[1] < 5){
         return(2)
       })) |> 
  (\(lst) setNames(lst, paste0("group", seq(lst))) )()))
gene FF1 FFPE1 FF2 FFPE2 group1 group2
1 gene1  10    10   0    10      3      2
2 gene2  20     9   2    10      3      2
3 gene3  30     2  50   100      1      3
4 gene4  40     1  60   200      1      3

相关问题