Транспонировать и фильтровать 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]