【问题标题】:data.frame with a column containing a matrix in Rdata.frame 的列包含 R 中的矩阵
【发布时间】:2011-05-26 19:01:37
【问题描述】:

我正在尝试将一些矩阵放入 R 中的数据框中,例如:

m <- matrix(c(1,2,3,4), nrow=2, ncol=2)
df <- data.frame(id=1, mat=m)

但是当我这样做时,我会得到一个 2 行 3 列的数据框,而不是 1 行 2 列的数据框。

阅读文档,我必须使用 I() 转义我的矩阵。

df <- data.frame(id=1, mat=I(m))

str(df)
'data.frame':   2 obs. of  2 variables:
 $ id : num  1 1
 $ mat: AsIs [1:2, 1:2] 1 2 3 4

据我了解,数据框包含矩阵的每一行的一行,而 mat 字段是矩阵列值的列表。

那么,如何获取包含矩阵的数据框?

谢谢!

【问题讨论】:

  • 尽管有我的回答,但我对另一位受访者有些同情:你为什么要这样做?也许我们可以帮助您找到更好的 R 习惯用法...
  • 我有输入和输出为矩阵的数据。我希望每个体验都是数据框的一行。
  • tidyverse 系列软件包的最新进展,尤其是 purrr,使得创建任意数据类型的嵌套列以用于函数式编程非常有用。矩阵的嵌套列可用作将每个矩阵转换为更简单结构的准备步骤。

标签: r dataframe


【解决方案1】:

我发现包含矩阵的 data.frames 令人费解,但是:我知道实现这一点的唯一方法是隐藏在 stats:::simulate.lm

试试这个,看看发生了什么:

d <- data.frame(y=1:5,n=5)
g0 <- glm(cbind(y,n-y)~1,data=d,family=binomial)
debug(stats:::simulate.lm)
s <- simulate(g0,n=5)

这是一种奇怪的后门解决方案。创建一个列表,将其类更改为data.frame,然后(这是必需)手动设置namesrow.names(如果您不执行这些最后步骤,数据仍将在对象中,但它会打印出来,好像它有零行......)

m1 <- matrix(1:10,ncol=2)
m2 <- matrix(5:14,ncol=2)
dd <- list(m1,m2)
class(dd) <- "data.frame"
names(dd) <- LETTERS[1:2]
row.names(dd) <- 1:5
dd

【讨论】:

  • 查看我的回复以获得更直接的解决方案。
【解决方案2】:

更简单的方法是使用矩阵占位符定义数据框

m <- matrix(c(1, 2, 3, 4), nrow = 2, ncol = 2) 
df <- data.frame(id = 1, mat = rep(0, nrow(m)))

然后分配矩阵。无需使用列表类或使用*apply() 函数。

df$mat <- m

【讨论】:

  • 尽管这会让您将矩阵转换为数据框中的一列。对于某些应用程序可能没问题(您可以通过 i*nrow + ncol 访问元素),但如果您的矩阵大小不同,则会受到限制。
【解决方案3】:

我在尝试理解 pls 包中的汽油数据时遇到了同样的问题。使用$ 完成这项工作。 首先,让我们创建一个矩阵,我们将其命名为spectrum_mat,然后创建一个名为response_var1 的向量。

spectra_mat = matrix(1:45, 9, 5)
response_var1 = seq(1:9)

现在我们将向量 response_var1 放入一个新的数据框中 - 我们称之为 df。

df = data.frame(response_var1)
df$spectra = spectra_mat

检查,

str(df)

'data.frame':   9 obs. of  2 variables:
 $ response_var1: int  1 2 3 4 5 6 7 8 9
 $ spectra      : int [1:9, 1:5] 1 2 3 4 5 6 7 8 9 10 ...

【讨论】:

    【解决方案4】:

    包含矩阵列的数据框在特定场景中确实有其用途。这些情况是当您对数据集中的每个观察值都有某个变量的整个向量时。我遇到过两种常见的情况:

    1. 贝叶斯分析:您为每个观察创建后验预测,因此对于新数据中的每一“行”,您都有一个完整的向量(该向量的长度是 MCMC 迭代的次数)。
    2. 函数数据分析:每个“观察”本身就是一个函数,您将观察到的函数实现存储为向量。

    如果您使用的是数据框,则有一些明显的方法可以处理这些数据,但这些方法都是低效的。我将以贝叶斯案例为例:

    1. “超宽”格式:除了数据框的其他列之外,向量的每个元素都有一列。这会产生一个非常宽的数据框,通常很难使用。这也使得仅引用与后验相对应的那些列变得困难。
    2. “超长”(整洁)格式:非常占用内存,因为数据框的所有其他列都必须在后验的每次迭代中不必要地重复。
    3. 列表列:您可以创建一个列表,其中每个元素都是对应于数据框该行的后验的向量。这里的问题是,您想要做的大部分操作都需要您将后验取消列出回矩阵,并且列出/取消列出是不必要的计算。

    具有矩阵列的数据框是解决这种情况的一个非常有用的解决方案。后验保留在与数据框具有相同行数的矩阵中。但是该矩阵仅被识别为数据框中的单个“列”,并且使用 df$mat 引用该列将返回矩阵。你甚至可以使用一些 dplyr 函数比如过滤来返回矩阵的对应行,但这有点experimental

    创建矩阵列的最简单方法是分两步。首先创建没有矩阵列的数据框,然后通过简单的赋值添加矩阵列。我还没有找到不涉及更改列类型的I() 的 1 步解决方案。

    m <- matrix(c(1,2,3,4), nrow=2, ncol=2)
    df <- data.frame(id = rep(1, nrow(m)))
    df$mat <- m
    names(df)
    # [1] "id"  "mat"
    str(df)
    # 'data.frame': 2 obs. of  2 variables:
    #  $ id : num  1 1
    #  $ mat: num [1:2, 1:2] 1 2 3 4
    

    【讨论】:

      【解决方案5】:

      您得到的结果(2 行 x 3 列)是 R 的预期结果,因为它等于 cbind 一个向量(id,带有回收)和一个矩阵(m)。

      IMO,如果您真的想绑定不同的数据结构,最好使用listarray(当尺寸一致时,不允许混合数字和因子值)。否则,只需 cbind 您的矩阵到现有的 data.frame 如果两者具有相同的行数就可以完成这项工作。例如

      x1 <- replicate(2, rnorm(10))
      x2 <- replicate(2, rnorm(10))
      x12l <- list(x1=x1, x2=x2)
      x12a <- array(rbind(x1, x2), dim=c(10,2,2))
      

      结果显示

      > str(x12l)
      List of 2
       $ x1: num [1:10, 1:2] -0.326 0.552 -0.675 0.214 0.311 ...
       $ x2: num [1:10, 1:2] -0.164 0.709 -0.268 -1.464 0.744 ...
      > str(x12a)
       num [1:10, 1:2, 1:2] -0.326 0.552 -0.675 0.214 0.311 ...
      

      如果您计划使用不同维度的矩阵,列表会更易于使用,并且如果它们的组织方式(对于行)与外部 data.frame 相同,您可以轻松地将它们子集化。这是一个例子:

      df1 <- data.frame(grp=gl(2, 5, labels=LETTERS[1:2]), 
                        age=sample(seq(25,35), 10, rep=T))
      with(df1, tapply(x12l$x1[,1], list(grp, age), mean))
      

      您还可以使用lapply(用于列表)和apply(用于数组)函数。

      【讨论】:

        猜你喜欢
        • 2021-12-23
        • 2014-12-29
        • 1970-01-01
        • 1970-01-01
        • 2020-04-20
        • 2017-12-22
        • 2023-03-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多