【问题标题】:Update dataframe column efficiently using some hashmap method in R使用 R 中的一些 hashmap 方法有效地更新数据框列
【发布时间】:2012-02-04 18:20:17
【问题描述】:

我是 R 新手,无法弄清楚我在下面的代码中可能做错了什么以及如何加快它的速度。 我有一个数据集,想添加一个包含从两列数据计算的平均值的列。请查看下面的代码(警告:阅读我的问题可能需要一些时间,但代码在 R 中运行良好):

首先让我定义一个数据集df(再次为代码的冗长描述道歉)

> df<-data.frame(prediction=sample(c(0,1),10,TRUE),subject=sample(c("car","dog","man","tree","book"),10,TRUE))
> df
   prediction subject
1           0     man
2           1     dog
3           0     man
4           1    tree
5           1     car
6           1    tree
7           1     dog
8           0    tree
9           1    tree
10          1    tree

接下来我将一个名为 subjectRate 的新列添加到 df

df$subjectRate <- with(df,ave(prediction,subject))
> df
       prediction subject subjectRate
    1           0     man         0.0
    2           1     dog         1.0
    3           0     man         0.0
    4           1    tree         0.8
    5           1     car         1.0
    6           1    tree         0.8
    7           1     dog         1.0
    8           0    tree         0.8
    9           1    tree         0.8
    10          1    tree         0.8

从新的表定义中,我生成一个 rateMap 以便自动填充新数据,其中 subjectRate 列使用先前获得的平均值初始化。

rateMap <- df[!duplicated(df[, c("subjectRate")]), c("subject","subjectRate")]
> rateMap
  subject subjectRate
1     man         0.0
2     dog         1.0
4    tree         0.8

现在我正在定义一个新的数据集,其中结合了 df 中的旧主题和新主题

> dfNew<-data.frame(prediction=sample(c(0,1),15,TRUE),subject=sample(c("car","dog","man","cat","book","computer"),15,TRUE))
> dfNew
   prediction  subject
1           1      man
2           0      cat
3           1 computer
4           0      dog
5           0     book
6           1      cat
7           1      car
8           0     book
9           0 computer
10          1      dog
11          0      cat
12          0     book
13          1      dog
14          1      man
15          1      dog

我的问题:如何有效地创建第三列?目前我正在运行下面的测试,我在地图中查找主题率,如果找到则输入该值,否则输入 0.5。

> all_facts<-levels(factor(rateMap$subject))
> dfNew$subjectRate <-  sapply(dfNew$subject,function(t) ifelse(t %in% all_facts,rateMap[as.character(rateMap$subject) == as.character(t),][1,"subjectRate"],0.5))
> dfNew
   prediction  subject subjectRate
1           1      man         0.0
2           0      cat         0.5
3           1 computer         0.5
4           0      dog         1.0
5           0     book         0.5
6           1      cat         0.5
7           1      car         0.5
8           0     book         0.5
9           0 computer         0.5
10          1      dog         1.0
11          0      cat         0.5
12          0     book         0.5
13          1      dog         1.0
14          1      man         0.0
15          1      dog         1.0

但是对于具有类似于 subject 的多列的真实数据集(超过 200,000 行)来计算平均值,代码需要很长时间才能运行。有人可以建议一个更好的方法来做我想要实现的目标吗?也许有些合并或什么,但我没有想法。 谢谢。

【问题讨论】:

    标签: r performance dataframe data-mining


    【解决方案1】:

    我怀疑(但不确定,因为我没有测试过)这会更快:

    dfNew$subjectRate <- rateMap$subjectRate[match(dfNew$subject,rateMap$subject)]
    

    因为它主要只使用索引和match。我认为它肯定更简单一些。这将用NAs 填充“新”值,而不是 0.5,然后可以随意填充,

    dfNew$subjectRate[is.na(dfNew$subjectRate)] <- newValue
    

    如果ave 块特别慢,那么这些天的标准建议是使用 data.table 包:

    require(data.table)
    dft <- as.data.table(df)
    setkeyv(dft, "subject")
    dft[, subjectRate := mean(prediction), by = subject]
    

    这可能会吸引一些 cmets 提出如何从最后一行中的数据表聚合中加快速度的方法。实际上,使用纯 data.tables 进行合并或加入可能会更灵活(而且速度更快),因此您可能还想研究该选项。 (请参阅?data.table 的最底部以获取大量示例。)

    【讨论】:

    • 非常感谢。到目前为止,我只使用了您发布的前两个代码 sn-ps,现在处理所有内容实际上只需要不到一秒钟的时间。我也一定会看看 data.table。
    • 嗨。我当时错过了这个。实现:= by group 时,最后一行会更快更优雅:dft[,subjectRate:=mean(prediction),by=subject]
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-17
    • 2018-09-11
    • 1970-01-01
    • 2016-08-21
    • 2013-10-21
    • 1970-01-01
    相关资源
    最近更新 更多