5

ddplywithを使用して、データフレーム内transformの新しい変数 ( summary_Date) に変数IDおよびを入力しようとしていますDate。変数の値は、以下を使用して評価されるピースの長さに基づいて選択されますifelse

特定の月に ID の観測が 5 つ未満の場合summary_Date、日付を最も近い月に丸めて計算したいと考えています ( round_datefrom packageを使用lubridate)。summary_Date特定の月に 1 つの ID に対して 5 つ以上の観測がある場合、単純にを にしたいと考えていますDate

require(plyr)
require(lubridate)

test.df <- structure(
  list(ID = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1, 1, 1, 1
                , 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,2, 2, 2, 2, 2, 2, 2, 2)
       , Date = structure(c(-247320000, -246196800, -245073600, -243864000
                            , -242654400, -241444800, -126273600, -123595200
                            , -121176000, -118497600, 1359385200, 1359388800
                            , 1359392400, 1359396000, 1359399600, 1359403200
                            , 1359406800, 1359410400, 1359414000, 1359417600
                            , 55598400, 56116800, 58881600, 62078400, 64756800
                            , 67348800, 69854400, 72964800, 76161600, 79012800
                            , 1358589600, 1358676000, 1358762400, 1358848800
                            , 1358935200, 1359021600, 1359108000, 1359194400
                            , 1359280800, 1359367200), tzone = "GMT"
                          , class = c("POSIXct", "POSIXt"))
       , Val=rnorm(40))
  , .Names = c("ID", "Date", "Val"), row.names = c(NA, 40L)
  , class = "data.frame")

test.df <- ddply(test.df, .(ID, floor_date(Date, "month")), transform
                 , summary_Date=as.POSIXct(ifelse(length(ID)<5
                                                  , round_date(Date, "month")
                                                  ,Date)
                                           , origin="1970-01-01 00:00.00"
                                           , tz="GMT")
                 # Included length_x to easily see the length of the subset
                 , length_x = length(ID))

head(test.df,5)
#   floor_date(Date, "month") ID                Date        Val summary_Date length_x
# 1                1962-03-01  1 1962-03-01 12:00:00 -0.1037988   1962-03-01        3
# 2                1962-03-01  1 1962-03-14 12:00:00  0.2923056   1962-03-01        3
# 3                1962-03-01  1 1962-03-27 12:00:00  0.4435410   1962-03-01        3
# 4                1962-04-01  1 1962-04-10 12:00:00  0.1159164   1962-04-01        2
# 5                1962-04-01  1 1962-04-24 12:00:00  2.9824075   1962-04-01        2

ステートメントはifelse機能しているようですが、「summary_Date」の値は、行固有の値ではなく、変換が機能しているサブセットに対して計算された最初の値のようです。たとえば、行 3 では、日付を切り上げる必要があるためsummary_Date(サブセット内の行が 5 つ未満であるため)、その代わりに( ) の最初に計算された値がそのサブセット内のすべての行で繰り返されます。1962-04-011962-03-27 12:00:00'summary_Date1962-03-01

編集:data.tableを使用して2つのステップで試してみたリカルドの答えに触発されましたddply。それも機能します:

test.df <- ddply(test.df, .(ID, floor_date(Date, "month")), transform
                 , length_x = length(ID))

test.df <- ddply(test.df, .(ID, floor_date(Date, "month")), transform
                 , summary_Date=as.POSIXct(ifelse(length_x<5
                                                  , round_date(Date, "month")
                                                  ,Date)
                                           , origin="1970-01-01 00:00.00"
                                           , tz="GMT"))

head(test.df,5)[c(1,3:7)]
#   floor_date(Date, "month") ID                Date        Val length_x summary_Date
# 1                1962-03-01  1 1962-03-01 12:00:00 -0.1711212        3   1962-03-01
# 2                1962-03-01  1 1962-03-14 12:00:00 -0.1531571        3   1962-03-01
# 3                1962-03-01  1 1962-03-27 12:00:00  0.1256238        3   1962-04-01
# 4                1962-04-01  1 1962-04-10 12:00:00  1.4481225        2   1962-04-01
# 5                1962-04-01  1 1962-04-24 12:00:00 -0.6508731        2   1962-05-01
4

2 に答える 2

7

ワンステップddplyソリューション(コメントとしても投稿)

ddply(test.df, .(ID, floor_date(Date, "month")), mutate, 
  length_x = length(ID), 
  summary_Date=as.POSIXct(ifelse(length_x < 5, round_date(Date, "month") ,Date)
    , origin="1970-01-01 00:00.00", tz="GMT")
)
于 2013-03-01T20:15:24.950 に答える
1
# transform to data.table
library(data.table)
test.dt <- data.table(test.df)

# calculate length of id by month-year. 
test.dt[, idlen := length(ID),  by=list(month(Date), year(Date)) ]

# calculate the summary date
test.dt[, summary_Date := ifelse(idlen<5, as.Date(round_date(Date, "month")), as.Date(Date))]

# If you would like to have it formatted add the following: 
test.dt[, summary_Date := as.Date(summary_Date, origin="1970-01-01")]

結果:

 > test.dt
    ID                Date         Val idlen summary_Date
 1:  1 1962-03-01 12:00:00  0.42646422     3   1962-03-01
 2:  1 1962-03-14 12:00:00 -0.29507148     3   1962-03-01
 3:  1 1962-03-27 12:00:00  0.89512566     3   1962-04-01   <~~~~~
 4:  1 1962-04-10 12:00:00  0.87813349     2   1962-04-01
 5:  1 1962-04-24 12:00:00  0.82158108     2   1962-05-01
 6:  1 1962-05-08 12:00:00  0.68864025     1   1962-05-01


アップデート:

2 つのステップが必要な理由の説明

1 つのステップで実行できない理由は、グループごとに 1 つの値しか得られないという事実に関係しています。その値をグループのメンバーに割り当てると、1 つの要素が多数に割り当てられます。Rそのような状況をうまく処理する方法を知っています:recycling単一の要素。

ただし、この特定のケースでは、リサイクルしたくありません。1むしろ、要素をに適用したくありませんmany。したがって、一意のグループが必要です。これは、2 番目のステップで行うことです。グループの各要素 (行) には、独自の特定の値が割り当てられます。

更新 2:

@Ramnath は、 を使用する素晴らしい提案をしmutateました。を見ると、次のよう?mutateになります。

この関数は変換に非常に似ていますが、変換を繰り返し実行します...後の変換では、以前の変換で作成された列を使用できます

これはまさにあなたがやりたいことです!

于 2013-03-01T19:46:18.167 に答える