Транспонировать и фильтровать Dataframe с нулевыми значениями в R

Это почти вызов!

У меня есть следующий фрейм данных:

tag     hour                    val
N1      2013-01-01 00:00:00     0.3404266179
N1      2013-01-01 01:00:00     0.3274182995
N1      2013-01-01 02:00:00     0.3142598749
N2      2013-01-01 02:00:00     0.3189924887
N2      2013-01-01 04:00:00     0.3170907762
N3      2013-01-01 05:00:00     0.3161910788
N3      2013-01-01 06:00:00     0.4247638954

Мне нужно преобразовать его в нечто вроде этого:

hour                    N1              N2              N3
2013-01-01 00:00:00     0.3404266179    NULL            NULL
2013-01-01 01:00:00     0.3274182995    NULL            NULL
2013-01-01 02:00:00     0.3142598749    0.3189924887    NULL
2013-01-01 03:00:00     NULL            NULL            NULL
2013-01-01 04:00:00     NULL            0.3170907762    NULL
2013-01-01 05:00:00     NULL            NULL            0.3161910788
2013-01-01 06:00:00     NULL            NULL            0.4247638954

Поскольку все не так просто, мой фрейм данных достигает N5000, а в часе содержится почти 200 000 записей для каждого N.

Временная метка очень хорошо себя ведет, так как она увеличивается каждую минуту для всех таким образом, что вы можете сгенерировать все временные метки с помощью простой команды, такой как strptime("2013-01-01 00:00:00", "%Y-%m-%d %H:%M:%S") + c(0:172800)*60 (172800 минут ~ 4 месяца). Но не обязательно у вас есть данные для каждой временной отметки, как я показываю на примере.

Я знаю, что мог бы написать функцию с бесконечными циклами, но есть ли способ сделать это, используя только функции R (и ее пакеты)?

Спасибо!

3 ответа

Решение

Вы хотите использовать пакет "reshape2":

 install.packages("reshape2")
 library(reshape2)
 newdf <- dcast(mydata, hour~tag)

Reshape2 - это невероятно мощный пакет, который я совершенно не понимаю... но иногда в нем есть такие полезные вещи, которые просто работают.:-)

ОБНОВЛЕНО: это "dcast", а не "cast"... Я по ошибке использовал пакет "reshape", а не "reshape2". Исправлена!

Вы также можете рассмотреть базовую функцию reshape если вы не хотите возиться с другим пакетом. Используя пример данных @gagolews

> reshape(df, idvar="hour", timevar="tag", v.names="val", direction="wide")
                 hour    val.N1    val.N2    val.N4
1 1969-12-31 19:00:01 0.8156553        NA        NA
2 1969-12-31 19:00:02 0.9203821        NA        NA
3 1969-12-31 19:00:03 0.8127614 0.7386737        NA
5 1969-12-31 19:00:05        NA 0.9648562        NA
6 1969-12-31 19:00:06        NA        NA 0.2540216
7 1969-12-31 19:00:07        NA        NA 0.5024042

Это не самое простое и элегантное решение, но оно работает:

Примерный data.frame:

df <- data.frame(tag=rep(c("N1", "N2", "N4"), c(3,2,2)),
                 hour=structure(c(1,2,3,3,5,6,7), class="POSIXct"),
                 val=runif(7))
##   tag                hour       val
## 1  N1 1970-01-01 01:00:01 0.6645598
## 2  N1 1970-01-01 01:00:02 0.7924186
## 3  N1 1970-01-01 01:00:03 0.3813311
## 4  N2 1970-01-01 01:00:03 0.8555780
## 5  N2 1970-01-01 01:00:05 0.4480540
## 6  N4 1970-01-01 01:00:06 0.1875233
## 7  N4 1970-01-01 01:00:07 0.5755332

Теперь мы создаем полученный date столбец (это просто пример):

uh <- structure(1:7, class="POSIXct") # or e.g. uh <- unique(df$hour), or seq(), etc.

Затем мы создаем "пустой" результирующий фрейм данных (каждый val будет NA)

nr <- length(uh) # number of rows on out
# column definitions:
(coldef <- paste("hour=uh", paste(unique(df$tag), "NA_real_", sep="=", collapse=", "), sep=", "))
## [1] "hour=uh, N1=NA_real_, N2=NA_real_, N4=NA_real_"
# create output df:
outdf <- eval(parse(text=sprintf("data.frame(list(%s))", coldef)))

Наконец, давайте установим значения в каждом N* колонка:

for (idx in split(1:nrow(df), df$tag))
   outdf[outdf$hour %in% df$hour[idx], as.character(df$tag[idx[1]])] <- df$val[idx]
Другие вопросы по тегам