【问题标题】:New column based on pattern in column names基于列名中的模式的新列
【发布时间】:2014-04-16 23:36:49
【问题描述】:

我有一个数据表。我想创建一个新列,该列等于那些列中的值的函数,列名中有一个模式

library(data.table)
library(dplyr)

set.seed(1)
DT <- data.table(Client = LETTERS[1:5], 
   Apple_2012 = rpois(5,5),  Apple_2013 = rpois(5,5), Pear_2012 = rpois(5,5), 
   Pear_2013 = rpois(5,5), Orange_2012 = rpois(5,5), Orange_2013 = rpois(5,5))

例如,我想

DT <- DT[ ,Fruit_2012 := Apple_2012 + Pear_2012 + Orange_2012]

但我想通过识别“2012”模式来做到这一点。像这样的:

DT <- DT[ ,Fruit_2012 := sum(names(DT)[grep("2012", names(DT))]) ]

或者

DT <- DT %.%
  mutate(Fruit_2012 = sum(names(DT)[grep("2012", names(DT))]) )

但是这些方法都没有任何结果。

# Error in sum(names(DT)[grep("2012", names(DT))]) : 
#  invalid 'type' (character) of argument

我尝试过使用listquotewith=FALSE 的组合,但没有更多的运气。

【问题讨论】:

  • 也许:DT[, Fruit_2012 := rowSums(.SD), .SDcols=grep("2012$", names(DT))]?
  • 非常适合sum。但想使用一个可以接受向量参数的通用函数(如max)。我应该使用apply(.SD, 1, FUN) 吗?它有效,但有更惯用的解决方案吗?

标签: r regex dplyr data.table


【解决方案1】:
set.seed(1)
df <- data.frame(
  Client = LETTERS[1:5], 
  Apple_2012 = rpois(5,5),
  Apple_2013 = rpois(5,5), 
  Pear_2012 = rpois(5,5), 
  Pear_2013 = rpois(5,5), 
  Orange_2012 = rpois(5,5), 
  Orange_2013 = rpois(5,5)
)

鉴于此数据,我强烈建议您将其转换为 tidy form,因为它包含 变量保持一致:

library(reshape2)

dfm <- melt(df, id = "Client")

variables <- colsplit(dfm$variable, "_", c("fruit", "year"))
dfm$variable <- NULL
dfm$fruit <- variables$fruit
dfm$year <- as.numeric(variables$year)

head(dfm)
#>   Client value fruit year
#> 1      A     4 Apple 2012
#> 2      B     4 Apple 2012
#> 3      C     5 Apple 2012
#> 4      D     8 Apple 2012
#> 5      E     3 Apple 2012
#> 6      A     8 Apple 2013

然后很容易用 dplyr 或其他方式总结您想要的方式:

library(dplyr)

dfm %.% group_by(Client, year) %.% summarise(fruit = mean(value))
#> Source: local data frame [10 x 3]
#> Groups: Client
#> 
#>    Client year fruit
#> 1       A 2012 5.333
#> 2       A 2013 5.667
#> 3       B 2012 3.333
#> 4       B 2013 5.333
#> 5       C 2012 5.667
#> 6       C 2013 7.000
#> 7       D 2012 5.000
#> 8       D 2013 6.000
#> 9       E 2012 4.667
#> 10      E 2013 4.333

【讨论】:

  • +1 我很欣赏在我使用的特定情况下这是一个 XY 问题,但我仍然对一般问题的解决方案感到好奇。
【解决方案2】:

在这些情况下,我通常使用Reduce

DT[, Fruit_2012 := Reduce('+', .SD), .SDcols = grep("2012", names(DT))]

#or
DT[, Fruit_2012_max := Reduce(pmax, .SD), .SDcols = grep("2012", names(DT))]

【讨论】:

    【解决方案3】:

    尝试包含在选择函数中。

     mutate(DT,fruits2012 = rowSums(DT %.% select(contains("2012"))))
    

    有点丑。但它有效。

    我希望 dplyr 包中有一个 .SD。如果是这样,代码将是这样的:

    DT %.%
          select(contains("2012")) %.%
          mutate(fruits2012 = rowSums(.SD))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-12
      • 1970-01-01
      • 2017-10-24
      • 1970-01-01
      • 1970-01-01
      • 2020-12-10
      • 2020-09-14
      • 1970-01-01
      相关资源
      最近更新 更多