使用R中的dplyr / data.table在数据框中使用自定义函数添加新列

时间:2016-12-22 04:40:46

标签: r data.table dplyr

我对R编程相对较新,并试图找出如何使用自定义函数以内存有效方式使用dplyrdata.table来评估数据框的新列。有人可以帮忙吗

以下是我的问题的简要总结

数据框1和2具有相同的类型和列数

df1 <- data.frame(col1 = c("A", "B", "C"), col2 = c(10,20,30))
df2 <- data.frame(col1 = c("DA", "EE", "FB", "C"), col2 = c(10,20,30,40))

这些数据框有数百万条记录。

现在我想通过使用df2中的值将一个新列添加到其中一个数据框(比如df1)。

library(dplyr)

calculateCol3 <- function(word) {
df2 %>%
    filter(grepl(paste0(word, "$"),col1) )%>%
    summarize(col3= sum(col2))
col3
}

df1 %>% group_by(col1) %>% mutate(col3 = calcualteCol3(col1))

这种方法有效,但速度很慢,我想这是因为复制数据集太多次了。有人可以建议一个更好的方法吗?预期结果是:

col1 col2 col3
   A   10   10
   B   20   30
   C   30   40 

我也尝试将数据帧转换为data.table,如下所示

dt1 <- data.table(df1)
dt2 <- data.table(df2)

dt1[, col3 := calculateCol3(col1)}, by = 1:nrow(dt1)]

一切似乎都很慢。我确定有更好的方法来实现这一目标。有人可以帮忙吗

由于

2 个答案:

答案 0 :(得分:3)

如果您想要一个有效的解决方案,我建议您不要使用正则表达式,也不要进行逐行操作。如果您的所有函数都是通过最后一个字母加入,那么您可以在不使用正则表达式的情况下获取后者,然后使用data.table进行二进制连接(为了提高效率)

library(data.table)
setDT(df2)[, EndWith := substring(col1, nchar(as.character(col1)))]
setDT(df1)[df2, col3 := i.col2, on = .(col1 = EndWith)]
df1
#    col1 col2 col3
# 1:    A   10   10
# 2:    B   20   30
# 3:    C   30   40

现在,通过查看您的函数,您似乎也尝试对每个联接df2$col2中的值求和。没问题,您也可以在data.table中进行二进制连接时运行函数。让我们说这是你的df2(只是为了说明你每封信的价值超过一个值)

df2 <- data.frame(col1 = c("DA", "FA", "EE", "FB", "C", "fC"), col2 = c(10,20,10,30,40,30))
df2
#   col1 col2
# 1   DA   10
# 2   FA   20
# 3   EE   10
# 4   FB   30
# 5    C   40
# 6   fC   30

第一步是相同的

setDT(df2)[, EndWith := substring(col1, nchar(as.character(col1)))]

虽然第二步将涉及二进制连接 - 只是以相反的方式,同时添加, by = .EACHI并指定所需的功能

setDT(df2)[df1, .(col2 = i.col2, col3 = sum(col2)), on = .(EndWith = col1), by = .EACHI]
#    EndWith col2 col3
# 1:       A   10   30
# 2:       B   20   30
# 3:       C   30   70

答案 1 :(得分:0)

使用fuzzyjoin包,我认为你可以做到这一点。 E.g:

#install.packages("fuzzyjoin")
df1$col1regex <- paste0(df1$col1,"$")
regex_join(df2, df1, by=c(col1="col1regex"), mode="right")

#  col1.x col2.x col1.y col2.y col1regex
#1     DA     10      A     10        A$
#2     FB     30      B     20        B$
#3      C     40      C     30        C$