我希望在一个数据框data.1
中选择与第二个数据框keep.these
中的行部分匹配的行,以获得desired.result
。我在这里找到了几个基于一列匹配的问题,但我希望在三列上匹配:STATE
,COUNTY
和CITY
。到目前为止,我已经提出了三种解决方案,但似乎没有一种解决方案。
请注意,每行包含我的真实数据中STATE
,COUNTY
和CITY
的唯一组合。
当我使用merge
时,我必须重新order
。函数match
似乎有效,但我不熟悉它,也不知道我对这个函数的使用是否符合预期。下面的apply
解决方案显然过于复杂。
如果我不需要重新排序结果,merge
方法将是理想的。使用大型数据集进行重新排序可能非常耗时。如果有人能证实这是一种合理的方法,match
方法似乎没问题。
是否有更好的解决方案,最好是在R
基地?
data.1 <- read.table(text= "
CITY COUNTY STATE AA
1 1 1 2
2 1 1 4
1 2 1 6
2 2 1 8
1 1 2 20
2 1 2 40
1 2 2 60
2 2 2 80
1 1 3 200
2 1 3 400
1 2 3 600
2 2 3 800
1 1 4 2000
2 1 4 4000
1 2 4 6000
2 2 4 8000
1 1 5 20000
2 1 5 40000
1 2 5 60000
2 2 5 80000
", header=TRUE, na.strings=NA)
keep.these <- read.table(text= "
CITY COUNTY STATE BB
1 1 2 -10
2 1 2 -11
1 2 2 -12
2 2 2 -13
1 1 4 -14
2 1 4 -15
1 2 4 -16
2 2 4 -17
", header=TRUE, na.strings=NA)
desired.result <- read.table(text= "
CITY COUNTY STATE AA
1 1 2 20
2 1 2 40
1 2 2 60
2 2 2 80
1 1 4 2000
2 1 4 4000
1 2 4 6000
2 2 4 8000
", header=TRUE, na.strings=NA)
##########
# this works, but I need to reorder
new.data.a <- merge(keep.these[,1:3], data.1, by=c('CITY', 'COUNTY', 'STATE'))
new.data.a <- new.data.a[order(new.data.a$STATE, new.data.a$COUNTY, new.data.a$CITY),]
rownames(desired.result) <- NULL
rownames(new.data.a) <- NULL
all.equal(desired.result, new.data.a)
##########
# this seems to work, but match is unfamiliar
new.data.2 <- data.1[match(data.1$CITY , keep.these$CITY , nomatch=0) &
match(data.1$STATE , keep.these$STATE , nomatch=0) &
match(data.1$COUNTY, keep.these$COUNTY, nomatch=0),]
rownames(desired.result) <- NULL
rownames(new.data.2) <- NULL
all.equal(desired.result, new.data.2)
##########
# this works, but is too complex
data.1b <- data.frame(my.group = apply( data.1[,1:3], 1, paste, collapse = "."), data.1)
keep.these.b <- data.frame(my.group = apply(keep.these[,1:3], 1, paste, collapse = "."), keep.these)
data.1b <- data.1b[apply(data.1b, 1, function(x) {x[1] %in% keep.these.b$my.group}),]
data.1b <- data.1b[,-1]
rownames(desired.result) <- NULL
rownames(data.1b) <- NULL
all.equal(desired.result, data.1b)
##########
答案 0 :(得分:3)
与重新排序相比,我不确定这在时间方面会如何做,但您只需添加合并选项即可更改排序。
new.data.a <- merge(keep.these[,1:3], data.1, by=c('CITY', 'COUNTY', 'STATE'), sort = FALSE)
rownames(desired.result) <- NULL
rownames(new.data.a) <- NULL
all.equal(desired.result, new.data.a)
答案 1 :(得分:3)
以下是针对此类问题的通用解决方案:
data.1.ID <- paste(data.1[,1],data.1[,2],data.1[,3])
keep.these.ID <- paste(keep.these[,1],keep.these[,2],keep.these[,3])
desired.result <- data.1[data.1.ID %in% keep.these.ID,]
我只是为每条记录创建了一个唯一的ID,然后进行了搜索。 注意:这将更改行名称,您可能需要添加以下内容:
row.names(desired.result) <- 1:nrow(desired.result)
修改强>
这是解决同样问题的另一种方法。
如果你有一个非常大的数据集,比如数百万行,另一个非常有效的解决方案是使用包data.table
。它的工作速度比merge
快近50-100倍,具体取决于您拥有的数据量。
您需要做的就是:
library(data.table)
第1步:将data.frame
转换为data.table
,前三列作为键。
d1 <- data.table(data.1, key=names(data.1)[1:3])
kt <- data.table(keep.these, key=names(keep.these)[1:3])
步骤2:使用data.table
的二分搜索进行合并:
d1[kt]
注1:执行简单。 注意2:这将按键对数据进行排序。为避免这种情况,请尝试以下操作:
data.1$index <- 1:nrow(data.1) # Add index to original data
d1 <- data.table(data.1,key=names(data.1)[1:3]) # Step1 as above
kt <- data.table(keep.these,key=names(keep.these)[1:3]) # Step1 as above
d1[kt][order(index)] # Step2 as above
如果你想删除最后两列(index
,BB
),那也是直截了当的:
d1[kt][order(index)][,-(5:6),with=F] #Remove index
尝试使用大型数据集,并将时间与merge
进行比较。它通常快50到100倍。
要详细了解data.table
,请尝试:
vignette("datatable-intro")
vignette("datatable-faq")
vignette("datatable-timings")
或者看到它的实际效果:
example(data.table)
希望这会有所帮助!!