#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)
Спасибо-