【问题标题】:How to read merged excel cells with R如何使用 R 读取合并的 Excel 单元格
【发布时间】:2016-05-29 12:24:45
【问题描述】:

我收到了数百张包含合并单元格的 Excel 表格。发件人坚持使用 Excel 和合并单元格——对此我无能为力。我如何使用 R 阅读这些内容?例如,输入表问题区域的简化版本可能如下所示,其中合并的单元格(B2、B3、C2、C3)包含单词“X”。合并单元格的数量及其在工作表中的位置(以及“X”的值)因工作表而异,并且同一工作表中可能有多个合并单元格。工作表实际上不是表格格式,它们包含其他空单元格。我已经成功地遍历了所有文件,清理了整个混乱,重塑了结果并获得了一个整洁的数据集(1 张而不是 736 个 Excel 工作簿)。问题是,到目前为止,我的解决方案忽略了合并单元格中的信息。

    A   B   C   D
1   a   f   i   l
2   b   X       m
3   c           n
4   d   g   j   o
5   e   h   k   p

如何将 Excel 工作表读入 R 中,使结果看起来像这样,带有单词“X”

    A   B   C   D
1   a   f   i   l
2   b   X   X   m
3   c   X   X   n
4   d   g   j   o
5   e   h   k   p

【问题讨论】:

  • 可能是this 会有所帮助
  • Excel VBA 最擅长处理 Excel 数据。您可以编写一个 VBA 宏来取消合并单元格、复制内容、将文件保存为 csv 文件、通过该宏运行文件,然后在 R 中打开它们。
  • 这项正在进行的工作与此处相关:github.com/rsheets/rexcel/blob/master/README.md
  • 如何确定合并区域是 B2:C3 而不是两个合并区域: B2:C2 和 A3:C3 ?这可能很难自动检测到。

标签: r excel


【解决方案1】:
library(openxlsx)

data <- read.xlsx(xlsxFile = "Your path", fillMergedCells = TRUE, colNames = FALSE)

fillMergedCells = TRUE

试试这个!

【讨论】:

  • 对我来说效果很好 - 我认为我的情况与 OP 类似,但不是多个文件。
【解决方案2】:

如果 VBA/R 混合适合您的目的,这里有一个 VBA 宏,它将取消合并工作表中的所有单元格,同时使用相应的值填充未合并区域中的所有单元格:

Sub UnMerge(ws As Worksheet)
    Dim R As Range, c As Range
    Dim v As Variant
    For Each c In ws.UsedRange
        If c.MergeCells Then
            v = c.Value
            Set R = c.MergeArea
            R.UnMerge
            R.Value = v
        End If
    Next c
End Sub

一个简单的测试来说明它是如何被调用的:

Sub test()
    UnMerge Sheets(1)
End Sub

UnMerged 可以用作更大程序的一部分,例如遍历文件夹中的所有 .xlsx 文件和文件中所有包含数据的工作表,将它们全部取消合并并将它们保存为 .csv 文件。

编辑时。本机 VBA 文件处理有点烦人。如果我需要遍历多个文件,我倾向于使用相关的脚本语言 VBScript。我不确定您的虚拟 Windows 是否可以处理 VBScript。我会这样认为,因为 VBScript 是 Windows 操作系统的标准部分。如果是这种情况,请查看以下是否有效(为了安全起见,在备份文件之后)。在包含要修改的 Excel 文件的文件夹中,将代码另存为带有 .vbs 扩展名的简单文本文件。然后,只需单击其图标。它将遍历包含脚本的目录中的所有.xlx.xlsx 文件,并在每个此类文件中取消合并表1。我没有对它进行广泛的测试,并且它不包含错误处理,但我确实在一个包含三个 Excel 文件的文件夹上对其进行了测试,每个 Excel 文件都包含多个合并区域,并且它在我的 Windows 机器上按预期运行。我不知道它是否可以在你的 Mac 上运行:

Option Explicit

Dim fso,fol,f,xl, wb, ws,ext,v,r,c

Set fso = WScript.CreateObject("Scripting.FileSystemObject")
Set xl = CreateObject("Excel.Application")
xl.DisplayAlerts = False
xl.ScreenUpdating = False
set fol = fso.GetFolder(fso.GetParentFolderName(WScript.ScriptFullName))

For Each f In fol.Files
    ext = LCase(fso.GetExtensionName(f.Name))
    If ext = "xls" Or ext = "xlsx" Then
        Set wb = xl.Workbooks.Open(f.Path)
        Set ws = wb.Sheets(1)
        For Each c In ws.UsedRange
            If c.MergeCells Then
                v = c.Value
                Set R = c.MergeArea
                R.UnMerge
                R.Value = v
            End If
        Next
        wb.Save
        wb.Close   
    End If
Next

【讨论】:

  • 我对 VBA 一点也不熟悉。如何遍历文件夹中的所有文件来执行此操作?
  • @DaveStumped 每个文件是否有 1 个工作表,或者某些文件是否有多个工作表?另外——你是在 Windows 机器上吗? (尽管存在 Mac 版本的 Excel,但在 Linux 甚至 Mac 之类的系统中处理 Excel 工作表更加困难)。
  • 目前,每个工作簿中有多个工作表。但是,至少到目前为止,每个工作簿中只有一张我感兴趣的工作表(幸运的是每个工作簿中都有相同的名称),并且我已经成功地将所有这些工作簿移到了每个工作簿中的工作表 1 中保存在磁盘上,所有这些都在同一个文件夹中。我正在使用 MAC,但我可以运行具有 Excel 2010(64 位)的虚拟 Windows 机器。
  • @DaveStumped 很高兴它有效。为了安全起见,我在脚本底部添加了xl.Quit。否则,脚本完成后,您可能会在后台运行一个 Excel 实例。
  • 我在这里为下一步创建了一个后续问题stackoverflow.com/questions/37512950/…
【解决方案3】:

此解决方案假定电子表格上只有一个合并区域,并且唯一的缺失值 (NA) 是由合并的单元格引起的。

代码:

library("openxlsx")
data = read.xlsx(xlsxFile = "Book1.xlsx", colNames = F)

cl = min(ceiling(which(is.na(data))/dim(data)[1]))
rw = min(which(is.na(data))%%dim(data)[1])

data[is.na(data)] = data[rw,cl]

示例:

从合并单元格的 Excel 中读取数据:

   X1   X2   X3   X4  X5
1   1    a    q    a  11
2   2    b    w    s  22
3   3    c    e    d  33
4   4    d <NA> <NA>  44
5   5 <NA> <NA> <NA>  55
6   6 <NA> <NA> <NA>  66
7   7    g    u    j  77
8   8    h    i    k  88
9   9    i    o    l  99
10 10    j    p    m 110

如您所见,“d”被合并到第 4 到 6 行和第 2 到 4 列。 唯一的 NA 是由于合并的单元格造成的。

从建议的代码中,clrw 找到合并值“d”的列和行。

最后一行查找所有 NA 并将它们替换为“d”。

结果:

   X1 X2 X3 X4  X5
1   1  a  q  a  11
2   2  b  w  s  22
3   3  c  e  d  33
4   4  d  d  d  44
5   5  d  d  d  55
6   6  d  d  d  66
7   7  g  u  j  77
8   8  h  i  k  88
9   9  i  o  l  99
10 10  j  p  m 110

注意: 如果您的 Excel 数据具有列名,则应删除 colnames = F

【讨论】:

  • 不幸的是,工作表在其他单元格中包含其他 NA。我已经编辑了我的原始问题以反映这一点。
【解决方案4】:

如果您只需用 X 填充空单元格,请将 Excell 中的数据导出为制表符分隔的文本文件,将它们作为字符 (as.is = TRUE) 导入R,然后用 X 替换空白。示例中的最后一行将所有字符列转换为 Roland's answer 的因子,便于分析。

tab <- read.table("yourExcelAsText.txt", sep="\t", header=TRUE, as.is=TRUE)
tab[tab==""] <- "X"
tab <- as.data.frame(unclass(tab))

【讨论】:

  • 整个工作表比显示的要复杂得多。我不想用 X 填充空单元格。“X”表示合并单元格中的信息,这些信息可能会因工作表而异,我需要以某种方式在工作表中保留该信息。例如,我不想将它保存在未标记单元格的左上角,因为我需要能够将它与“b”相关联,这取决于可能在 A2、A3 或 C1 中找到的工作表。因此,如果我将它保存在每个未标记的单元格中,我将能够在以后的步骤中将其拾取,从而清理这个非常混乱的电子表格。
  • 在这种情况下,@lmo 提供了对您更有用的代码。
【解决方案5】:

你需要根据具体情况来解决。下面的代码解决了您引用的案例。我又加了一个。将文件另存为csv 或读取为 xlxs。这使用了for,但它可以很容易地被矢量化以提高速度。

da=read.table("testtemp.csv",sep=";",na.strings=c("", "NA"),stringsAsFactors = F) 
#str(da)

#add more cases
da[5,1]<-da[5,2]<-da[4,2]<-NA
da

> da
    V1   V2   V3 V4
1    q    f    i  l
2    b    x <NA>  m
3    c <NA> <NA>  n
4    d <NA>    j  o
5 <NA> <NA>    k  p

#function to find cases
cencell=function(da){ #i=2;j=2
  fc=data.frame(matrix(NA,nrow(da)-1,3))
  ij=1
  for (i in 1:(ncol(da)-1))
    for (j in 1:(nrow(da)-1)){
      cst=c(da[j,i+1],da[j+1,i+1],da[j+1,i])
      if(all(is.na(cst))){fc[ij,1:2]<-c(j,i)
      fc[ij,3]<-da[j,i]
      ij<-1+ij}
    }
  fc[1:(ij-1),]
}
(ctc=cencell(da))
#replace cases
daf=da  #i=1
for(i in 1:nrow(ctc)){daf[ctc[i,1]+1,ctc[i,2]]<-ctc[i,3]
daf[ctc[i,1]:(ctc[i,1]+1),ctc[i,2]+1]<-ctc[i,3]
}
daf

> daf
  V1 V2 V3 V4
1  q  f  i  l
2  b  x  x  m
3  c  x  x  n
4  d  d  j  o
5  d  d  k  p

【讨论】:

    猜你喜欢
    • 2014-05-21
    • 1970-01-01
    • 2019-07-08
    • 2017-04-19
    • 2021-11-21
    • 1970-01-01
    • 2013-07-15
    • 2015-06-22
    • 1970-01-01
    相关资源
    最近更新 更多