【问题标题】:R: How do you subset all data-frames within a list?R:你如何对列表中的所有数据框进行子集化?
【发布时间】:2018-02-25 23:33:32
【问题描述】:

我有一个名为WaFramesCosts 的数据框列表。我想简单地对其进行子集化以显示特定的列,以便我可以导出它们。我试过了:

    for (i in names(WaFramesCosts)) {
      WaFramesCosts[[i]][,c("Cost_Center","Domestic_Anytime_Min_Used","Department",
"Domestic_Anytime_Min_Used")]

    }

但它返回错误

Error in `[.data.frame`(WaFramesCosts[[i]], , c("Cost_Center", "Department",  : 
  undefined columns selected

我也试过了:

for (i in seq_along(WaFramesCosts)){
WaFramesCosts[[i]][ , -which(names(WaFramesCosts[[i]]) %in% c("Cost_Center","Domestic_Anytime_Min_Used","Department",
    "Domestic_Anytime_Min_Used"))]

但我得到了同样的错误。谁能看到我做错了什么?

旁注:作为参考,我使用了这个:

for (i in seq_along(WaFramesCosts)) {
    t <- WaFramesCosts[[i]][ , grepl( "Domestic" , names( WaFramesCosts[[i]] ) )] 
    q <- subset(WaFramesCosts[[i]], select = c("Cost_Center","Domestic_Anytime_Min_Used","Department","Domestic_Anytime_Min_Used"))  

    WaFramesCosts[[i]] <- merge(q,t)
  }

虽然用不同的方法尝试相同的目标,但似乎更接近了。

【问题讨论】:

  • 请发布您的数据或至少一个可重复的示例
  • @Parfait 谢谢你的关注。我一直在努力解决这个问题,所以我不小心复制并粘贴了一个旧的命名约定。

标签: r subset col


【解决方案1】:

欢迎回来,Kootseeahknee。你still 错误地假设for 循环的最后一个命令在最后隐式返回。如果你想要这种行为,也许你想要lapply

myoutput <- lapply(names(WaFramesCosts)), function(i) {
  WaFramesCosts[[i]][,c("Cost_Center","Domestic_Anytime_Min_Used","Department","Domestic_Anytime_Min_Used")]
})

undefined columns selected 错误告诉我,您对数据集的假设不正确:至少有一列缺少至少一列。根据您之前的问题 (How to do a complex edit of columns of all data frames in a list?),我推断您想要匹配的列,而不是假设它在所有内容中。由此,您可以/应该使用grep 或一些变体:

myoutput <- lapply(names(WaFramesCosts)), function(i) {
  WaFramesCosts[[i]][,grep("(Cost_Center|Domestic_Anytime_Min_Used|Department)", 
                           colnames(WaFramesCosts)),drop=FALSE]
})

这将匹配包含任何这些字符串的列名。通过使用正则表达式确保发生整个字符串或开始/结束匹配,您可以更加精确。例如,从(Cost|Dom)(包含“Cost”或“Dom”的任何内容)更改为(^Cost|Dom) 意味着任何以“Cost”开头或包含“Dom ";同样,(Cost|ment$) 匹配任何包含“Cost”或ends 为“ment”的内容。但是,如果您总是想要完全匹配并且只需要那些存在的匹配项,那么这样的方法会起作用:

myoutput <- lapply(names(WaFramesCosts)), function(i) {
  WaFramesCosts[[i]][,intersect(c("Cost_Center","Domestic_Anytime_Min_Used","Department"),
                                colnames(WaFramesCosts)),drop=FALSE]
})

注意,在最后一个例子中:注意mtcars[,2](返回一个向量)和mtcars[,2,drop=FALSE](返回一个带有1列的data.frame)之间的区别。防御性编程,如果您认为过滤可能会返回单列,请确保不会通过将 ,drop=FALSE 附加到括号子集来无意中转换为 vector

【讨论】:

  • 哈,我又犯了这个错误。我应该暂时离开这个项目,因为我的脑海里浮现出所有这些概念。我为通宵道歉。我在尝试再次尝试实现目标的新方法时发布了这个问题。也感谢您的匹配帮助;这些列名很多,很杂乱,而且并不总是相同,因此有助于更轻松地找到它们。
【解决方案2】:

根据您的描述,这是使用库 dplyr 为给定的一组列组合数据框列表的示例。这并不要求所有数据框都具有相同的列(在可重现的示例中提供您的数据会更好)

# test data

df1 = read.table(text = "
c1 c2 c3
a 1 101
b 2 102
", header = TRUE, stringsAsFactors = FALSE)

df2 = read.table(text = "
c1 c2 c3
w 11 201
x 12 202
", header = TRUE, stringsAsFactors = FALSE)

# dfs is a list of data frames
dfs <- list(df1, df2)

# use dplyr::bind_rows
library(dplyr)

cols <- c("c1", "c3")
result <- bind_rows(dfs)[cols]

result

# c1  c3
# 1  a 101
# 2  b 102
# 3  w 201
# 4  x 202

【讨论】:

  • 为什么只为bind_rows 导入整个包? Base R 的do.call(rbind, dfs) 可以轻松工作。
  • 我同意这个小例子,@Parfait。在更广泛的工作中,无论如何我倾向于使用 dplyr bind_rows 据称是 do.call(rbind, dfs)" 通用模式的有效实现,并且它对列不匹配等更宽容,所以更容易使用.
  • @epi99 我会试试这个,谢谢!我一直试图避免它有几个原因,但似乎以这种方式结合这些可能是我想要的结果的唯一希望。
猜你喜欢
  • 1970-01-01
  • 2014-02-20
  • 1970-01-01
  • 2017-07-21
  • 2021-12-04
  • 2014-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多