2

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

我的第一个想法是

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

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

这是原始 df 中第一个用户课程对的 dput。我会放更多,但每个用户课程需要 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")
4

2 回答 2

3

您可以使用基本 R 函数来执行此操作。例如

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 ,否则手动进行拆分-应用-组合将是可行的方法。

于 2012-11-02T21:42:17.253 回答
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)

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

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

等等。

transform当用作plyr. 在我上面给出的示例中,smoothed = lowess(DayInCourse, CumulativePointsReceived)$y)只是传递给转换的附加参数,因此对于x拆分数据帧中的每个块,ddply应用transform

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

然后合并结果。

于 2012-11-02T21:12:31.567 回答