R 合并具有部分id的数据帧
假设我有两个数据帧:R 合并具有部分id的数据帧,r,merge,dataframe,match,partial,R,Merge,Dataframe,Match,Partial,假设我有两个数据帧: > df1 <- data.frame(name = c('John Doe', 'Jane F. Doe', 'Mark Smith Simpson', 'Sam Lee')) > df1 name 1 John Doe 2
> df1 <- data.frame(name = c('John Doe',
'Jane F. Doe',
'Mark Smith Simpson',
'Sam Lee'))
> df1
name
1 John Doe
2 Jane F. Doe
3 Mark Smith Simpson
4 Sam Lee
> df2 <- data.frame(family = c('Doe', 'Smith'), size = c(2, 6))
> df2
family size
1 Doe 2
2 Smith 6
>df1 df1
名称
1无名氏
2简·F·多伊
3马克·史密斯·辛普森
4李山姆
>df2 df2
家庭规模
1能源部2
2史密斯6
我想合并两个数据帧以获得以下结果:
name family size
1 John Doe Doe 2
2 Jane F. Doe Doe 2
3 Mark Smith Simpson Smith 6
4 Sam Lee <NA> NA
名称族大小
约翰·多伊
简·F·多伊
3马克·史密斯·辛普森·史密斯6
4山姆李娜
但除了以下非常复杂的解决方案外,我无法找到解决方法,因为我的真实数据中有100多个“姓氏”:
>df3这里有一个策略,您可以使用lappy
和grep
匹配所有的姓氏。这将在任何位置找到它们。首先让我定义一个helper函数
transindex<-function(start=1) {
function(x) {
start<<-start+1
ifelse(x, start-1, NA)
}
}
从内部开始计算,我在df2
和grep
中循环所有的姓氏,查找这些值(在模式中添加“\b”,以便匹配整个单词)grepl
将返回一个逻辑向量(真/假)。然后,我应用上述辅助函数transindex()
将这些向量更改为匹配的df2
行的索引,或NA
。因为一行可能匹配多个族,所以我只需使用coalesce
helper函数选择第一个族
我不能将df1
中的行与df2
中的行进行匹配,我可以将它们与
cbind(df1, size=df2[idx,])
name family size
# 1 John Doe Doe 2
# 1.1 Jane F. Doe Doe 2
# 2 Mark Smith Simpson Smith 6
# NA Sam Lee <NA> NA
cbind(df1,size=df2[idx,])
姓名家庭规模
#约翰·多伊
#1.1简·F·多伊2
#2马克·史密斯·辛普森·史密斯6
#李娜
您不必尝试使用正则表达式和部分匹配,而是可以将姓名拆分为查找表格式,其中人名的每个组成部分都保留在一行中,并与其全名匹配:
df1 <- data.frame(name = c('John Doe',
'Jane F. Doe',
'Mark Smith Simpson',
'Sam Lee'),
stringsAsFactors = FALSE)
df2 <- data.frame(family = c('Doe', 'Smith'), size = c(2, 6),
stringsAsFactors = FALSE)
library(tidyr)
library(dplyr)
str_df <- function(x) {
ss <- strsplit(unlist(x)," ")
data.frame(family = unlist(ss),stringsAsFactors = FALSE)
}
splitnames <- df1 %>%
group_by(name) %>%
do(str_df(.))
splitnames
name family
1 Jane F. Doe Jane
2 Jane F. Doe F.
3 Jane F. Doe Doe
4 John Doe John
5 John Doe Doe
6 Mark Smith Simpson Mark
7 Mark Smith Simpson Smith
8 Mark Smith Simpson Simpson
9 Sam Lee Sam
10 Sam Lee Lee
潜在问题:如果一个人的名字和另一个人的姓相同,你会得到一些不正确的匹配 另一个看起来有效的方法,至少在样本数据中是这样的:
df1name = as.character(df1$name)
df1name
#[1] "John Doe" "Jane F. Doe" "Mark Smith Simpson" "Sam Lee"
regmatches(df1name, regexpr(paste(df2$family, collapse = "|"), df1name), invert = T) <- ""
df1name
#[1] "Doe" "Doe" "Smith" ""
cbind(df1, df2[match(df1name, df2$family), ])
# name family size
#1 John Doe Doe 2
#1.1 Jane F. Doe Doe 2
#2 Mark Smith Simpson Smith 6
#NA Sam Lee <NA> NA
df1name=as.character(df1$name)
df1name
#[1] “John Doe”“Jane F.Doe”“Mark Smith Simpson”“Sam Lee”
regmatches(df1name,regexpr)(粘贴(df2$family,collapse=“|”)df1name,invert=T)对于错误的答案,我深表歉意。我应该向提出问题的用户澄清,而不是假设他们想要姓氏的最后一部分。答案已删除。@pizza不必担心。你实际上指出了我的结果中的一个错误,我已经纠正了。我只是想确保您知道您的样本与测试数据不匹配,以防您想要更新它。如果事情是那样的话,我不想太苛刻。
df1 <- data.frame(name = c('John Doe',
'Jane F. Doe',
'Mark Smith Simpson',
'Sam Lee'),
stringsAsFactors = FALSE)
df2 <- data.frame(family = c('Doe', 'Smith'), size = c(2, 6),
stringsAsFactors = FALSE)
library(tidyr)
library(dplyr)
str_df <- function(x) {
ss <- strsplit(unlist(x)," ")
data.frame(family = unlist(ss),stringsAsFactors = FALSE)
}
splitnames <- df1 %>%
group_by(name) %>%
do(str_df(.))
splitnames
name family
1 Jane F. Doe Jane
2 Jane F. Doe F.
3 Jane F. Doe Doe
4 John Doe John
5 John Doe Doe
6 Mark Smith Simpson Mark
7 Mark Smith Simpson Smith
8 Mark Smith Simpson Simpson
9 Sam Lee Sam
10 Sam Lee Lee
left_join(df2,splitnames)
Joining by: "family"
family size name
1 Doe 2 Jane F. Doe
2 Doe 2 John Doe
3 Smith 6 Mark Smith Simpson
df1name = as.character(df1$name)
df1name
#[1] "John Doe" "Jane F. Doe" "Mark Smith Simpson" "Sam Lee"
regmatches(df1name, regexpr(paste(df2$family, collapse = "|"), df1name), invert = T) <- ""
df1name
#[1] "Doe" "Doe" "Smith" ""
cbind(df1, df2[match(df1name, df2$family), ])
# name family size
#1 John Doe Doe 2
#1.1 Jane F. Doe Doe 2
#2 Mark Smith Simpson Smith 6
#NA Sam Lee <NA> NA