我正在尝试编写一个函数,该函数将数据框列表和条件列表作为其参数,然后返回这些数据框的列表,其中的列指示这些值在另一个数据框中重复的行 .
例如,我有三个数据帧:
DF1:
Name1 | Zip_code | Data
----- | -------- | ----
George| 123 | abc
----- | -------- | ----
Marge | 456 | def
----- | -------- | ----
Mike | 789 | foo
DF2:
Name | data | zip_code
----- | -------- | --------
Mike | klm | 789
----- | -------- | --------
George| xxx | 123
----- | -------- | --------
Marge | yyy | 456
----- | -------- | --------
Bob | zzz | 678
DF3:
Data | Name | zip_code
----- | -------- | --------
zzz | Bob | 678
----- | -------- | --------
ggg | Mike | 789
假设我只关心哪些名称和邮政编码是重复的,我希望输出看起来像这样:
DF1:
Name1 | Zip_code | Data | row_df2 | row_df3
----- | --------- | ---- | ------- | -------
George| 123 | abc | 2 | NA
----- | --------- | ---- | ------- | -------
Marge | 456 | def | 3 | NA
----- | --------- | ---- | ------- | -------
Mike | 789 | foo | 1 | 2
DF2:
Name | data | zip_code | row_df3
----- | ----- | --------- | -------
Mike | klm | 789 | 2
----- | ----- | --------- | -------
George| xxx | 123 | NA
----- | ----- | --------- | -------
Marge | yyy | 456 | NA
----- | ----- | --------- | -------
Bob | zzz | 678 | 1
每个数据帧之间的列名称并不总是相同的,例如我们可以在一个数据帧中使用“Name”,在另一个数据帧中使用“NameWhole” . 此外,每个数据框中可能有不同数量的列 . 我意识到要比较的数据的顺序从每个数据帧的左到右需要相同,但是否则列之间的内容无关紧要 . 从而,
df1有:
名称| zip_code |数据
df2有:
数据|名称|邮政编码
df3有:
名称|数据|邮政编码
我目前的解决方案如下:
首先,初始化数据帧列表,这是函数的第一个参数:
dflist[[1]] <- df1
dflist[[2]] <- df2
dflist[[3]] <- df3
然后我们初始化条件列表,这是函数的第二个参数 . 由于我们对Names和zip_codes在数据框架中的共同点感兴趣,因此这是:
criterialist[[1]] <- c(1,2)
criterialist[[2]] <- c(1,3)
criterialist[[3]] <- c(2,3)
现在的功能是:
cross_checker <- function(dflist, criterialist){
# Insert an index column indicating the row number to be returned:
for (i in 2:length(dflist)){
dflist[[i]]$index <- 1:nrow(dflist[[i]])
}
# Next we loop over the dataframes with two for-loops:
for (i in 1:length(dflist)-1){
for (j in 2:length(dflist)){
dflist[[i]][,ncol(dflist[[i]])+1] <- merge(dflist[[i]], dflist[[j]], by.x=criterialist[[i]], by.y=criterialist[[j]], all.x=TRUE)$index
}
}
结果我只有一个新的索引列进入df1,有时我的RStudio只打开一个调试窗口 . 我不确定“合并”是否可以解决这个问题,但我还没弄清楚“匹配”是如何工作的 .
我想有一种方法是用for循环来强制它,但我认为这将是非常缓慢的 .
最终的想法是创建一个函数,该函数采用任意数量的数据帧,并使用任意标准来检查重复记录,并使用新列返回这些数据帧,该列指示记录重复的行和数据帧 .
编辑:道歉,我的第一个问题 . 以下是表格的可重现代码:
name1 <- c("George","Marge","Mike")
zip1 <- c(123,456,789)
data1 <- c("abc","def","foo")
df1 <- data.frame(name1,zip1,data1,stringsAsFactors = F)
name2 <- c("Mike","George","Marge","Bob")
data2 <- c("klm","xxx","yyy","zzz")
zip2 <- c(789,123,456,678)
df2 <- data.frame(name2,data2,zip2,stringsAsFactors = F)
data3 <- c("zzz", "ggg")
name3 <- c("Bob","Mike")
zip3 <- c(678,789)
df3 <- data.frame(data3,name3,zip3,stringsAsFactors = F)
编辑2:
我决定添加一个额外的数据帧(所以现在有4个):
name1 <- c("George","Marge","Mike")
zip1 <- c(123,456,789)
data1 <- c("abc","def","foo")
df1 <- data.frame(name1,zip1,data1,stringsAsFactors = F)
name2 <- c("Mike","George","Marge","Bob")
data2 <- c("klm","xxx","yyy","zzz")
zip2 <- c(789,123,456,678)
df2 <- data.frame(name2,data2,zip2,stringsAsFactors = F)
data3 <- c("zzz", "ggg")
name3 <- c("Bob","Mike")
zip3 <- c(678,789)
df3 <- data.frame(data3,name3,zip3,stringsAsFactors = F)
name4<-c("Marge", "George","Bob")
zip4<-c(234,123,678)
data4<-c("ask","bff","hhh")
df4 <- data.frame(name4,zip4,data4,stringsAsFactors = F)
然后我决定尝试以下代码:
cross_checker2 <- function(dflist,criterialist){
returnlist<-list()
looplen1 <- length(dflist)-1
for(i in 1:looplen1){
temp_df1 <- dflist[[i]]
temp_crit1 <- criterialist[[i]]
for(j in (i+1):length(dflist)){
temp_df2 <- dflist[[j]]
temp_crit2 <- criterialist[[j]]
temp_df1 <- merge(temp_df1,temp_df2,by.x=temp_crit1,by.y=temp_crit2,all.x=TRUE)
}
returnlist[[length(returnlist)+1]]<-temp_df1
}
我创建以下列表作为参数传递给函数:
deflista<-list()
deflista[[1]]<-df1
deflista[[2]]<-df2
deflista[[3]]<-df3
deflista[[4]]<-df4
crit1<-c(1,2)
crit2<-c(1,3)
crit3<-c(2,3)
crit4<-c(1,2)
critlist<-list()
critlist[[1]]<-crit1
critlist[[2]]<-crit2
critlist[[3]]<-crit3
critlist[[4]]<-crit4
并称之为:
test <- cross_checker2(deflista,critlist)
除第二个数据帧外,其他所有内容的输出都是正确的 . 第一个数据帧是正确的:
name1 | zip1 | data1 | data2 | data3 | data4
-------| ----- | -------|--------| -------| -------
George | 123 | abc | xxx | <NA> | bff
-------| ------| -------| -------| -------| --------
Marge | 456 | def | yyy | <NA> | <NA>
------ | ------ | ------ | ------ | ------ | ------
Mike | 789 | foo | klm | ggg | <NA>
现在第二个:
name2 | data2 | zip2 | data3 | data4
------ | ------ | ------ | ------ | ------
Bob | zzz | 678 | zzz | <NA>
------ | ------ | ------ | ------ | -------
George | xxx | 123 | <NA> | <NA>
----- | ------ | ------ | ------ | ------
Marge | yyy | 456 | <NA> | <NA>
----- | ------ | ------ | ------ | ------
Mike | klm | 789 | ggg | <NA>
这是不正确的,因为乔治和鲍勃在最后一个数据帧(deflista [[4]])存在,但由于某种原因合并不返回那些 .
第三个数据帧:
name3 | zip3 | data3 | data4
------ | ------ | ------- | ------
Bob | 678 | zzz | hhh
----- | ------ | ------- | --------
Mike | 789 | ggg | <NA>
这是正确的,因为Bob是在最后一个数据帧中找到的(deflista [[4]])
我无法弄清楚for循环有什么问题,因为在比较一堆中的第二个数据帧时必须有一些索引问题 . 有任何想法吗?
出于这些目的,我省去了返回找到的条目的行索引,但是我可以在我弄清楚它有什么问题时立即添加它 . 此外,更喜欢基础库中的任何解决方案 .
2 回答
我相信,到目前为止,我已经修复了原始问题中的循环,它们返回了预期的结果:
[[2]]
name2 data2 zip2 index row_df3
1 Mike klm 789 1 2
2 George xxx 123 2 NA
3 Marge yyy 456 3 NA
4 Bob zzz 678 4 1
[[3]]
data3 name3 zip3索引
1 zzz Bob 678 1
2 ggg Mike 789 2
请注意,这是检查3个数据帧的预期结果(在问题的Edit2之前) .
有几个缺陷导致原始代码中断:
第二个
for
循环中的循环限制定义不正确:for (i in 1:length(dflist)-1){
. 这里,:
运算符优先,因此索引从0
开始,这会导致错误 . 这可以通过另外一对paranthesesfor (i in 1:(length(dflist)-1)){
来修复,甚至可以通过使用seq_len()
函数更好地修复for (i in seq_len(length(dflist)-1)) {
merge()
返回两列index.x
和index.y
. 它只返回单个index
列,以便与df1
合并,其中OP不遗余力地添加索引列 .merge()
的结果需要在追加之前按index.x
排序 .双
for
循环导致数据帧与其自身的比较 . 相反,combn()
函数用于查找所有唯一组合 .谢谢你的反馈!
道歉,我想当我编辑我的原始帖子时,它删除了我收到的一些输入 . 我不知道会那样做 .
但是,我为此设置了一个解决方案,其中一个最重要的是合并,因为我没有意识到它会改变列和行的顺序 .
无论如何,这有效: