【问题标题】:Adding new column using custom function in data frame using dplyr/data.table in R使用 R 中的 dplyr/data.table 在数据框中使用自定义函数添加新列
【发布时间】:2016-12-22 04:40:46
【问题描述】:

我对 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)]

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

谢谢

【问题讨论】:

  • 是的,作为一般规则,您应该尝试编写您的函数,以便不需要单独应用 NROW。 (我不清楚你的函数应该做什么,所以我无法提供更具体的帮助。)
  • 您的示例代码根本不起作用。
  • df3 = grepl(paste0(word, '$'), df2$col1)) 应该是二进制 TRUE/FALSE 。你希望df3$col2 表现如何?
  • 我已经编辑了函数。我希望结果如下
  • 我已经编辑了函数。我希望结果如下 head(df1) col1 col2 col3 A 10 10 B 20 30 C 30 40

标签: r data.table dplyr


【解决方案1】:

如果您想要一个有效的解决方案,我建议您不要使用正则表达式,也不要进行逐行操作。如果您的所有功能都是按最后一个字母加入,您可以在不使用正则表达式的情况下获得后者,然后使用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

【讨论】:

  • 非常感谢。该解决方案非常快
  • @David Arenburg 我喜欢你的回答,因为这个问题是重复的!你摇滚
【解决方案2】:

使用fuzzyjoin 包,我认为您可以完成这项工作。例如:

#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$

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-13
    • 1970-01-01
    • 2020-07-29
    • 2019-11-05
    • 2023-01-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多