Преобразование data.frame в многомерную матрицу

#r #dataframe #matrix #multidimensional-array #vector

#r #фрейм данных #матрица #многомерный-массив #вектор

Вопрос:

Например, рассмотрим следующие данные

 > sample.df
  f1 f2   x1   x2   x3
1  2  2 7.28 9.40 5.02
2  1  1 6.30 9.56 3.74
3  2  1 6.88 8.72 3.14
4  1  2 6.68 9.58 3.84
  

Интересно, как написать MAGIC так, чтобы

 > sample.matrix <- MAGIC(sample.df)
> sample.matrix[1, 1, ]
[1] 6.30 9.56 3.74
> sample.matrix[1, 2, ]
[1] 6.68 9.58 3.84
  

По сути, sample.matrix[x, y, ] выбирается строка в фрейме данных с sample.df[sample.df$f1 == x amp; sample.df$f2 == y, ] помощью , а затем удаляются избыточные столбцы, указывающие значение f1 и f2 . Обратите внимание, что каждая комбинация (f1, f2) появляется и появляется только один раз во фрейме данных.

За моей первой мыслью as.matrix последовало a dim<- , но строки во фрейме данных не отсортированы. Для сортировки потребуется O (n * log (n)), но я просто хочу создать таблицу, поэтому теоретически временная сложность может быть ограничена O (n) .

Было бы лучше, если бы вы могли использовать векторизацию, если это возможно.

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

1. cran.r-project.org/web/packages/data.table/vignettes / … пожалуйста, смотрите 1c и 2a

Ответ №1:

Вот идея с помощью matrix . Обратите внимание, что это не совсем то же самое, что требуемый вам результат, но его можно легко преобразовать.

Предполагая, что df является вашим sample.df ,

 m1 <- matrix(do.call(paste, df[with(df, order(f1, f2)),-c(1, 2)]), nrow = 2, byrow = TRUE)
m1[1, 2]
#[1] "6.68 9.58 3.84"
m1[1, 1]
#[1] "6.3 9.56 3.74"
m1[2, 1]
#[1] "6.88 8.72 3.14"
m1[2, 2]
#[1] "7.28 9.4 5.02"
  

Вы можете получить их в виде числовых векторов путем разделения, т.е.

 as.numeric(strsplit(m1[1, 2], ' ')[[1]])
#[1] 6.68 9.58 3.84
  

Ответ №2:

Редактировать

После повторного прочтения вопроса, я думаю, мы можем использовать split without order ing, чтобы избежать этапа сортировки. Поскольку f1 и f2 уникальны для каждой строки, мы можем сделать

 split(sample.df[, -(1:2)], list(sample.df$f1, sample.df$f2))


#$`1.1`
#   x1   x2   x3
#2 6.3 9.56 3.74

#$`2.1`
#    x1   x2   x3
#3 6.88 8.72 3.14

#$`1.2`
#    x1   x2   x3
#4 6.68 9.58 3.84

#$`2.2`
#    x1  x2   x3
#1 7.28 9.4 5.02
  

Оригинальный ответ

Я не совсем понимаю цель, но один из способов — order sample.df by f1 , f2 а затем подмножество с использованием Map

 new_df <- sample.df[with(sample.df, order(f1, f2)),]

Map(function(x, y) new_df[with(new_df, f1 == x amp; f2 == y), -(1:2)],
                   new_df$f1, new_df$f2)

#[[1]]
#   x1   x2   x3
#2 6.3 9.56 3.74

#[[2]]
#    x1   x2   x3
#4 6.68 9.58 3.84

#[[3]]
#    x1   x2   x3
#3 6.88 8.72 3.14

#[[4]]
#    x1  x2   x3
#1 7.28 9.4 5.02
  

Если приведенный выше результат является вашим ожидаемым результатом, то каждая строка new_df — это результат, который вы хотите. Если вы хотите, чтобы они были отдельным списком, мы также можем split использовать каждую строку

 split(new_df[, -(1:2)], seq_len(nrow(new_df)))
  

что даст вам тот же результат.

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

1. Могу ли я преобразовать результат split в вектор? as.numeric не работает. Если это возможно, тогда я смогу использовать dim<- хак.

2. @nalzok Что-то вроде этого split(unlist(sample.df[, -(1:2)], use.names = FALSE), list(sample.df$f1, sample.df$f2), ) ?

3. Похоже, это не работает, но unlist(split(sample.df[, -(1:2)], list(sample.df$f1, sample.df$f2)), use.names = FALSE) делает свое дело!

4. хорошо .. я думал, вы хотите сохранить структуру списка, чтобы различать каждую строку. Это вернет один вектор.

5. Вы правы, и это то, что я сейчас делаю. После data.vector <- unlist(split(... этого я бы сделал a dim(data.vector) <- c(2, 2, 3, 4) , чтобы вернуть структуру списка. Однако R создает матрицы по столбцам, поэтому мне все еще интересно, как это сделать правильно…