данные.фрейм со столбцом, содержащим матрицу в R

#r #dataframe

#r #фрейм данных

Вопрос:

Я пытаюсь поместить некоторые матрицы в dataframe в 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 представляет собой список значений столбцов матрицы.

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

Спасибо!

Комментарии:

1. Несмотря на мой ответ, я испытываю некоторую симпатию к другому респонденту: почему вы хотите это сделать? Возможно, мы сможем помочь вам найти лучшую R-идиому для этого…

2. У меня есть данные, входные и выходные данные которых являются матрицами. Я хотел, чтобы каждый опыт был строкой фрейма данных.

3. Последние достижения в семействе пакетов tidyverse, в частности purrr, делают полезным создание вложенных столбцов произвольных типов данных для целей функционального программирования. Вложенные столбцы матриц могут быть полезны в качестве подготовительного шага для преобразования каждой матрицы в более простую структуру.

Ответ №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 , а затем (это обязательно) задайте 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
  

Комментарии:

1. Смотрите мой ответ для гораздо более простого решения.

Ответ №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
  

Комментарии:

1. Хотя в этом случае матрица превращается В столбец в dataframe. Может подойти для некоторых приложений (и вы можете просто получить доступ к элементам с помощью i * nrow ncol), но это ограничивает, если ваши матрицы имеют разные размеры.

Ответ №3:

Я столкнулся с той же проблемой, пытаясь понять данные о бензине в пакете pls. Используется $ для задания. Сначала давайте создадим матрицу, назовем ее spectra_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, такие как фильтрация, для возврата соответствующих строк матрицы, но это немного экспериментально.

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

Ответ №5:

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

ИМО, было бы лучше использовать 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 ...
  

Списками проще пользоваться, если вы планируете использовать матрицы различных размеров, и при условии, что они организованы таким же образом (для строк), как и внешний 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 (для массива).

Ответ №6:

Чтобы получить a data.frame с 1 строкой и 2 столбцами для данного примера, вы должны поместить matrix внутри a list .

 m <- matrix(1:4, 2)

x <- list2DF(list(id=1, mat=list(m)))
x
#  id        mat
#1  1 1, 2, 3, 4

str(x)
#'data.frame':   1 obs. of  2 variables:
# $ id : num 1
# $ mat:List of 1
#  ..$ : int [1:2, 1:2] 1 2 3 4


y <- data.frame(id=1, mat=I(list(m)))
y
#  id        mat
#1  1 1, 2, 3, 4

str(y)
#'data.frame':   1 obs. of  2 variables:
# $ id : num 1
# $ mat:List of 1
#  ..$ : int [1:2, 1:2] 1 2 3 4
#  ..- attr(*, "class")= chr "AsIs"
  

Создать a data.frame со столбцом, содержащим a matrix , с заданными данными с 2 строками и 2 столбцами, непосредственно при создании будет проще data.frame с помощью I() . Альтернативой без AsIs может быть вставка его позже, как уже показано другими.

 m <- matrix(1:4, 2)

x <- data.frame(id=1, mat=I(m))
str(x)
'data.frame':   2 obs. of  2 variables:
 $ id : num  1 1
 $ mat: 'AsIs' int [1:2, 1:2] 1 2 3 4

y <- data.frame(id=rep(1, nrow(m)))
y[["m"]] <- m
#y["m"] <- m   #Alternative
#y[,"m"] <- m  #Alternative
#y$m <- m      #Alternative
str(y)
#'data.frame':   2 obs. of  2 variables:
# $ id: num  1 1
# $ m : int [1:2, 1:2] 1 2 3 4

z <- `[<-`(data.frame(id=rep(1, nrow(m))), , "mat", m)
str(z)
#'data.frame':   2 obs. of  2 variables:
# $ id : num  1 1
# $ mat: int [1:2, 1:2] 1 2 3 4
  

В качестве альтернативы данные могут храниться в list .

 m <- matrix(1:4, 2)
x <- list(id=1, mat=m)
x
#$id
#[1] 1
#
#$mat
#     [,1] [,2]
#[1,]    1    3
#[2,]    2    4

str(x)
#List of 2
# $ id : num 1
# $ mat: int [1:2, 1:2] 1 2 3 4