【问题标题】:How in R, can you create new columns using existing columns as variables?在 R 中,如何使用现有列作为变量创建新列?
【发布时间】:2020-09-21 12:41:01
【问题描述】:

我是 R 新手,因此非常感谢您对任何代码的更多解释,以帮助解决我的问题。

我有一个 data.frame,其中包含彼此相关的列组,我想对这些组中的每一个执行计算以获取新的输出列。例如,在实验中的许多生物学重复,我想在折叠它们之前独立地对每个重复进行计算。

我知道我可以在 dplyr 中使用 mutate 来创建新列,但我不确定如何在循环中执行此操作或如何使用 lapply 类型策略来避免每次重新绑定列名。我最大的问题是了解如何将列名转换为这些策略之一可用的东西。

例如:

> A.1 <- c(11,12,13,4,15,6,17,18)
> A.2 <- c(2,4,5,5,19,7,5,1)
> 
> B.1 <- c (3,4,5,1,31,76,13,70)
> B.2 <- c (10,9,8,15,31,12,13,12)
> 
> C.1 <- c(1,2,3,4,5,6,7,8)
> C.2 <- c(2,4,5,8,10,12,15,18)
> 
> df <- data.frame(A.1, A.2, B.1, B.2, C.1, C.2)
>
> df 
A.1 A.2 B.1 B.2 C.1 C.2
1  11   2   3  10   1   2
2  12   4   4   9   2   4
3  13   5   5   8   3   5
4   4   5   1  15   4   8
5  15  19  31  31   5  10
6   6   7  76  12   6  12
7  17   5  13  13   7  15
8  18   1  70  12   8  18
> 

我想在 A.new = A.1/A.2、B.new = B.1/B.2 等处创建新列,而无需明确输入每个列名。另请注意,“A”和“B”实际上是字符串,因此将它们全部输入会非常麻烦且耗时。

类似这样,但对于许多列组来说是一般情况:

> df <- df %>% mutate(A.new = A.1/A.2)
> df <- df %>% mutate(B.new = B.1/B.2)
> df <- df %>% mutate(C.new = C.1/C.2)
> 
> df
 A.1 A.2 B.1 B.2 C.1 C.2      A.new      B.new     C.new
1  11   2   3  10   1   2  5.5000000 0.30000000 0.5000000
2  12   4   4   9   2   4  3.0000000 0.44444444 0.5000000
3  13   5   5   8   3   5  2.6000000 0.62500000 0.6000000
4   4   5   1  15   4   8  0.8000000 0.06666667 0.5000000
5  15  19  31  31   5  10  0.7894737 1.00000000 0.5000000
6   6   7  76  12   6  12  0.8571429 6.33333333 0.5000000
7  17   5  13  13   7  15  3.4000000 1.00000000 0.4666667
8  18   1  70  12   8  18 18.0000000 5.83333333 0.4444444
> 

我还没有在这里看到我的问题的答案,但如果您能指出我现有的答案,将不胜感激!我目前正在考虑将列名包含在变量中,但也许这不是解决这个问题的正确方法(R 也是我正在学习的第一种编程语言),所以我对答案的搜索还没有产生太多结果。

提前感谢您的指导!

【问题讨论】:

标签: r loops dataframe dplyr lapply


【解决方案1】:

正如@A 所提到的。 S.K. 如果你有长格式的数据,计算起来会更容易。

我们可以使用pivot_longer 获取长格式数据,并为每个row 将第一个值除以该组列的第二个值。

library(dplyr)

df %>%
  mutate(row = row_number()) %>%
  tidyr::pivot_longer(cols = -row, 
                      names_to = c('.value', 'group'), 
                      names_sep = '\\.') %>%
   group_by(row) %>%
   summarise(across(A:C, list(new = ~.[1]/.[2]))) %>%
   #If you have an older version of dplyr use
   #summarise_at(vars(A:C), list(new = ~.[1]/.[2])) %>%
   select(-row) %>%
   bind_cols(df, .)


#  A.1 A.2 B.1 B.2 C.1 C.2  A_new  B_new C_new
#1  11   2   3  10   1   2  5.500 0.3000 0.500
#2  12   4   4   9   2   4  3.000 0.4444 0.500
#3  13   5   5   8   3   5  2.600 0.6250 0.600
#4   4   5   1  15   4   8  0.800 0.0667 0.500
#5  15  19  31  31   5  10  0.789 1.0000 0.500
#6   6   7  76  12   6  12  0.857 6.3333 0.500
#7  17   5  13  13   7  15  3.400 1.0000 0.467
#8  18   1  70  12   8  18 18.000 5.8333 0.444

您可以在summarise 步骤中使用A:C 指定列名范围。另外请注意,在pivot_longer 步骤中,names_sep 参数用于区分列组。由于您的列名称为A.1,A.2 我使用'.' 作为分隔符,您可能需要根据您拥有的列名称进行更改。

【讨论】:

    【解决方案2】:

    使用split.default,我们可以更轻松地做到这一点

    lst1 <- lapply(split.default(df, sub("\\.\\d+$", "", names(df))), 
            function(x) x[[1]]/x[[2]])
    df[paste0(names(lst1), ".new")] <- lst1
    df
    #  A.1 A.2 B.1 B.2 C.1 C.2      A.new      B.new     C.new
    #1  11   2   3  10   1   2  5.5000000 0.30000000 0.5000000
    #2  12   4   4   9   2   4  3.0000000 0.44444444 0.5000000
    #3  13   5   5   8   3   5  2.6000000 0.62500000 0.6000000
    #4   4   5   1  15   4   8  0.8000000 0.06666667 0.5000000
    #5  15  19  31  31   5  10  0.7894737 1.00000000 0.5000000
    #6   6   7  76  12   6  12  0.8571429 6.33333333 0.5000000
    #7  17   5  13  13   7  15  3.4000000 1.00000000 0.4666667
    #8  18   1  70  12   8  18 18.0000000 5.83333333 0.4444444
    

    注意:我们不需要任何包,可以很容易地完成

    数据

    df <- structure(list(A.1 = c(11, 12, 13, 4, 15, 6, 17, 18), A.2 = c(2, 
    4, 5, 5, 19, 7, 5, 1), B.1 = c(3, 4, 5, 1, 31, 76, 13, 70), B.2 = c(10, 
    9, 8, 15, 31, 12, 13, 12), C.1 = c(1, 2, 3, 4, 5, 6, 7, 8), C.2 = c(2, 
    4, 5, 8, 10, 12, 15, 18)), class = "data.frame", row.names = c(NA, 
    -8L))
    

    【讨论】:

    • 感谢您的回复。我尝试运行代码并收到此错误: .subset2(x, i, exact = exact) 中的错误:下标超出范围。
    • @Sarah 它是否基于与我工作正常的相同示例
    • 你知道这是否需要我可能没有安装的任何特定包吗?
    • @Sarah 不,只是base R。我只是复制/粘贴你的输入数据来测试这个
    • @Sarah 更新了我用作输入的数据结构
    猜你喜欢
    • 1970-01-01
    • 2021-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-15
    • 2022-07-01
    • 1970-01-01
    相关资源
    最近更新 更多