#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(...
этого я бы сделал adim(data.vector) <- c(2, 2, 3, 4)
, чтобы вернуть структуру списка. Однако R создает матрицы по столбцам, поэтому мне все еще интересно, как это сделать правильно…