Создание индексированного многомерного массива в [R] из фрейма данных 2×2

#data-binding #r #multidimensional-array

#привязка данных #r #многомерный массив

Вопрос:

У меня есть двумерный data.frame с панельными данными (отдельные наблюдения за определенный период времени). Я считаю, что это было бы более полезно, если бы я создал трехмерный массив, содержащий те же данные с измерениями: дата, отдельные данные, значения.

Итак, мой подход заключается в том, чтобы изолировать конкретные даты внутри существующего фрейма данных 2×2, а затем сложить эти фрагменты друг на друга, чтобы получить трехмерный массив. Однако каждый фрагмент имеет разное количество строк, поэтому функция ‘abind’ не позволяет мне складывать их.

 # create example data frame
df1 = cbind(rep(8,12),c(rep(4,4),rep(3,4),2,2,1,1),
rep(2010,12),c("John","Frank","Bill","Anne","John",
"Frank","Bill","Anne","John","Frank","John","Frank"),
1:12,90:79,41:52)

df1 = data.frame(df1)
names(df1) = c("MM","DD","YR","Individual","Value1","Value2","Value3")

# the 'cube' function isolates a specific MM/DD/YR 'slice'
# Later I will attempt to stack the slices to get a 3-d array.
cube = function(MM,DD,YR) {
df2 = df1[df1$MM == MM amp; df1$DD == DD amp; df1$YR == YR,]
df2
}

# specify some parameter values
m = 8
d = c(1:4)
y = 2010

# apply 'cube' function to all date combinations specified
# by parameters m, d, y

out = apply(expand.grid(m,d,y),1,
function(x,y,z) cube(x[1],x[2],x[3]))

out = array(out)
k = dim(expand.grid(m,d,y))
z = data.frame(out[1])

require(abind)

# specify function that will transform 2-d data.frame into 3-d array.
for (i in 2:k[1]){
p = data.frame(out[i])
z = abind(z,p,along = 3)
}
  

Сообщение об ошибке, которое я получаю при запуске цикла, является:

 Error in abind(z, p, along = 3) : 
  arg 'X2' has dims=4, 7, 1; but need dims=2, 7, X
  

Я использую пакет CRAN ‘abind’.

Вопрос: Есть ли способ заставить функцию ‘abind’ накладывать фрагменты разного размера друг на друга? Или есть более эффективный способ создать желаемый массив?

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

1. Я не уверен на 100%, что вы подразумеваете под «фреймом данных 2×2». Наивно читать, это звучит как 2 строки и 2 столбца (что не может быть тем, что вы имеете в виду, я не думаю). Было бы действительно полезно, если бы вы могли предоставить небольшой воспроизводимый пример.

2. Хорошо; теперь код включает воспроизводимый пример.

3. Делает ли новый ответ то, что вы хотите?

4. Да; это так — спасибо. Однако, когда я использую его с моим реальным набором данных (не воспроизводимым примером), я получаю ошибку, которую пытаюсь выяснить. Когда я «расплавляю» данные, он говорит: «Для агрегации требуется fun.aggregate: длина, используемая по умолчанию», и результатом является массив с набором значений 0, 1 и 2. Когда я разберусь с этим, я повторно опубликую. Еще раз спасибо!

Ответ №1:

Полностью переписано (спасибо за пример). Я переписал данные вашего примера, чтобы они были немного более компактными.

 df1 <- data.frame(MM=rep(8,12),DD=c(rep(4,4),rep(3,4),2,2,1,1),
                  YR=rep(2010,12),
                  Individual=c("John","Frank","Bill","Anne","John",
                    "Frank","Bill","Anne","John","Frank","John","Frank"),
                  Value1=1:12,Value2=90:79,Value3=41:52)
## create composite date variable
df1 <- transform(df1,date=as.Date(paste(YR,MM,DD,sep="/")))
## drop date components
df1 <- subset(df1,select=-c(MM,DD,YR))
library(reshape)
m <- melt(df1,id.var=c("Individual","date"))
cast(m,Individual~...~date)
  

В качестве альтернативы, если вы не хотите заполнять пробелы с помощью NAs, но хотите иметь «неровный» список, вы можете сделать это:

 lapply(split(df1,df1$date),function(x) subset(x,select=-date))
  

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

1. Спасибо — это полезно, но не совсем то, что я ищу. Я добавил воспроизводимый код к своему ответу (выше). Я думаю, что ваш метод работает, когда для каждого наблюдения есть только одно «Значение» (date, subj). Но я надеюсь, что с помощью трехмерного массива я смогу обрабатывать несколько значений за одно наблюдение.

2. Что заставило его работать с моими данными, так это замена вашей последней строки кода на sum в функции приведения: cast(m,Individual~...~date,sum) Спасибо-