【问题标题】:R: rbind a list of data.frames with different columns in different data framesR:rbind一个data.frames列表,在不同的数据帧中有不同的列
【发布时间】:2015-02-24 16:20:06
【问题描述】:

我有一个包含 11,383 个数据框的列表。我需要将它们合并到一个大数据框中,但是它们有不同的列(2,3,4 列),所以当我使用 Dplyr 的 rbind_all 时,我得到了不想要的结果。

一种方法是 rbind 具有相同列数的数据帧(具有不同的标题,但我不介意它们)。由于我有 2,3 和 4 列的数据框,根据列表中每个数据框的列数,它将产生 3 个大数据框。

预期输出:

4列数据框:

SKU             Tv y Video  Tecnología  Deportes
2003091070002P  Tv y Video  Tecnología  Deportes
2.00E+12        Tv y Video  Tecnología  Deportes
2003120060008P  Tv y Video  Tecnología  Deportes
2004121460080P  Cómputo     Tecnología  Decohogar
2.00G+12        Cómputo     Tecnología  Decohogar
2004121440802P  Cómputo     Tecnología  Decohogar
2.00A+12        Cómputo     Tecnología  Decohogar

两列数据框:

            SKU         PROMOCIONES
1   110 2089060010006P  PROMOCIONES
2   111 2089660010006P  PROMOCIONES
#

这是我的代码:

df_2col <- data.frame()  #Starts Data frame for dfs with 2 columns

df_3col <- data.frame()  #Starts Data frame for dfs with 3 columns

df_4col <- data.frame()  #Starts Data frame for dfs with 4 columns


lapply(my_list, function(i){
    if (ncol(i) == 2)
        df_2col <- rbind(i)
    ifelse (ncol(i) == 3)
        df_3col <- rbind(i)
    ifelse (ncol(i) == 4)
        df_4col <- rbind(i)
})

但我得到这个错误:

Error in ifelse(ncol(i) == 3) : argument "no" is missing, with no default 

我的数据列表示例:

list(list(structure(list(SKU = "2079230130006P", Decohogar = "Decohogar", 
    Para.la.Mesa = "Para.la.Mesa", Copas.y.Vasos = "Copas.y.Vasos"), .Names = c("SKU", 
"Decohogar", "Para.la.Mesa", "Copas.y.Vasos"), class = "data.frame", row.names = 134L)), 
    list(structure(list(SKU = "2079240080001P", Decohogar = "Decohogar", 
        Para.la.Mesa = "Para.la.Mesa", Copas.y.Vasos = "Copas.y.Vasos"), .Names = c("SKU", 
    "Decohogar", "Para.la.Mesa", "Copas.y.Vasos"), class = "data.frame", row.names = 132L)), 
    list(structure(list(SKU = "2069060020005P", PROMOCIONES = "PROMOCIONES"), .Names = c("SKU", 
    "PROMOCIONES"), class = "data.frame", row.names = 111L)), 
    list(structure(list(SKU = "2047121452095P", Dormitorio = "Dormitorio", 
        Colchones = "Colchones", X2.plazas = "X2.plazas"), .Names = c("SKU", 
    "Dormitorio", "Colchones", "X2.plazas"), class = "data.frame", row.names = 223L)), 
    list(structure(list(SKU = "2069060010006P", PROMOCIONES = "PROMOCIONES"), .Names = c("SKU", 
    "PROMOCIONES"), class = "data.frame", row.names = 110L)), 
    list(structure(list(SKU = "2069060010006P", PROMOCIONES = "PROMOCIONES"), .Names = c("SKU", 
    "PROMOCIONES"), class = "data.frame", row.names = 109L)))

注意:当您知道列表中每个数据框的列数时,这将起作用。有没有办法做到这一点?我的意思是,如果将来有一个包含 5 列的数据框,则代码还应该为该数据框返回一个包含 5 列的大数据框。

【问题讨论】:

  • 它们是否有相交的列名?
  • @akrun,是的,有一个 commun 列:“SKU”,它是每个数据帧中的第一列。我已经放了一些数据,所以你可以看看它是如何的。谢谢。
  • 试试library(data.table);rbindlist(do.call(c, my_list), fill=TRUE)
  • 或者合并它们? Reduce(function(...) merge(..., all=T), my_list)
  • @akrun,使用 data.table 得到:Error in rbindlist(do.call(c, my_list), fill = TRUE) : Item 1 of list input is not a data.frame, data.table or list

标签: r lapply rbind


【解决方案1】:

我们可以展平列表元素do.call(c,..) 获取每个列表元素(“indx”)的列数(ncol),将其用于split 列表,rbindlist 结果元素。

library(data.table)
my_list1 <- do.call(`c`, my_list)
indx <- sapply(my_list1, ncol)
lst <- lapply(split(my_list1, indx), rbindlist)
lst
#$`2`
#              SKU PROMOCIONES
#1: 2069060020005P PROMOCIONES
#2: 2069060010006P PROMOCIONES
#3: 2069060010006P PROMOCIONES

#$`4`
#             SKU  Decohogar Para.la.Mesa Copas.y.Vasos
#1: 2089230130006P  Decohogar Para.la.Mesa Copas.y.Vasos
#2: 2089240080001P  Decohogar Para.la.Mesa Copas.y.Vasos
#3: 2047121452095P Dormitorio    Colchones     X2.plazas

如果我们需要获取单独的data.frame 对象(不推荐),请使用list2env

 list2env(setNames(lst, paste0('dat',seq_along(lst))), envir=.GlobalEnv)

更新

如果有 NULL 或 NA 值作为列表元素之一,我们可能会收到此错误

my_list1[[7]] <- NA
split(my_list1, sapply(my_list1, ncol))
#Error in split.default(my_list1, sapply(my_list1, ncol)) : 
 #group length is 0 but data length > 0

然后,我们可以检查元素是否为data.frame(“isDF”),子集列表并获取“ncol”,并像以前一样。

isDF <- sapply(my_list1, is.data.frame)
indx <- sapply(my_list1[isDF], ncol)
lapply(split(my_list1[isDF], indx), rbindlist)

【讨论】:

  • 知道了:Error in split.default(my_listfinal, indx) : group length is 0 but data length &gt; 0 它与提供的数据配合得很好,但可能列表中的某些数据框给我带来了麻烦。其中一些有 0 行...您能否为解决方案的每一行添加一些解释。谢谢。
  • @OmarGonzales 如果您可以发布一个小示例的 dput 会更好
  • 这次出现此错误:Error in args[[i]] : attempt to select less than one element,运行此行时:lst &lt;- lapply(split(my_list1[isDF], indx), rbindlist)
  • @OmarGonzales 它必须与 NULL 元素相关联。你的名单有多大?此外,在列表的一个非常小的子集中进行测试,如果错误仍然存​​在,请输入该子集
  • 我想,我应该清除我的对象(r​​m = list = ls())。我的代码没有问题,但收到此消息: Data.frame 中的错误(2 = list(SKU = c("2003120060006P", "2003120060006P", : arguments 暗示不同的行数: 3939、2563、4786、95```
【解决方案2】:

rbind_all 有一个填充函数,可以用 NA 替换空白数据。 当我第一次尝试使用 rbind 时出现错误,因为您提供的数据集是列表列表而不是数据框列表。我首先将嵌套列表转换为数据框,然后使用 rbind 创建单个数据框。

您的示例数据是“x”

sapply(x, class)
x2 <- lapply(x, as.data.frame)
x3 <- rbind_all(x2)

我不知道你是否正在制作一个整洁的数据框,但如果你是,你可以使用 tidyr 来帮助

library(tidyr)
x4 <- gather(x3, key=SKU, na.rm=TRUE)[,-2]

更新

这个问题现在已经解决了,但这是我对我的解决方案的更新,以列出各个类别的数据框

x5 <- lapply(unique(x4$value), function(n) filter(x4, value == n))

【讨论】:

    猜你喜欢
    • 2020-07-10
    • 2022-06-16
    • 2018-10-17
    • 2021-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    • 2015-04-18
    相关资源
    最近更新 更多