匹配两个数据帧并提取最大值

时间:2017-08-16 17:08:37

标签: r performance dataframe max

我有两张桌子:

df_workingFile

      group   v   
1      a    110 
2      a    90 
3      b    57 
4      b    53  

df_groupIDs

  group   
1      a 
2      b  

我想将df_workingFile的最大值从组标签中提取到df_groupIDs

df_groupIDs

  groups   max
1      a   110
2      b    57

我有代码可以做到这一点,但是对于大型数据集来说它确实很慢。

data.frame(df_groupIDs, maxValue = 
   sapply(df_groupIDs$group, function(newCol) 
   max(subset(df_workingFile, newCol == df_workingFile$group)$v)))

有关如何提高效率的任何建议吗?

3 个答案:

答案 0 :(得分:4)

使用data.table,这是一个“更新连接”:

library(data.table)
setDT(df_groupIDs)
setDT(df_workingFile)

df_groupIDs[ , mx := df_workingFile[.(.SD$group), on=.(group), max(v), by=.EACHI]$V1 ]

#    group  mx
# 1:     a 110
# 2:     b  57

.SD$group部分不是惯用语。它应该是.SD,但有一个open bug preventing that

工作原理

联接的语法是x[i, on=],其中i用于根据x中的规则在on=中查找行。更新的语法是x[, var := expr]。在这里,它们与x[, var := x2[.SD, on=]]类似,其中.SD指的是来自x的数据子集。我们可以等效地将expr写为

df_workingFile[df_groupIDs, on=.(group), max(v), by=.EACHI]$V1

请参阅?data.table中有关by=.EACHI正在做什么的文档。 V1只是计算结果的默认名称(在本例中为max(v))。

性能

  

我有代码可以做到这一点,但是对于大型数据集来说它确实很慢。

这种方法应该相当有效,因为(i)它分配给现有的df_groupIDs表而不是创建一个新表; (ii)它仅计算df_groupIDs中显示的组的最大值(而不是df_workingFile中显示的所有组); (iii)优化分组最大值(见?GForce)。

有关比较时间(更新加入与dplyr,匹配等)的示例,请参阅merge data.frames based on year and fill in missing values

答案 1 :(得分:1)

您可以先df_workingFile计算每个ID的最大值。之后,进行left_join

library(dplyr)

df_max <- df_workingFile %>%
    group_by(group) %>%
    summarise(max = max(v))

df_final <- df_groupIDs %>% left_join(df_max, by = "group")

这是R基础方法。

df_max <- aggregate(v ~ group, data = df_workingFile, FUN = max)

df_final <- merge(df_groupIDs, df_max, by = "group", all.x = TRUE)

答案 2 :(得分:1)

这是一个基本R方法,它使用tapply计算最大值,然后使用transform将它们添加到第二个data.frame,使用match查找正确的索引。

# calculate maximum values
vals <- with(df_workingFile, tapply(v, group, max))
# add new variable
transform(df_groupIDs, max=vals[match(group, names(vals))])
  group max
a     a 110
b     b  57

要添加变量,更标准的表示法是

df_groupIDs$max <- vals[match(df_groupIDs$group, names(vals))]