data.frame со столбцом, содержащим матрицу в R

Я пытаюсь поместить некоторые матрицы в кадр данных в 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

Насколько я понимаю, датафрейм содержит по одной строке для каждой строки матрицы, а поле мата — это список значений столбца матрицы.

Таким образом, как я могу получить кадр данных, содержащий матрицы?

Спасибо !


person Scharron    schedule 26.05.2011    source источник
comment
Несмотря на мой ответ, у меня есть некоторое сочувствие к другому респонденту: почему вы хотите это сделать? Возможно, мы сможем помочь вам найти лучшую идиому R для этого...   -  person Ben Bolker    schedule 27.05.2011
comment
У меня есть данные с входами и выходами, являющимися матрицами. Я хотел, чтобы каждый опыт был строкой фрейма данных.   -  person Scharron    schedule 27.05.2011
comment
Недавние достижения в семействе пакетов tidyverse, особенно в Purrr, делают полезным создание вложенных столбцов произвольных типов данных для целей функционального программирования. Вложенные столбцы матриц могут быть полезны в качестве подготовительного шага для преобразования каждой матрицы в более простую структуру.   -  person David Bruce Borenstein    schedule 13.04.2017


Ответы (5)


Я нахожу 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, а затем (это обязательно) установите names и row.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
person Ben Bolker    schedule 26.05.2011
comment
Смотрите мой ответ для гораздо более простого решения. - person Jonathan Gellar; 20.04.2020

Гораздо более простой способ сделать это — определить фрейм данных с заполнителем для матрицы.

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
person adamleerich    schedule 08.09.2011
comment
Хотя это оставляет вам матрицу, превращаемую в столбец в кадре данных. Может быть нормально для некоторых приложений (и вы можете просто получить доступ к элементам с помощью i*nrow + ncol), но это ограничивает, если ваши матрицы имеют разные размеры. - person Three Diag; 06.04.2016

Я столкнулся с той же проблемой, пытаясь понять данные о бензине в пакете pls. Использовал $ для работы. Во-первых, давайте создадим матрицу, назовем ее speck_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 ...
person zoc99    schedule 02.04.2017

Фреймы данных, содержащие матричные столбцы, находят свое применение в специализированных сценариях. Эти сценарии представляют собой случаи, когда у вас есть целый вектор некоторой переменной для каждого наблюдения в вашем наборе данных. Есть два случая, с которыми я столкнулся, когда это распространено:

  1. Байесовский анализ: вы создаете апостериорный прогноз для каждого наблюдения, поэтому для каждой строки в ваших новых данных у вас есть целый вектор (длина этого вектора — это количество итераций MCMC).
  2. Функциональный анализ данных: каждое наблюдение само по себе является функцией, и вы сохраняете наблюдаемую реализацию этой функции в виде вектора.

Если вы работаете с фреймами данных, есть несколько очевидных способов обработки этих данных, оба из которых неэффективны. Я буду использовать байесовский случай в качестве примера:

  1. Сверхширокий формат: у вас есть один столбец для каждого элемента векторов в дополнение к другим столбцам фрейма данных. Это создает чрезвычайно широкий фрейм данных, с которым часто трудно работать. Это также затрудняет обращение только к тем столбцам, которые соответствуют апостериорным.
  2. Сверхдлинный (аккуратный) формат: очень интенсивно использует память, потому что все остальные столбцы вашего фрейма данных должны повторяться без необходимости для каждой итерации апостериорного.
  3. Столбцы списка: вы можете создать список, в котором каждый элемент является вектором, соответствующим апостериорному для этой строки фрейма данных. Проблема здесь в том, что большинство манипуляций, которые вы хотите сделать, потребуют от вас удаления апостериорного списка обратно в матрицу, а перечисление/удаление списка является ненужным вычислением.

Фреймы данных со столбцами матрицы — очень полезное решение в этой ситуации. Апостериор остается в матрице с тем же количеством строк, что и фрейм данных. Но эта матрица распознается только как один столбец во фрейме данных, и ссылка на этот столбец с помощью df$mat вернет матрицу. Вы даже можете использовать некоторые функции dplyr, такие как фильтрация, чтобы вернуть соответствующие строки матрицы, но это немного экспериментальный.

Самый простой способ создать столбец матрицы состоит из двух шагов. Сначала создайте фрейм данных без столбца матрицы, затем добавьте столбец матрицы с помощью простого назначения. Я не нашел одноэтапного решения для этого, которое не включает I(), которое изменяет тип столбца.

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
person Jonathan Gellar    schedule 20.04.2020

Полученный результат (2 строки x 3 столбца) — это то, что следует ожидать от R, поскольку он представляет собой cbind вектор (id, с повторным использованием) и матрицу (m).

IMO, было бы лучше использовать list или array (когда размеры совпадают, не допускается сочетание числовых и коэффициентных значений), если вы действительно хотите связать разные структуры данных. В противном случае просто 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 ...

Списки проще использовать, если вы планируете использовать матрицу различных размеров, и при условии, что они организованы так же (для строк), что и внешний фрейм данных, вы можете легко подмножить их. Вот пример:

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 (для массива).

person chl    schedule 26.05.2011