gpt4 book ai didi

r - 如何有效地合并两个数据集?

转载 作者:IT王子 更新时间:2023-10-28 23:37:05 26 4
gpt4 key购买 nike

我正在尝试通过一个通用 ID 合并两个相当大的数据集 - 但并不荒谬(360,000 X 4、57,000 X 4) - 数据集。我尝试了常规的 merge()merge.data.table()sqldf()。每次我一直用完内存(cannot allocate vector of size...)。有什么解决办法吗?还是 R 是一个糟糕的数据合并工具? head() 如下(我正在尝试合并 STUDENT.NAME):

  ID10    STUDENT.NAME   FATHER.NAME MOTHER.NAME
1 1 DEEKSHITH J JAYANNA SWARNA
2 4 MANIKANTHA D DEVARAJ MANJULA
3 5 NAGESH T THIMMAIAH N SHIVAMMA
4 6 NIZAMUDDIN R NOOR MOHAMMED BIBI
5 7 PRABHU YELLAPPA YELLAPPA MALLAMMA
6 8 SADDAM PASHA NISAR AHMED ZAREENA

最佳答案

从您的问题的性质来看,您肯定是在进行多对多的合并,其中每个学生在每个数据帧中出现多次。您可能想检查多少次。如果每个学生在每个数据框中出现两次,这意味着一个学生将做 4 行。如果一个学生出现 10 次,则合并将添加 100 行。首先检查您将获得多少行。这是我使用的函数:

count.rows <- function(x,y,v,all=FALSE){
tx <- table(x[[v]])
ty <- table(y[[v]])
val <- val <- names(tx)[match(names(tx),names(ty),0L) > 0L]
cts <- rbind(tx[match(val,names(tx))],ty[match(val,names(ty))])
colnames(cts) <- val
sum(apply(cts,2,prod,na.rm=all),na.rm=TRUE)
}
count.rows(DF1,DF2,"STUDENT.NAME")

如果您按照您的要求去做(阅读 R 文档),您会发现复杂性取决于答案的长度。这不是由于合并算法本身,而是所有结果的绑定(bind)在一起。如果你真的想要一个更少的内存消耗解决方案,你尤其需要摆脱这种绑定(bind)。以下算法为您做到这一点。我把它写出来,以便您找到逻辑,并且可以对其进行优化。请注意,它不会给出相同的结果,它会复制两个数据帧的 all 列。所以你可能想稍微调整一下。

mymerge <- function(x,y,v,count.only=FALSE){
ix <- match(v,names(x))
iy <- match(v,names(y))

xx <- x[,ix]
yy <- y[,iy]
ox <- order(xx)
oy <- order(yy)
xx <- xx[ox]
yy <- yy[oy]

nx <- length(xx)
ny <- length(yy)

val <- unique(xx)
val <- val[match(val,yy,0L) > 0L]
cts <- cbind(table(xx)[val],table(yy)[val])
dimr <- sum(apply(cts,1,prod),na.rm=TRUE)

idx <- vector("numeric",dimr)
idy <- vector("numeric",dimr)
ndx <- embed(c(which(!duplicated(xx)),nx+1),2)[unique(xx) %in% val,]
ndy <- embed(c(which(!duplicated(yy)),ny+1),2)[unique(yy) %in% val,]

count = 1
for(i in 1:nrow(ndx)){
nx <- abs(diff(ndx[i,]))
ny <- abs(diff(ndy[i,]))
ll <- nx*ny

idx[count:(count+ll-1)] <-
rep(ndx[i,2]:(ndx[i,1]-1),ny)

idy[count:(count+ll-1)] <-
rep(ndy[i,2]:(ndy[i,1]-1),each=nx)
count <- count+ll
}
x <- x[ox[idx],]
names(y) <- paste("y.",names(y),sep="")
x[names(y)] <- y[oy[idy],]
rownames(x) <- 1:nrow(x)
x
}

一些测试代码,以便您可以看到它的工作原理:

DF1 <- data.frame(
ID = 1:10,
STUDENT.NAME=letters[1:10],
SCORE = 1:10
)
id <- c(3,11,4,6,6,12,1,4,7,10,5,3)
DF2 <- data.frame(
ID = id,
STUDENT.NAME=letters[id],
SCORE = 1:12
)

mymerge(DF1,DF2,"STUDENT.NAME")

对两个包含 50 万行和 4 列的数据帧执行相同操作,每个学生姓名最多匹配 10 个,它会返回一个包含 580 万行和 8 列的数据帧,并在内存中显示以下图片:

enter image description here

黄色框是合并调用,绿色框是 mymerge 调用。内存范围从 2.3Gb 到 3.74Gb,因此合并调用使用 1.45 Gb,而 mymerge 则略高于 0.8 Gb。仍然没有“内存不足”错误...测试代码如下:

Names <- sapply(
replicate(120000,sample(letters,4,TRUE),simplify=FALSE),
paste,collapse="")

DF1 <- data.frame(
ID10 = 1:500000,
STUDENT.NAME = sample(Names[1:50000],500000,TRUE),
FATHER.NAME = sample(letters,500000,TRUE),
SCORE1 = rnorm(500000),
stringsAsFactors=FALSE
)

id <- sample(500000,replace=TRUE)
DF2 <- data.frame(
ID20 = DF1$ID10,
STUDENT.NAME = DF1$STUDENT.NAME[id],
SCORE = rnorm(500000),
SCORE2= rnorm(500000),
stringsAsFactors=FALSE
)
id2 <- sample(500000,20000)
DF2$STUDENT.NAME[id2] <- sample(Names[100001:120000],20000,TRUE)

gc()
system.time(X <- merge(DF1,DF2,"STUDENT.NAME"))
Sys.sleep(1)
gc()
Sys.sleep(1)
rm(X)
gc()
Sys.sleep(3)
system.time(X <- mymerge(DF1,DF2,"STUDENT.NAME"))
Sys.sleep(1)
gc()
rm(X)
gc()

关于r - 如何有效地合并两个数据集?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7441188/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com