【问题标题】:Create a new column a fill with values from a set of multiple columns conditional on column names根据列名创建一个新列,填充来自一组多列的值
【发布时间】:2022-01-26 17:51:38
【问题描述】:

我有这个数据框:

df <- df <- structure(list(A01 = c(0L, 0L, 2L, 0L, 4L, 1L, 10L, 10L), A02 = c(0L, 
-1L, 0L, 1L, 4L, 4L, 9L, 12L), A03 = c(-5L, -4L, 2L, -4L, 3L, 
2L, 8L, 12L), A04 = c(-1L, -3L, 3L, 1L, 3L, -3L, 9L, 12L), A05 = c(-1L, 
-3L, 1L, -1L, 3L, 0L, 7L, 10L), A06 = c(2L, -3L, 3L, 1L, 4L, 
0L, 7L, 12L), A07 = c(3L, -3L, 3L, 1L, 4L, 0L, 7L, 9L), X = c(2L, 
2L, 6L, 7L, 12L, 15L, 22L, 24L)), class = "data.frame", row.names = c(NA, 
-8L))

  A01 A02 A03 A04 A05 A06 A07  X
1   0   0  -5  -1  -1   2   3  2
2   0  -1  -4  -3  -3  -3  -3  2
3   2   0   2   3   1   3   3  6
4   0   1  -4   1  -1   1   1  7
5   4   4   3   3   3   4   4 12
6   1   4   2  -3   0   0   0 15
7  10   9   8   9   7   7   7 22
8  10  12  12  12  10  12   9 24

我想应用此代码: 来自我以前的问题Mutate a new column and paste value from existing columns conditional on string in column names

library(dplyr)
library(stringr)
df %>% 
  rowwise %>%
  mutate(new_col = get(str_c('A0', X))) %>%
  ungroup

我收到错误:

Error: Problem with `mutate()` column `new_col`.
i `new_col = get(str_c("A0", X))`.
x object 'A012' not found
i The error occurred in row 5.
Run `rlang::last_error()` to see where the error occurred.

而且我知道原因:原因是代码尝试获取A012 列,因为X 列= 12 中的第5 行。但是没有列A012

Desired_output:

   A01 A02 A03 A04 A05 A06 A07  X new_col
1   0   0  -5  -1  -1   2   3  2    0
2   0  -1  -4  -3  -3  -3  -3  2    -1
3   2   0   2   3   1   3   3  6    3
4   0   1  -4   1  -1   1   1  7    1
5   4   4   3   3   3   4   4 12    NA
6   1   4   2  -3   0   0   0 15    NA
7  10   9   8   9   7   7   7 22    NA
8  10  12  12  12  10  12   9 24    NA

【问题讨论】:

  • 您是否总是希望列中包含“0”,或者您是否想将这些数字视为用零填充到某个宽度?比如说你确实有一列与 X = 12 行匹配。那是 A12 还是 A012?
  • 非常好的问题。确实,这作为问题出现了。但是对于这个问题,colnames 是原样的! stackoverflow.com/questions/70503223/…>

标签: r dataframe dplyr


【解决方案1】:

通过if 条件可以实现您想要的结果:

library(dplyr)
library(stringr)
df %>% 
  rowwise() %>%
  mutate(new_col = if (str_c('A0', X) %in% names(.)) get(str_c('A0', X)) else NA) %>%
  ungroup()
#> # A tibble: 8 × 9
#>     A01   A02   A03   A04   A05   A06   A07     X new_col
#>   <int> <int> <int> <int> <int> <int> <int> <int>   <int>
#> 1     0     0    -5    -1    -1     2     3     2       0
#> 2     0    -1    -4    -3    -3    -3    -3     2      -1
#> 3     2     0     2     3     1     3     3     6       3
#> 4     0     1    -4     1    -1     1     1     7       1
#> 5     4     4     3     3     3     4     4    12      NA
#> 6     1     4     2    -3     0     0     0    15      NA
#> 7    10     9     8     9     7     7     7    22      NA
#> 8    10    12    12    12    10    12     9    24      NA

【讨论】:

    【解决方案2】:

    您可以尝试以下基本 R 代码

    transform(
      df,
      new_col = df[cbind(seq_along(X), match(paste0("A0", X), names(df)))]
    )
    

    给了

      A01 A02 A03 A04 A05 A06 A07  X new_col
    1   0   0  -5  -1  -1   2   3  2       0
    2   0  -1  -4  -3  -3  -3  -3  2      -1
    3   2   0   2   3   1   3   3  6       3
    4   0   1  -4   1  -1   1   1  7       1
    5   4   4   3   3   3   4   4 12      NA
    6   1   4   2  -3   0   0   0 15      NA
    7  10   9   8   9   7   7   7 22      NA
    8  10  12  12  12  10  12   9 24      NA
    

    dplyr 版本可能是这个样子(抱歉我不是dplyr 大师,肯定有比这更优雅的表示)

    > df %>%
    +   mutate(new_col = .[cbind(seq_along(X), match(paste0("A0", X), names(.)))])
      A01 A02 A03 A04 A05 A06 A07  X new_col
    1   0   0  -5  -1  -1   2   3  2       0
    2   0  -1  -4  -3  -3  -3  -3  2      -1
    3   2   0   2   3   1   3   3  6       3
    4   0   1  -4   1  -1   1   1  7       1
    5   4   4   3   3   3   4   4 12      NA
    6   1   4   2  -3   0   0   0 15      NA
    7  10   9   8   9   7   7   7 22      NA
    8  10  12  12  12  10  12   9 24      NA
    

    【讨论】:

      【解决方案3】:

      您可以使用purrr::imap_dbl 迭代向量df$X 及其索引,创建新列名,在给定索引处提取该列的值,并返回一个双精度值。如果没有匹配,NULL 将被替换为双类型NA。中缀运算符%||%来自rlang,由purrr导出;文档说它基于 Ruby 中的 OR 运算符,尽管我熟悉 Javascript 中的类似内容。

      library(purrr)
      
      df$new_col <- imap_dbl(df$X, 
                             function(val, i) df[i, sprintf("A%02d", val)] %||% NA_real_)
      df
      #>   A01 A02 A03 A04 A05 A06 A07  X new_col
      #> 1   0   0  -5  -1  -1   2   3  2       0
      #> 2   0  -1  -4  -3  -3  -3  -3  2      -1
      #> 3   2   0   2   3   1   3   3  6       3
      #> 4   0   1  -4   1  -1   1   1  7       1
      #> 5   4   4   3   3   3   4   4 12      NA
      #> 6   1   4   2  -3   0   0   0 15      NA
      #> 7  10   9   8   9   7   7   7 22      NA
      #> 8  10  12  12  12  10  12   9 24      NA
      

      我假设列名中的数字被零填充到宽度为 2,但如果将 "A0" 粘贴到每个数字实际上是正确的,请改为这样做。

      【讨论】:

        猜你喜欢
        • 2017-10-12
        • 1970-01-01
        • 2022-12-18
        • 1970-01-01
        • 1970-01-01
        • 2018-11-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-14
        相关资源
        最近更新 更多