在数据帧上聚合lowess()

时间:2012-11-02 20:57:15

标签: r aggregate

所以我有一个包含四列的数据框:课程ID,用户ID,日(整数)和收到的累积点数。我想要做的是,对于每个用户课程对,使用lowess来平滑课程所有日子的累积分数。 lowess函数采用向量,应用平滑算法,然后返回两个向量xy ...我只对y向量感兴趣。< / p>

我的第一个想法是

aggregate(df$CumulativePointsReceived, 
          list(df$UserID, df$CourseID),
          function(x) lowess(x)$y)

但是返回一个基本上无法使用的数据帧,其中第三列是这些向量的列表。我想要的是一个与输入df完全相同的数据帧,但是每个用户课程日都有一列平滑点值。我确信有一种非循环方式可以做到这一点,但我似乎无法以正确的方式思考它。提前谢谢......

这是原始df中第一个用户课程对的输入。我会增加更多,但是每个用户课程都需要110天才会变得非常大。

structure(list(CourseID = c(6567146L, 6567146L, 6567146L, 6567146L,
6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L,
6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L,
6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L,
6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L,
6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L,
6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L,
6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L,
6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L,
6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L,
6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L,
6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L,
6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L,
6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L,
6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L,
6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L, 6567146L,
6567146L), UserID = c(4759679L, 4759679L, 4759679L, 4759679L,
4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L,
4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L,
4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L,
4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L,
4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L,
4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L,
4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L,
4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L,
4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L,
4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L,
4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L,
4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L,
4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L,
4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L,
4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L, 4759679L,
4759679L), DayInCourse = 1:110, CumulativePointsReceived = c(0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 107, 107, 107, 107, 107, 107, 107, 107, 107,
107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107)), .Names =     c("CourseID",
"UserID", "DayInCourse", "CumulativePointsReceived"), row.names =     c(46085L,
46118L, 46120L, 46133L, 46102L, 46086L, 46182L, 46184L, 46159L,
46139L, 46088L, 46090L, 46144L, 46161L, 46187L, 46113L, 46177L,
46193L, 46151L, 46143L, 46126L, 46121L, 46104L, 46170L, 46128L,
46131L, 46167L, 46098L, 46127L, 46178L, 46101L, 46129L, 46152L,
46175L, 46093L, 46122L, 46096L, 46136L, 46106L, 46116L, 46148L,
46173L, 46189L, 46117L, 46172L, 46162L, 46164L, 46108L, 46091L,
46112L, 46135L, 46181L, 46190L, 46171L, 46169L, 46100L, 46141L,
46103L, 46168L, 46110L, 46107L, 46089L, 46154L, 46165L, 46125L,
46163L, 46147L, 46166L, 46183L, 46160L, 46150L, 46097L, 46115L,
46157L, 46194L, 46138L, 46188L, 46153L, 46155L, 46179L, 46180L,
46191L, 46095L, 46176L, 46111L, 46105L, 46142L, 46087L, 46109L,
46158L, 46145L, 46114L, 46192L, 46140L, 46146L, 46174L, 46094L,
46124L, 46149L, 46119L, 46186L, 46130L, 46134L, 46156L, 46185L,
46099L, 46123L, 46137L, 46132L, 46092L), class = "data.frame")

2 个答案:

答案 0 :(得分:3)

您可以使用基本R功能执行此操作。 E.g。

lapply(split(df, list(df$UserID, df$CourseID)),
       function(x) with(x, lowess(DayInCourse, CumulativePointsReceived))$y)

返回:

$`4759679.6567146`
  [1]  40.92152  42.50447  44.08898  45.67481  47.26167  48.84919
  [7]  50.43697  52.02450  53.61120  55.19639  56.77928  58.35896
 [13]  59.93435  61.50424  63.06724  64.62175  66.16596  67.69780
 [19]  69.21547  70.71909  72.20948  73.68773  75.15522  76.61367
 [25]  78.06516  79.51217  80.95767  82.40508  83.85843  85.32230
 [31]  86.80193  88.30315  89.83235  91.39619  93.00115  94.65248
 [37]  96.35240  98.75650 100.73124 102.31467 103.55841 104.51780
 [43] 105.24556 105.78855 106.18658 106.47246 106.67275 106.80862
 [49] 106.89685 106.95067 106.98051 106.99458 106.99936 107.00000
 [55] 107.00000 107.00000 107.00000 107.00000 107.00000 107.00000
 [61] 107.00000 107.00000 107.00000 107.00000 107.00000 107.00000
 [67] 107.00000 107.00000 107.00000 107.00000 107.00000 107.00000
 [73] 107.00000 107.00000 107.00000 107.00000 107.00000 107.00000
 [79] 107.00000 107.00000 107.00000 107.00000 107.00000 107.00000
 [85] 107.00000 107.00000 107.00000 107.00000 107.00000 107.00000
 [91] 107.00000 107.00000 107.00000 107.00000 107.00000 107.00000
 [97] 107.00000 107.00000 107.00000 107.00000 107.00000 107.00000
[103] 107.00000 107.00000 107.00000 107.00000 107.00000 107.00000
[109] 107.00000 107.00000

我们可以修改此方法以包含转换步骤:

out <- lapply(split(df, list(df$UserID, df$CourseID)),
              function(x) transform(x, smooth = lowess(DayInCourse,         
                                    CumulativePointsReceived)$y))

> head(out[[1]])
      CourseID  UserID DayInCourse CumulativePointsReceived   smooth
46085  6567146 4759679           1                        0 40.92152
46118  6567146 4759679           2                        0 42.50447
46120  6567146 4759679           3                        0 44.08898
46133  6567146 4759679           4                        0 45.67481
46102  6567146 4759679           5                        0 47.26167
46086  6567146 4759679           6                        0 48.84919

由于您只提供了一个课程/用户组合,因此结果是一个只包含一个组件的列表。在现实世界的示例中,列表将包含更多组件。在这种情况下做

final <- do.call(rbind, out)

aggregate()步失败的原因是您要传递lowess()数据框,并且它需要两个向量xy。我不认为这是正确的做法。除非您想学习 plyr ,否则手动进行拆分 - 应用组合将是您的选择。

答案 1 :(得分:1)

我认为使用plyr

会更容易
df <- ddply(df, .(CourseID, UserID), transform,
        smoothed = lowess(DayInCourse, CumulativePointsReceived)$y)

plyr的一般哲学是“分裂 - 应用 - 结合”。 ddply函数的语法(它接受一个数据框并返回一个数据框 - 还有其他函数用于数组或列表)

ddply(dataframe, field-list, function, function-args)

然后,该函数将数据帧拆分为行块,其中field-list中指定的所有字段值都相同。然后,它接受每个块并应用function以及任何其他function-args,然后将这些函数调用的结果合并到一个数据框中。

以下是一个例子:

ddply(mtcars, "cyl", colMeans)

在这种情况下,colMeans是一个函数,它取数据框中每列的平均值,因此对cyl的每个值分别采用均值。

您也可以指定自己的功能:

ddply(mtcars, "cyl", function(df) c(hp.mean=mean(df$hp), hp.sd=sd(df$hp)))

现在解释transformtransform是一个方便的函数,用于向数据框添加新列而不会出现难看的索引。比较以下两个相同的电话:

Orange$score <- Orange$age * Orange$circumference^2

Orange <- transform(Orange, score = age * circumference^2)

第二个版本更易于阅读且不易出错。从这个例子中可以看出,transform的语法是

tranform(dataframe, myname2 = some-value, myname2 = some-other-value)

等等。

当用作transform中的函数调用时,

plyr真正自成一体。在上面给出的示例中,smoothed = lowess(DayInCourse, CumulativePointsReceived)$y)只是传递给转换的附加参数,因此对于拆分数据框中的每个块xddplytransform应用为

transform(x, smoothed = lowess(DayInCourse, CumulativePointsReceived)$y))

然后结合结果。