数据框中每个组的字符串更新

时间:2017-03-07 08:14:35

标签: r

我有一个大数据框df,如下所示:

 firstname = c("John L",  "Robert C", "John", "J L", "Tom F", "T F", "Tom")
 lastname = c("Doe", "Doe", "Doe", "Doe", "Frost", "Frost", "Frost")
 id = c(178, 649, 384, 479, 539, 261, 347)
 df = data.frame(firstname, lastname, id)

df视图中显示如下:

 firstname   lastname   id
  John L      Doe       178
  Robert C    Doe       649
  John        Doe       384
  J L         Doe       479
  Tom F       Frost     539
  T F         Frost     261
  Tom         Frost     347  

如您所见,数据框中的名字不一致。有时它只是一个例子。我想拥有一致的名字。我想有一个像这样的输出数据框:

 firstname   lastname   id
  John L      Doe       178
  Robert C    Doe       649
  John L      Doe       384
  John L      Doe       479
  Tom F       Frost     539
  Tom F       Frost     261
  Tom F       Frost     347

我尝试了一些方法,比如使用lastname进行分组,然后为每个组获取最长的字符串,然后通过使用下面的组中的其他名字匹配来更新if elseif语句中的firstname

  > sapply(strsplit("John L Doe"," "), function(a) paste(a[1],a[3]))
   [1] "John Doe"
  > sapply(strsplit("John L Doe"," "), function(a) paste(substr(a[1],1,1),a[2],a[3]))
   [1] "J L Doe" 

它没有用,因为我意识到在组中使用最长的字符串并不是一个好方法。

非常感谢先进的任何支持,以及解决此问题的指南。

编辑:为问题添加更多信息。

firstname的首字母到firstname的完整形式的映射始终是正确的。例如,将会有" John L Doe"。但是,他的firstname将有3个变种。例如," John L"," John"和" J L"。这是因为这些是非常狭窄主题的作者名单。我希望修复的名称格式只是不一致。拥有一个一致的名称将有助于我进行更广泛的分析。所以,我期待R中的解决方案能够做到这一点。

3 个答案:

答案 0 :(得分:1)

您尝试实现的目标通常是使用将每个拼写变体与首选名称相匹配的字典来完成。有基于文本相似性和文本挖掘的智能解决方案。除非你已经将字典c(" JL",J L",JL"等等......)链接到John L.我不会在R中这样做。 / p>

查看DataWranglerTrifactaDataikuOpenrefine他们都有免费版本,可以满足您的需求。我知道Openrefine(以前是GoogleRefine)可以编写脚本。

答案 1 :(得分:1)

您的用例并不完全清楚。 如上所述,如果您的姓氏相同,初始名称相同但名字不同,则会出现问题。如果您确信在您的数据中绝不会出现这种情况,那么解决方案可能非常简单。

但是,如果你要做的是查明这些名字是否指的是同一个人,那么你需要更多,这意味着潜入实体的主题和解

这里有一些简洁的R套餐(我已经参与了涉及实体对账的项目),包括dd,但最重要的是:如果你想要可靠的记录链接,你就可以了需要至少比名字更多一点&姓氏

答案 2 :(得分:1)

以下解决方案会产生您的预期结果,但请记住,如果Jack L Doe和John L Doe存在,J L Doe将映射到第一个最长的名称。

  firstname = c("John L",  "Robert C", "John", "J L", "Tom F", "T F", "Tom", "Jack L", "Robert Can","R C", "R C")
  lastname = c("Doe", "Doe", "Doe", "Doe", "Frost", "Frost", "Frost", "Doe","Frost","Doe", "Frost")
  id = c(178, 649, 384, 479, 539, 261, 347,100,200,300,400)
  df = data.frame(firstname, lastname, id,stringsAsFactors = FALSE)
  df$Initials <- sapply(strsplit(as.vector(firstname), " "), function(x) paste(substr(x, 1,1), collapse=""))
  df$LongName<-apply(df,1,function(x) {
    if(sub("\\s","",x[["firstname"]]) == x[["Initials"]]){
      choices<-df$firstname[ grepl(x[["Initials"]], df$Initials) & df$lastname == x[["lastname"]]]
    }
    else{
      choices<-df$firstname[ grepl(x[["Initials"]], df$Initials) & grepl(x[["firstname"]], df$firstname) & df$lastname == x[["lastname"]]] 
    }

    choices[which.max(nchar(choices))]
    }
  )

结果

  > df
  firstname lastname  id Initials   LongName
  1      John L      Doe 178       JL     John L
  2    Robert C      Doe 649       RC   Robert C
  3        John      Doe 384        J     John L
  4         J L      Doe 479       JL     John L
  5       Tom F    Frost 539       TF      Tom F
  6         T F    Frost 261       TF      Tom F
  7         Tom    Frost 347        T      Tom F
  8      Jack L      Doe 100       JL     Jack L
  9  Robert Can    Frost 200       RC Robert Can
  10        R C      Doe 300       RC   Robert C
  11        R C    Frost 400       RC Robert Can