使用R中的一些hashmap方法有效地更新数据帧列

ak3*_*t0n 3 performance r data-mining dataframe

我是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
Run Code Online (Sandbox Code Playgroud)

接下来,我将一个名为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
Run Code Online (Sandbox Code Playgroud)

从新表定义中我生成一个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
Run Code Online (Sandbox Code Playgroud)

现在,我正在定义一个新数据集,其中包含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
Run Code Online (Sandbox Code Playgroud)

我的问题:如何有效地创建第三列?目前我正在运行下面的测试,我在地图中查找主题率,如果找到则输入值,否则输入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
Run Code Online (Sandbox Code Playgroud)

但与真正的数据集(20多万行)用类似多列受到计算平均,代码需要很长的时间来运行.有人可能会建议一个更好的方法去做我想要实现的目标吗?也许是一些合并或其他什么,但我没有想法.谢谢.

jor*_*ran 6

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

dfNew$subjectRate <- rateMap$subjectRate[match(dfNew$subject,rateMap$subject)]
Run Code Online (Sandbox Code Playgroud)

因为它主要使用索引和match.我想,这当然有点简单.这将用NAs而不是0.5来填充"新"值,然后可以根据需要填写,

dfNew$subjectRate[is.na(dfNew$subjectRate)] <- newValue
Run Code Online (Sandbox Code Playgroud)

如果这篇ave文章特别慢,那么现在的标准建议是使用data.table包:

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

这可能会吸引一些评论,建议在最后一行中提高数据表聚合的速度.实际上,使用pure data.tables进行合并或连接可能更加流畅(而且速度快),因此您可能也想调查该选项.(请参阅最底层?data.table的一些示例.)