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