2016-09-14 18 views
2

data.frameの各行に関数を適用して列クラスを保存する方法があるのだろうか?のは、私が何を意味するか明確にする例を見てみましょう:data.frameの各行に関数を適用し、列クラスを保持する

test <- data.frame(startdate = as.Date(c("2010-03-07", "2013-09-13", "2011-11-12")), 
        enddate = as.Date(c("2010-03-23", "2013-12-01", "2012-01-05")), 
        nEvents = c(123, 456, 789)) 

は、私がstartdateenddate間のすべての日を挿入することにより、data.frame testを拡張したもの日間のイベントの数を配布したいとします。これを行うには私の最初の試みは、これだった:applytestas.matrixを呼び出すので、それが文字行列に変換されると、すべての列クラスが失われているため

eventsPerDay1 <- function(row) { 
    n_days <- as.numeric(row$enddate - row$startdate) + 1 
    data.frame(date = seq(row$startdate, row$enddate, by = "1 day"), 
       nEvents = rmultinom(1, row$nEvents, rep(1/n_days, n_days))) 
} 

apply(test, 1, eventsPerDay1) 

これは、しかし、ことはできません。

私はすでに下記の2つの回避策を見つけました。私の質問は、より哲学的なものです。

library(magrittr) 
############# Workaround 1 
eventsPerDay2 <- function(startdate, enddate, nEvents) { 
    n_days <- as.numeric(enddate - startdate) + 1 
    data.frame(date = seq(startdate, enddate, by = "1 day"), 
       nEvents = rmultinom(1, nEvents, rep(1/n_days, n_days))) 
} 

mapply(eventsPerDay2, test$startdate, test$enddate, test$nEvents, SIMPLIFY = F) %>% 
    do.call(rbind, .) 


############# Workaround 2 
seq_along(test) %>% 
    lapply(function(i) test[i, ]) %>% 
    lapply(eventsPerDay1) %>% 
    do.call(rbind, .) 

回避策と私の「問題」は以下の通りです:

  • 対処方法1:それは最高の理由ではないかもしれないが、私は単にmapplyが好きではありません。それは他の*apply関数とは異なる署名(引数の順序が異なるため)があり、私は常にforというループがより明確になったと感じています。
  • 回避策2:非常に柔軟性がありますが、何が起きているのかは一目瞭然ではないと私は考えています。

だから誰でも、コールがapply(test, 1, eventsPerDay1)のようになり、それが機能することは知っていますか?

+0

クラスを保存したい場合は、 'apply'ではなく' apply'ではなく 'lapply'ループを使用してください。提案のおかげで – akrun

+0

@akrunに感謝しますが、"回避策2 "で行ったこととまったく同じですか?そうでない場合は、あなたが意味することを詳しく教えてください。ありがとう! – AEF

+0

はい、そうです。私は 'data.table'を使って解決策を投稿しました。それがより良いことを確認してください。 – akrun

答えて

2

我々は機能にdata.table

library(data.table) 
res <- setDT(test)[,n_days := as.numeric(enddate - startdate) + 1 
      ][, .(date = seq(startdate, enddate, by= "1 day"), 
      nEvents = c(rmultinom(1, nEvents, rep(1/n_days, n_days)))), 
     by = 1:nrow(test)][, nrow := NULL] 
str(res) 
#Classes ‘data.table’ and 'data.frame': 152 obs. of 2 variables: 
# $ date : Date, format: "2010-03-07" "2010-03-08" "2010-03-09" "2010-03-10" ... 
# $ nEvents: int 5 9 7 11 6 6 10 7 12 3 ... 

で上記ラップすることができますが、これを行うことができ

eventsPerDay <- function(dat){ 
     as.data.table(dat)[, n_days:= as.numeric(enddate - startdate) + 1 
     ][, .(date = seq(startdate, enddate, by= "1 day"), 
    nEvents = c(rmultinom(1, nEvents, rep(1/n_days, n_days)))) , 1:nrow(dat) 
     ][, nrow := NULL][] 
    } 

eventsPerDay(test) 
2

もう一つのアイデア:

library(dplyr) 
library(tidyr) 

test %>% 
    mutate(id = row_number()) %>% 
    group_by(startdate) %>% 
    complete(startdate = seq.Date(startdate, enddate, 1), nesting(id)) %>% 
    group_by(id) %>% 
    mutate(nEvents = rmultinom(1, first(nEvents), rep(1/n(), n()))) %>% 
    select(startdate, nEvents) 

います:

#Source: local data frame [152 x 3] 
#Groups: id [3] 
# 
#  id startdate nEvents 
# <int>  <date> <int> 
#1  1 2010-03-07  6 
#2  1 2010-03-08  6 
#3  1 2010-03-09  6 
#4  1 2010-03-10  7 
#5  1 2010-03-11  12 
#6  1 2010-03-12  5 
#7  1 2010-03-13  8 
#8  1 2010-03-14  5 
#9  1 2010-03-15  5 
#10  1 2010-03-16  9 
## ... with 142 more rows 
関連する問題