是否可以 unlist() 嵌套数据框,同时保留 data.frame 中的其他列?

Posted

技术标签:

【中文标题】是否可以 unlist() 嵌套数据框,同时保留 data.frame 中的其他列?【英文标题】:Is it possible to unlist() listed data.frame while keeping other columns from data.frame? 【发布时间】:2019-06-10 18:59:08 【问题描述】:

我有一个从其他函数创建的 data.frame,它采用 .xlsx 文件列表并读取所有工作簿和包含的工作表。

结果是一个很好的数据框:

df<-data.frame(
file.name <-c(“C:/R/Folder1/WB1.xlsx”,
“C:/R/Folder1/WB2.xlsx,”,”C:/R/Folder1/WB2.xlsx”, “C:/R/Folder2/WB1.xlsx”, “C:/R/Folder2/WB1.xls”),
data<-list(df1,df2,df3,df4,df5))

虽然我能够检索(取消嵌套)数据帧,但我丢失了我需要的相应文件位置。

有没有办法在取消嵌套时保留数据框中的相应行并将 paste() 作为一列?

*抱歉有错别字。发布在 SO 应用上。

更新(现在我在电脑前)

可重现的例子:

数据:

df1<-data.frame(V1=c(sample(900:970,6)),
                V2=c(sample(LETTERS[1:6],6)))

df2<-data.frame(V1=sample(750:780,6),
                V2=sample(LETTERS[8:16],6))

df3<-data.frame(V1=sample(200:250,6),
                V2=sample(LETTERS[10:20],6),
                V3=sample(2300:5821,6))

df4<-data.frame(V1=sample(396:480,6),
                V2=sample(LETTERS,6))

df5<-data.frame(V1=sample(50:100,6),
                V2=sample(LETTERS,6))

df6<-data.frame(V1=sample(200:250,6),
                V2=sample(LETTERS,6),
                V3=sample(letters,6))

my.list <- list(df1,df2,df3,df4,df5,df6)

mydf<-data.frame(
  files=c("C:/Folder1/Data/File1.xlsx","C:/Folder1/Data/File2.xlsx",
          "C:/Folder1/Data/File3.xlsx","C:/Folder2/Data/File1.xlsx",
          "C:/Folder2/Data/File2.xlsx","C:/Folder2/Data/File3.xlsx"))

mydf$data<-my.list

尝试取消嵌套时 - 我遇到了以下问题(由于 data.frames 列表(第 2 列)中的观察值和变量存在差异:

y<-unnest(mydf, data)
Error: Column `V3` can't be converted from integer to factor
In addition: Warning messages:
1: In bind_rows_(x, .id) : Unequal factor levels: coercing to character
2: In bind_rows_(x, .id) :
  binding character and factor vector, coercing into character vector
3: In bind_rows_(x, .id) :
  binding character and factor vector, coercing into character vector...

其他函数的结果

#tidyverse
y<-mydf %>% unnest(data)
Error: Column `V3` can't be converted from integer to factor
In addition: Warning messages:
1: In bind_rows_(x, .id) : Unequal factor levels: coercing to character

y<-mydf %>%
+   unnest(data) %>%
+   group_by(files) %>%
+   mutate(
+     data = flatten_chr(data),
+     data_colname = str_c("data_", row_number())
+   ) %>% # or just as.character
+   spread(data_colname, data)
Error: Column `V3` can't be converted from integer to factor
In addition: Warning messages:
1: In bind_rows_(x, .id) : Unequal factor levels: coercing to character

添加利用函数来拉入 .xlsx 和所有工作表 - 如 example 所示:

library(tidyverse)
library(readxl)

dir_path1 <- "~/File1/Data/Qtr1"  
dir_path2 <- "~/File1/Data/Qtr2"         
dir_path3 <- "~/File1/Data/Qtr3"  
dir_path4 <- "~/File1/Data/Qtr4"

re_file <- ".xlsx"     

read_sheets <- function(dir_path1, file)
  xlsx_file <- paste0(dir_path1, file)
  xlsx_file %>%
    excel_sheets() %>%
    set_names() %>%
    map_df(read_excel, path = xlsx_file, .id = 'sheet_name') %>% 
    mutate(file_name = file) %>% 
    select(file_name, sheet_name, everything())


df <- list.files(dir_path, re_file) %>% 
  map_df(~ read_sheets(dir_path, .))

返回:

# A tibble: 15 x 5
   file_name  sheet_name  col1  
   <chr>      <chr>      <dbl> 
 1 Q1_File1.xlsx Sheet1    1         
 2 Q1_File1.xlsx Sheet2    1         
 3 Q1_File2.xlsx Sheet1    1          
 ...

但是,与示例数据不同(如链接所示),返回的数据 (col1) 是数据帧列表。

【问题讨论】:

也许可以看到 tidyr 包中的 unnest 函数(见例子tidyr.tidyverse.org/reference/unnest.html 【参考方案1】:

此问题与 df3 的数字为 V3 而 df6 是 V3 的字符有关。你可以:

    跳过导入df3$V3df6$V3 重命名这些变量之一

此外,要消除警告,您可以使用 stringsAsFactors = FALSE 创建 data.frames,或者您可以使用 tibble() 而不是 data.frame(),因为这是 tibble 的默认行为。

编辑: 为了更好地执行选项 2,您可以使用下面的代码为每个变量添加前缀。

my.list2 <- lapply(my.list, function(x) sapply(x, function(y) paste0(class(y), names(y))))
       , function(x) 
         
         x%>%
           rename_if(is.numeric, ~paste0('num', .x))%>%
           rename_if(is.character, ~paste0('char', .x))%>%
           rename_if(is.factor, ~paste0('fact', .x))
         
       )

这是选项 2,它仅适用于因素警告:

df1<-data.frame(V1=c(sample(900:970,6)),
                V2=c(sample(LETTERS[1:6],6)))

df2<-data.frame(V1=sample(750:780,6),
                V2=sample(LETTERS[8:16],6))

df3<-data.frame(V1=sample(200:250,6),
                V2=sample(LETTERS[10:20],6),
                V4=sample(2300:5821,6)) #used to be V3

df4<-data.frame(V1=sample(396:480,6),
                V2=sample(LETTERS,6))

df5<-data.frame(V1=sample(50:100,6),
                V2=sample(LETTERS,6))

df6<-data.frame(V1=sample(200:250,6),
                V2=sample(LETTERS,6),
                V3=sample(letters,6))

my.list <- list(df1,df2,df3,df4,df5,df6)

mydf<-data.frame(
  files=c("C:/Folder1/Data/File1.xlsx","C:/Folder1/Data/File2.xlsx",
          "C:/Folder1/Data/File3.xlsx","C:/Folder2/Data/File1.xlsx",
          "C:/Folder2/Data/File2.xlsx","C:/Folder2/Data/File3.xlsx"))

mydf$data<-my.list

unnest(mydf, data)

                        files  V1 V2   V4   V3
1  C:/Folder1/Data/File1.xlsx 951  A   NA <NA>
2  C:/Folder1/Data/File1.xlsx 932  F   NA <NA>
3  C:/Folder1/Data/File1.xlsx 908  B   NA <NA>
4  C:/Folder1/Data/File1.xlsx 953  C   NA <NA>
5  C:/Folder1/Data/File1.xlsx 929  E   NA <NA>
6  C:/Folder1/Data/File1.xlsx 928  D   NA <NA>
7  C:/Folder1/Data/File2.xlsx 778  K   NA <NA>
8  C:/Folder1/Data/File2.xlsx 771  H   NA <NA>
9  C:/Folder1/Data/File2.xlsx 757  M   NA <NA>
10 C:/Folder1/Data/File2.xlsx 773  P   NA <NA>
11 C:/Folder1/Data/File2.xlsx 759  N   NA <NA>
12 C:/Folder1/Data/File2.xlsx 765  O   NA <NA>
13 C:/Folder1/Data/File3.xlsx 236  M 3964 <NA>
14 C:/Folder1/Data/File3.xlsx 214  O 5241 <NA>
...truncated

【讨论】:

嗯,这里的问题是正在读入 .xlsx 文件 - 我的意思是,很多。有些有 50 个,有些有 300 个。它们的列名也相同。知道如何克服这个问题吗?我将粘贴用于读取文件的示例函数- 这可能是一个不同的问题。但是您不能导入带有标题的电子表格吗?否则,你怎么能真正提到路上的田野? 见评论。如果您想更好地回答基于类重命名变量的部分,您仍然应该问一个不同的问题 嘿@Co​​le。我有一个解决方案——我相信。我会把它贴在这里以防万一有人遇到同样的问题,

以上是关于是否可以 unlist() 嵌套数据框,同时保留 data.frame 中的其他列?的主要内容,如果未能解决你的问题,请参考以下文章

scala中的“unlist”(例如展平一系列序列的序列......)

使用R语言将不同长度的向量合并为数据框

在 R 中,通过在嵌套列表中用 NA 替换 NULL 来防止 unlist 删除 NULL 值

如何更有效地将嵌套列表扁平化为一个列表而不是使用 unlist 方法?

R:重新列出平面列表

在一列上汇总数据框,同时保留其他列