【问题标题】:R intersect data.frame on multiple criteriaR在多个标准上与data.frame相交
【发布时间】:2013-03-24 04:42:37
【问题描述】:

我正在尝试根据多个标准上的两个 data.frames 的交集来填充二进制向量。

我的代码可以运行,但我觉得仅获取二进制向量就占用了过多的内存。

当我将代码应用于我的完整数据(40 毫米以上行)时。我开始有记忆问题。

有没有更简单的方法来生成向量?

这是一些样本数据(例如,子样本将只包括完整样本中的 obs):

ob1_1 <- as.data.frame(cbind(c(1999),c("111","222","666","777")),stringsAsFactors=FALSE)
ob2_1 <- as.data.frame(cbind(c(2000),c("111","333","555","777")),stringsAsFactors=FALSE)
ob3_1 <- as.data.frame(cbind(c(2001),c("111","222","333","777")),stringsAsFactors=FALSE)
ob4_1 <- as.data.frame(cbind(c(2002),c("111","444","555","777")),stringsAsFactors=FALSE)

full_sample <-  rbind(ob1_1,ob2_1,ob3_1,ob4_1)
colnames(full_sample) <- c("yr","ID")

ob1_2 <- as.data.frame(cbind(c(1999),c("111","222","777")),stringsAsFactors=FALSE)
ob2_2 <- as.data.frame(cbind(c(2000),c("333")),stringsAsFactors=FALSE)
ob3_2 <- as.data.frame(cbind(c(2001),c("888")),stringsAsFactors=FALSE)
ob4_2 <- as.data.frame(cbind(c(2002),c("111","444","555","777")),stringsAsFactors=FALSE)

sub_sample <-  rbind(ob1_2,ob2_2,ob3_2,ob4_2)
colnames(sub_sample) <- c("yr","ID")

这是我的工作代码:

q_intersect <- ""
q_intersect <- paste(q_intersect , "select       a.yr, a.ID       ", sep=" ")
q_intersect <- paste(q_intersect , "from         full_sample a  ", sep=" ")
q_intersect <- paste(q_intersect , "intersect                     ", sep=" ")
q_intersect <- paste(q_intersect , "select       b.yr, b.ID       ", sep=" ")
q_intersect <- paste(q_intersect , "from         sub_sample b  ", sep=" ")
q_intersect <- trim(gsub(" {2,}", " ", q_intersect ))

intersect_temp <- cbind(sqldf(q_intersect ),1)
colnames(intersect_temp ) <- c("yr","ID","in_both")

q_expand <- ""
q_expand <- paste(q_expand , "select       in_both            ", sep=" ")
q_expand <- paste(q_expand , "from         full_sample a      ", sep=" ")
q_expand <- paste(q_expand , "left join    intersect_temp  b  ", sep=" ")
q_expand <- paste(q_expand , "on           a.yr=b.yr          ", sep=" ")
q_expand <- paste(q_expand , "and          a.ID=b.ID          ", sep=" ")
q_expand <- trim(gsub(" {2,}", " ", q_expand ))

solution <- as.integer(sqldf(q_expand)[,1])
solution [is.na(solution )] <- 0 

提前感谢您的帮助!

【问题讨论】:

  • 你应该用自然语言解释你想要什么。 (你说的代码正在工作只是锁定了我的 R 会话,可能是因为没有 trim 函数?)不,第一个 sqldf 调用将其锁定。
  • @Dwin,我也遇到了同样的锁定问题。但仅在 q_intersect 部分的前 4 行内。顺便说一句,布拉德,在您之前的问题中,您使用的是data.table,而这里您使用的是data.frame。这是故意的吗?
  • @RicardoSaporta 嗨。刚刚未标记的 data.table。请参阅昨天在聊天室中纠正我的讨论。可能会进行更大的取消标记扫描。 SO 观点是标签是用于问题而不是答案。以全新的眼光,我现在看到并同意搜索“[data.table] data.table is:question”就是“[data.table]”单独的样子。但是,使用data.table 标记接受的答案似乎还可以(见聊天),其中投票数>10。要使用 data.table 搜索答案,我们可以使用“[r] -[data.table] data.table is:answer”。
  • @MatthewDowle,很高兴知道。感谢您指出这一点。

标签: r memory intersect sqldf


【解决方案1】:

目前尚不清楚您要完成什么,但我相信这样的事情会简单得多。

library(data.table)
fullDT <- data.table(full_sample, key=c("yr", "ID"))
subDT  <- data.table(sub_sample,  key=c("yr", "ID"))

fullDT[ , intersect := 0L]
fullDT[subDT, intersect := 1, nomatch=0]

这个想法是您将每个data.tablekey 设置为您想要相交的列。当您调用full[sub], nomatch=0] 时,您将获得内部连接,我们仅将这些值设置为1;内部连接中未标识的值保留为0,如前行中设置的那样。

fullDT
#        yr  ID intersect
#   1: 1999 111         1
#   2: 1999 222         1
#   3: 1999 666         0
#   4: 1999 777         1
#   5: 2000 111         0
#   6: 2000 333         1
#   7: 2000 555         0
#   8: 2000 777         0
#   9: 2001 111         0
#  10: 2001 222         0
#  11: 2001 333         0
#  12: 2001 777         0
#  13: 2002 111         1
#  14: 2002 444         1
#  15: 2002 555         1
#  16: 2002 777         1

【讨论】:

  • 里卡多,这看起来不错。我使用 data.frames 创建示例数据,但如果可能,我更喜欢 data.tables。
  • 这绝对比我的方法简单得多。再次感谢您!
  • @Brad,完全没有问题。我在上面的 cmets 中询问,仅仅是因为它使问题变得容易得多。
  • 您可以通过为整个数据集设置intersect :=0(在设置连接到1 的子集之前)来加快速度。
  • @RicardoSaporta -- 您可能还需要稍微改写您的描述。
【解决方案2】:

更简单的 SQL 我推测您希望创建一个与 full_sample 具有相同行数的单列数据框,以便输出中的给定行包含 1,如果 @ 中的相应行987654323@ 具有匹配的 sub_sample 行,否则为 0。

在这种情况下,可以将多个 SQL 语句压缩为一个更简单的 SQL 语句,如下所示。左连接确保包含full_sample 的所有行,自然连接导致连接发生在两个输入数据帧之间共有的所有列名上。

sqldf("select s.yr is not null as solution 
       from full_sample f natural left join sub_sample s")

(顺便提一下,字符串字面量可以跨越多行,如图所示,因此不需要将多行粘贴在一起。)

Out of Memory Database 默认情况下,sqldf 使用内存数据库,但您可以通过 dbname= 参数指定文件名(不需要提前存在)以用作 out of内存数据库。这样你就不会被内存限制了。

sqldf("select s.yr is not null as solution 
       from full_sample f natural left join sub_sample s", dbname = "mydb")

(在某些情况下,您还可以通过使用索引来提高性能。有关示例,请参见sqldf home page。)

更新:添加了更简单的 sql 解决方案

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-31
    • 2017-08-16
    • 2014-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-24
    • 2020-03-08
    相关资源
    最近更新 更多