如何编写 R 代码以由特定单元格直接从 excel 中读取?

How do I write R code to read directly from excel by specific cells?

我想知道一个好的起点(可能是有用的示例包,其他类似问题,R functions/code 起点)来编写直接从 [=19= 中的特定单元格提取的 R 代码] 文件并将其输入到可用于分析的数据框中。

全文:我从读取 96 孔板的实验中得到 excel 文件作为输出。 excel个文件是盘子的形状。 excel 文件可能如下图所示。在这种情况下,我想创建一个数据框,每个值都有一行,但是一个因子列在 excel 文件图像中的每种颜色上附加了一个标签。我想象这是通过指定确切的单元格位置和硬编码来完成的?我是 R 的新手,但有很多书籍和其他资源可供使用,这就是为什么任何关于好的起点的建议都会有所帮助!

Excel file example

readxl::read_excel()openxlsx::read.xlsx()都有允许定义特定范围的参数,即rangerows/cols。两者都允许定义 sheet。请参阅有关这些功能的 help

解析来自 96 孔实验的数据并非易事。您需要执行三个主要步骤:

  1. 将数据读入数据框。
  2. 使数据框“整洁”。
  3. 将标签与数据相关联。

第 1 步:加载数据

readxl::read_excel()函数可用于从Excel文件中获取原始数据到R中。还有其他方法可以做同样的事情,但我喜欢 readxl::read_excel(),因为它是 tidyverse 的一部分。我将在下一节中展示如何调用此函数。

第 2 步:整理数据

整齐的数据比“杂乱”的数据更容易处理。如果您不熟悉整理数据的概念,可能值得花时间阅读 this introduction or this paper。简而言之,如果满足以下条件,则数据框是整洁的:

  • 每一列都是一个变量。
  • 每一行都是一个观察值。

在这种情况下,这意味着我们需要:

  • 4 列:

    • "row_i",指盘子上的一行,例如0-7
    • "col_j",指的是盘子上的一列,例如0-11
    • “label”,指的是单元格中指定的标签“Label 1”和“Label 2” A4 和 A13
    • “值”,指单元格中的数值。
  • 192 行:

    • “标签 1”印版为 96,“标签 2”印版为 96。
    • 如果我们要排除没有价值的井,我们可以有更少的行,但是 这样做真的没有任何好处。

下面是一些加载和整理数据的代码。 pivot_longer() 函数将盘状数据转换为整齐的数据。如果您不熟悉此功能,this vignette 是一个很好的介绍。

library(tidyverse)

# Load the "Label 1" and "Label 2" data separately, then combine then into a 
# single data frame afterwards.  This approach is pretty fragile (e.g. if a 
# "Label 3" were to be added, we'd have to change the code to account for 
# that), but unfortunately this data doesn't really lend itself to being parsed 
# robustly.

# Because the code for parsing the two plates will be pretty similar, we can 
# use a function to avoid repeating ourselves.
load_plate <- function(path, label, anchor) {
  readxl::read_excel(
        path,

        # Read an 8x12 block of cells.  There are easier ways to specify which 
        # cell to load (e.g. "B5:M12"), but using readxl::anchored() guarantees 
        # that the resulting data frame has the expected dimensions, which in 
        # turn simplifies the task of labeling the row and column indices.
        range=readxl::anchored(anchor, c(8, 12)),

        # The column indices aren't present in the Excel file, so we add them 
        # here.  The paste() function is necessary because column names have 
        # to be strings.  Later on we'll convert these names back to numbers 
        # and use them to populate the "col_j" column.
        col_names=paste(0:11),
      ) %>%

  # The row indices aren't present in the Excel file, so we add them here.  
  # We also add the label column, which is the same for all of these wells.
  mutate(
        row_i=0:7,
        label=label
      ) %>%

  pivot_longer(
        !c(row_i, label),
        names_to="col_j",
        names_transform=list(col_j=as.integer),
      )
}

data <- bind_rows(
      load_plate("path/to/data.xlsx", 1, "B5"),
      load_plate("path/to/data.xlsx", 2, "B14"),
)

第 3 步:标记数据

数据框现在包含来自 Excel 文件的数据,但不包含标签(例如 blue/red/yellow/green)。我自己处理的微孔板数据比较多,所以专门写了一个叫wellmapr的包给这类数据加标签。这个包促进的基本方法是:

  • 将数据加载到整齐的数据框中。
  • 将布局加载到另一个整齐的数据框中。
  • 合并两个数据框。

第一步是创建一个单独的文件来描述印版的布局。上面链接的文档描述了如何编写这些文件,它们通常非常简单。以下是描述您的数据的文件:

[row]
A.factor = "blue"
H.factor = "blue"

[col]
1.factor = "blue"
12.factor = "blue"

[block.1x3]
B2.factor = "red"
B3.factor = "yellow"
B4.factor = "green"

接下来的步骤是加载布局并将其与数据合并:

library(wellmapr)

layout <- wellmapr::load("path/to/layout.toml")

# This join works because both data frames have "row_i" and "col_j" columns 
# that contain 0-indexed row/column indices.  In fact, we intentionally prepared 
# the `data` data frame such that it would have these columns.
df <- inner_join(data, layout)

最终结果是一个数据框,它结合了每个孔的测量数据(“值”、“标签”)和布局信息(“因子”):

# A tibble: 90 x 9
   row_i label col_j value well  well0 row   col   factor
   <dbl> <dbl> <dbl> <dbl> <chr> <chr> <chr> <chr> <chr> 
 1     0     1     0   101 A1    A01   A     1     blue  
 2     0     1     1   104 A2    A02   A     2     blue  
 3     0     1     2   106 A3    A03   A     3     blue  
 4     0     1     3    99 A4    A04   A     4     blue  
 5     0     1     4    94 A5    A05   A     5     blue  
 6     0     1     5    96 A6    A06   A     6     blue  
 7     0     1     6    92 A7    A07   A     7     blue  
 8     0     1     7    84 A8    A08   A     8     blue  
 9     0     1     8   109 A9    A09   A     9     blue  
10     0     1     9   110 A10   A10   A     10    blue  
# … with 80 more rows

一些离别的感想:

  • 使用wellmapr 将布局与分析分离,这真是一件好事。这使得使用不同的布局重用相同的分析脚本以及使用不同的分析脚本重用相同的布局变得容易。

  • 我展示了如何使用 inner_join() 将标签与数据合并,但是 wellmapr::load() 可以自动进行合并。让 wellmapr::load() 进行合并实际上更好,因为它处理与包含多个数据文件的布局相关的极端情况。有关详细信息,请参阅文档。