工作簿上的R函数跳过空白单元格

fkaflof6  于 2023-09-27  发布在  其他
关注(0)|答案(1)|浏览(80)

我试图写一个函数,编辑通过loadWorkbook导入的工作簿,有一个问题,空白单元格被忽略,而不是作为NA处理。下面的代码演示了这个问题。

df <- data.frame(x = c(1, 2, 3, 4, NA, 6), y = c(7, 8, 9, 10, NA, 12))
xlsx::write.xlsx(df, file = 'testdf.xlsx', showNA = FALSE, row.names = FALSE)
testwb <- loadWorkbook(file = 'testdf.xlsx')

sheetnames <- c('Sheet1')
sheets <- lapply(sheetnames, function(name) getSheets(testwb)[[name]])
rows <- getRows(sheets[[1]], rowIndex=1:7)
cells <- getCells(rows, colIndex=1:2)
values <- sapply(unlist(cells), getCellValue)
values
length(values)

当我运行它时,我得到了我所期望的,包括NA:
1.1 1.2 2.1 2.2 3.1 3.2 4.1 4.2 5.1 5.2 6.2 7.1 7.2
“x”“y”“1”“7”“2”“8”“3”“9”“4”“10”NA NA“6”“12”
但是,如果我打开excel文件并手动删除第一行数据,然后再次运行它,我会得到这样的结果:
1.1 1.2 3.1 3.2 4.1 4.2 5.1 5.2 7.1 7.2
“x”“y”“2”“8”“3”“9”“4”“10”“6”“12”
这给我带来了问题,因为当在两个工作表之间进行比较时,如果一个工作表的空白单元格比另一个工作表的空白单元格多,那么它们最终会得到不同数量的值。如何强制它包含NA值?
我尝试手动重建工作簿的副本,以便可以像这样在writeData中使用keepNA参数:

testwb2 <- openxlsx::createWorkbook()
addWorksheet(testwb2, 'Sheet1')
writeData(testwb2, 'Sheet1', read_xlsx('testdf.xlsx', sheet = 1), keepNA = TRUE)

sheetnames <- c('Sheet1')
sheets <- lapply(sheetnames, function(name) getSheets(testwb2)[[name]])
rows <- getRows(sheets[[1]], rowIndex=1:7)
cells <- getCells(rows, colIndex=1:2)
values <- sapply(unlist(cells), getCellValue)
values
length(values)

但是我得到了错误
envRefInferField(x,what,getClass(class(x)),selfEnv)中的错误:“getNumberOfSheets”不是引用类“Workbook”的有效字段或方法名称
我也不明白有没有一个简单的方法来处理这个问题?

11dmarpk

11dmarpk1#

这个问题有点令人困惑,但这个问题可能已经被回答了几次。我认为现在的情况是这样的:当你删除第一行时,你的电子表格软件会进行某种清理,并从数据中删除空行(它不再是你编写的xlsx文件中xml结构的一部分),xlsx包只返回它在工作簿中可以读取的单元格。
我已经尝试修复openxlsx的类似问题,因此我假设xlsx的行为类似。
下面我创建了一个文件,它的行为与您描述的问题一样,显示openxlsx也表现得很淘气,但还有其他表现得很好的包。

df <- data.frame(
  x = c(1, 2, 3, 4, NA, 6),
  y = c(7, 8, 9, 10, NA, 12)
)

tmp <- openxlsx2::temp_xlsx()
openxlsx2::wb_workbook()$
  add_worksheet("Sheet1")$
  add_data(x = df[2:4,], dims = "A1:B4")$
  add_data(x = df[6,], dims = "A6:B6", col_names = FALSE)$
  save(tmp)

testwb <- xlsx::loadWorkbook(file = tmp)

sheetnames <- c('Sheet1')
sheets <- lapply(sheetnames, function(name) xlsx::getSheets(testwb)[[name]])
rows   <- xlsx::getRows(sheets[[1]], rowIndex=1:7)
cells  <- xlsx::getCells(rows, colIndex=1:2)
values <- sapply(unlist(cells), xlsx::getCellValue)
values
#>  1.1  1.2  2.1  2.2  3.1  3.2  4.1  4.2  6.1  6.2 
#>  "x"  "y"  "2"  "8"  "3"  "9"  "4" "10"  "6" "12"
length(values)
#> [1] 10

# naughty
openxlsx::read.xlsx(tmp)
#>   x  y
#> 1 2  8
#> 2 3  9
#> 3 4 10
#> 4 6 12

# nice
readxl::read_xlsx(tmp)
#> # A tibble: 5 × 2
#>       x     y
#>   <dbl> <dbl>
#> 1     2     8
#> 2     3     9
#> 3     4    10
#> 4    NA    NA
#> 5     6    12

# nice
openxlsx2::read_xlsx(tmp)
#>    x  y
#> 2  2  8
#> 3  3  9
#> 4  4 10
#> 5 NA NA
#> 6  6 12

相关问题