执行包含字符串的 mutate 函数

问题描述 投票:0回答:3

这是我的数据框

data.frame(
  condition = as.factor(c("ecoli_RPMI", "staph_RPMI", "RPMI", "ecoli_DMEM", "staph_DMEM", "DMEM", "ecoli_RPMI", "staph_RPMI", "RPMI", "ecoli_DMEM", "staph_DMEM", "DMEM")),
  time = as.numeric(c(1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2)),
  value = as.numeric(c(0.3, 0.3, 0.2, 0.4, 0.4, 0.1, 0.9, 0.8, 0.1, 0.7, 0.8, 0.2)))

我有更多的条件,代表细菌,即大肠杆菌或葡萄球菌,然后是它们生长的介质,以便条件写成这样,即“ecoli_RPMI”,“staph_RPMI”,“ecoli_DMEM”,“staph_DMEM”。我有多个时间点 (50) 左右以及多种细菌和培养基。

我也有媒体控制的条件。即“RPMI”、“DMEM”在多个时间点也再次具有相应的值

我正在尝试减去与介质对照(在同一行上)对应的“值”,即从带有 RPMI 后缀的所有细菌中减去“RPMI”值,x_RPMI 即“ecoli_RPMI”、“staph_RPMI”并分配值名为“ Corrected.values”的新列,例如:ecoli_RPMI 的值 - RPMI 的值

想要的结果是这样的

data.frame(
  condition = as.factor(c("ecoli_RPMI", "staph_RPMI", "RPMI", "ecoli_DMEM", "staph_DMEM", "DMEM", "ecoli_RPMI", "staph_RPMI", "RPMI", "ecoli_DMEM", "staph_DMEM", "DMEM")),
  time = as.numeric(c(1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2)),
  value = as.numeric(c(0.3, 0.3, 0.2, 0.4, 0.4, 0.1, 0.9, 0.8, 0.1, 0.7, 0.8, 0.2)),
  corrected_value = as.numeric(c(0.1, 0.1, 0, 0.3, 0.3, 0, 0.8, 0.7, 0, 0.5, 0.6, 0)))

我已经尝试过各种方法:

  1. 使用

    mutate
    case_when

    进行 group by 语句

    有点像这样

    df %>%
      group_by(time)%>%
      mutate(corrected_value = case_when(
      conditions == "ecoli_RPMI" ~ value - value[Conditions == "RPMI"],
    

    输入了所有的可能性,但他的似乎不起作用。我想知道是否可以使用字符串参数来简化它,因为字符串在所有条件下都是一致的,即始终

    "bacteria"_"media"

  2. 我也尝试过

    pivot_wider
    但没有任何运气

非常感谢您的帮助!

r string dplyr mutate
3个回答
0
投票

我认为最简单的解决方案是将条件变量拆分为两个变量(细菌、培养基),然后对分组数据进行减法。你可以这样做:

data.frame(condition = as.factor(
  c(
    "ecoli_RPMI",
    "staph_RPMI",
    "RPMI",
    "ecoli_DMEM",
    "staph_DMEM",
    "DMEM",
    "ecoli_RPMI",
    "staph_RPMI",
    "RPMI",
    "ecoli_DMEM",
    "staph_DMEM",
    "DMEM"
  )
),
time = as.numeric(c(1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2)),
value = as.numeric(c(
  0.3, 0.3, 0.2, 0.4, 0.4, 0.1, 0.9, 0.8, 0.1, 0.7, 0.8, 0.2
))) %>%
  mutate(
    bacterium = case_when(
      str_detect(condition, "ecoli") ~ "Ecoli",
      str_detect(condition, "staph") ~ "Staph",
      TRUE ~ "None"
    ),
    medium = case_when(
      str_detect(condition, "RPMI") ~ "RPMI",
      str_detect(condition, "DMEM") ~ "DMEM",
      TRUE ~ "None"
    )
  ) %>%
  group_by(medium, time) %>%
  mutate(corrected.values = value - value[bacterium == "None"]) %>%
  ungroup()

我正在使用 str_detect() 从条件中提取细菌和培养基。然后,对于每个时间点和培养基组合,您可以从整个组中减去没有细菌时获得的值。

这会产生这个结果,这似乎就是您正在寻找的结果。

# A tibble: 12 × 6
   condition   time value bacterium medium corrected.values
   <fct>      <dbl> <dbl> <chr>     <chr>             <dbl>
 1 ecoli_RPMI     1   0.3 Ecoli     RPMI                0.1
 2 staph_RPMI     1   0.3 Staph     RPMI                0.1
 3 RPMI           1   0.2 None      RPMI                0  
 4 ecoli_DMEM     1   0.4 Ecoli     DMEM                0.3
 5 staph_DMEM     1   0.4 Staph     DMEM                0.3
 6 DMEM           1   0.1 None      DMEM                0  
 7 ecoli_RPMI     2   0.9 Ecoli     RPMI                0.8
 8 staph_RPMI     2   0.8 Staph     RPMI                0.7
 9 RPMI           2   0.1 None      RPMI                0  
10 ecoli_DMEM     2   0.7 Ecoli     DMEM                0.5
11 staph_DMEM     2   0.8 Staph     DMEM                0.6
12 DMEM           2   0.2 None      DMEM                0  

0
投票

以下是两种方法:

第一个使用

group_modify()

在这里,我们首先动态创建一个组

bacteria
。然后我们使用
group_modify()
来对所有分组变量进行
.keep
。神奇的事情发生在我们的函数
.f
中,我们将其应用于分组数据
dat
以及包含分组信息的 tibble
grp
,其中每个组信息都存储在单独的列中。

我们基本上计算

corrected_values
调用中的
mutate
减去
value
,其中
condition
等于整个
grp$bacteria
列中的当前细菌组
value

library(tidyverse)

dat |> 
  group_by(time,
           bacteria = gsub("^.*_(\\w*$)", "\\1", condition)) |> 
  group_modify(.keep = FALSE,
               .f = \(dat, grp) {
    dat |> mutate(corrected_values = value - value[condition == grp$bacteria]) |>
  ungroup()
  })

#> # A tibble: 12 x 5
#>     time bacteria condition  value corrected_values
#>    <dbl> <chr>    <fct>      <dbl>            <dbl>
#>  1     1 DMEM     ecoli_DMEM   0.4              0.3
#>  2     1 DMEM     staph_DMEM   0.4              0.3
#>  3     1 DMEM     DMEM         0.1              0  
#>  4     1 RPMI     ecoli_RPMI   0.3              0.1
#>  5     1 RPMI     staph_RPMI   0.3              0.1
#>  6     1 RPMI     RPMI         0.2              0  
#>  7     2 DMEM     ecoli_DMEM   0.7              0.5
#>  8     2 DMEM     staph_DMEM   0.8              0.6
#>  9     2 DMEM     DMEM         0.2              0  
#> 10     2 RPMI     ecoli_RPMI   0.9              0.8
#> 11     2 RPMI     staph_RPMI   0.8              0.7
#> 12     2 RPMI     RPMI         0.1              0

第二个使用

pivot_wider() |> mutate(across()) |> pivot_longer() |> left_join()

诀窍在于

across()
语句,其中我们迭代每一列(
time
除外),然后
get
具有相应后缀的列,并从当前列
col
中减去它。

library(tidyverse)

dat |> 
  pivot_wider(names_from = condition,
              values_from = value) |> 
  mutate(across(! time,
                \(col) col - get(gsub("^.*_(\\w*$)", "\\1", cur_column()))
                )
         ) |> 
  pivot_longer(cols = !time,
               names_to = "condition",
               values_to = "corrected_values") |> 
  left_join(dat, by = c("time", "condition"))

#> # A tibble: 12 x 4
#>     time condition  corrected_values value
#>    <dbl> <chr>                 <dbl> <dbl>
#>  1     1 ecoli_RPMI              0.1   0.3
#>  2     1 staph_RPMI              0.1   0.3
#>  3     1 RPMI                    0     0.2
#>  4     1 ecoli_DMEM              0.3   0.4
#>  5     1 staph_DMEM              0.3   0.4
#>  6     1 DMEM                    0     0.1
#>  7     2 ecoli_RPMI              0.8   0.9
#>  8     2 staph_RPMI              0.7   0.8
#>  9     2 RPMI                    0     0.1
#> 10     2 ecoli_DMEM              0.5   0.7
#> 11     2 staph_DMEM              0.6   0.8
#> 12     2 DMEM                    0     0.2

来自OP的数据

dat <- data.frame( condition = as.factor(c("ecoli_RPMI", "staph_RPMI", "RPMI", "ecoli_DMEM", "staph_DMEM", "DMEM", "ecoli_RPMI", "staph_RPMI", "RPMI", "ecoli_DMEM", "staph_DMEM", "DMEM")), time = as.numeric(c(1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2)), value = as.numeric(c(0.3, 0.3, 0.2, 0.4, 0.4, 0.1, 0.9, 0.8, 0.1, 0.7, 0.8, 0.2)))

reprex 包于 2023 年 7 月 27 日创建(v2.0.1)


0
投票

您可以使用以下方法,将条件分为成分应变和介质,然后(每次)从包含应变的行中减去不包含应变的行:

data |>
  separate(condition, c("strain", "medium"), "_", remove = FALSE, fill = "left") |>
  group_by(time, medium) |>
  mutate(corrected_value = value - value[is.na(strain)]) |>
  ungroup()

产量:

# A tibble: 12 × 6
   condition  strain medium  time value corrected_value
   <fct>      <chr>  <chr>  <dbl> <dbl>           <dbl>
 1 ecoli_RPMI ecoli  RPMI       1   0.3             0.1
 2 staph_RPMI staph  RPMI       1   0.3             0.1
 3 RPMI       NA     RPMI       1   0.2             0
 4 ecoli_DMEM ecoli  DMEM       1   0.4             0.3
 5 staph_DMEM staph  DMEM       1   0.4             0.3
 6 DMEM       NA     DMEM       1   0.1             0
 7 ecoli_RPMI ecoli  RPMI       2   0.9             0.8
 8 staph_RPMI staph  RPMI       2   0.8             0.7
 9 RPMI       NA     RPMI       2   0.1             0
10 ecoli_DMEM ecoli  DMEM       2   0.7             0.5
11 staph_DMEM staph  DMEM       2   0.8             0.6
12 DMEM       NA     DMEM       2   0.2             0

或者,考虑将数据重塑为语义上更有意义的格式:

data |>
  separate(condition, c("strain", "medium"), "_", fill = "left") |>
  pivot_wider(names_from = strain) |>
  rename(baseline = `NA`) |>
  pivot_longer(! c(medium, time, baseline), names_to = "strain") |>
  mutate(corrected_value = value - baseline)
# A tibble: 8 × 6
  medium  time baseline strain value corrected_value
  <chr>  <dbl>    <dbl> <chr>  <dbl>           <dbl>
1 RPMI       1      0.2 ecoli    0.3             0.1
2 RPMI       1      0.2 staph    0.3             0.1
3 DMEM       1      0.1 ecoli    0.4             0.3
4 DMEM       1      0.1 staph    0.4             0.3
5 RPMI       2      0.1 ecoli    0.9             0.8
6 RPMI       2      0.1 staph    0.8             0.7
7 DMEM       2      0.2 ecoli    0.7             0.5
8 DMEM       2      0.2 staph    0.8             0.6
© www.soinside.com 2019 - 2024. All rights reserved.