删除重复条目,同时保留唯一信息

Removing duplicate entries while retaining unique information

我有一个包含多行的数据集,它是一个联系方式数据库。有些条目重复了几次,但包含不同的信息。示例:

> example
     Title             Name              Email         Phone      
[1,] "Chair"           "Oswald Gruber"   "abc@abc.com" "+33 12345"
[2,] "Respondent"      "Oswald Gruber"   NA            "+44 54321"
[3,] "Comm.mngr"       "Kaspar Villiger" "qwe@rty.com" "+1 123456"
[4,] "Investment mngr" "Markus Urben"    "jkl@jkl.com" NA         
[5,] "Responsible"     "Markus Urben"    "jkl@jkl.com" "+1 33333"

所以我希望每个人只被提及一次,但不会丢失信息。因此,如果我在此示例中合并前两行,我想保留电子邮件地址和两个 phone 号码,但只保留一种标题。

如果有人能提出任何解决方案,我将不胜感激。

假设您的 "example" 对象是 data.frame(也可以使用矩阵)。 对于那些你想保留所有信息的列,你可以这样做(未经测试编码错别字):

result <- aggregate(example[,c("Phone","Email")], by = list(Name = example[,"Name"]), FUN = paste, sep = ", ")

因此 phone 数字和电子邮件地址将作为字符串元素粘贴到单个列中,值以逗号分隔)。 或者,

result <- aggregate(example[,c("Phone","Email")], by = list(Name = example[,"Name"]), FUN = c)

将给出 2 列,其中包含长度为特定名称的条目数的向量列表。

对于您只想保留一个值的列,您必须指定您想要的值。如果它总是第一个出现的值,那就是

result2 <- aggregate(example[,"title"], by = list(Name = example[,"Name"]), function(x) x[1])

然后你可以

merged <- merge(results, result2)

我会把它拆分成一个关系数据库。这是假设名字可以作为识别一个人的唯一键。

library(dplyr)

test = 
  data_frame(
    Title = c("Chair", "Respondent", "Comm.mngr", "Investment mngr", "Responsible"),
    Name = c("Oswald Gruber", "Oswald Gruber", "Kaspar Villiger", "Markus Urben", "Markus Urben"),
    Email = c("abc@abc.com", NA, "qwe@rty.com", "jkl@jkl.com", "jkl@jkl.com"),
    Phone = c("+33 12345", "+44 54321", "+1 123456", NA, "+1 33333") )

Person__Title = 
  test %>%
  select(Name, Title) %>%
  distinct %>%
  filter(!is.na(Title))

Person__Phone =
  test %>%
  select(Name, Phone) %>%
  distinct %>%
  filter(!is.na(Phone))

Person__Email = 
  test %>%
  select(Name, Email) %>%
  distinct %>%
  filter(!is.na(Email))

Person = 
  test %>%
  select(Name) %>%
  distinct

然后,如果你想把它们全部合并在一起,你可以这样做

make_list = function(vector)
  vector %>%
  unique %>%
  na.omit %>%
  paste(collapse = ", ")

merge = 
  Person %>%
  left_join(Person__Email) %>%
  left_join(Person__Phone) %>%
  left_join(Person__Title) %>%
  group_by(Name) %>%
  summarise_each(funs(make_list))

但我不推荐它。在同一个单元格中包含多条信息违背了良好数据设计的原则。

您可以按 Name 分组并将每列转换为列表。

library(dplyr)
dat %>% group_by(Name) %>%
  summarise_each(funs(list)) -> res

所以,看起来像

data.frame(res)
#              Name                        Title                    Email
# 1 Kaspar Villiger                    Comm.mngr              qwe@rty.com
# 2    Markus Urben Investment mngr, Responsible jkl@jkl.com, jkl@jkl.com
# 3   Oswald Gruber            Chair, Respondent          abc@abc.com, NA
#                  Phone
# 1            +1 123456
# 2         NA, +1 33333
# 3 +33 12345, +44 54321

我不知道你想要什么进一步的修改,但你可以很容易地删除 NA values/duplicates 并选择只保留一个标题,只需对代码稍作更改。例如,要删除 NA/duplicates,您可以使用 funs(list(unique(na.omit(.)))).

还有一个data.table解决方案:

library(data.table)
mrg <- function(x) paste(unique(x[!is.na(x)]),collapse=", ")
setDT(example)[,list(Title=head(Title,1), Email=mrg(Email), Phone=mrg(Phone)), by="Name"]

#               Name           Title       Email                Phone
# 1:   Oswald Gruber           Chair abc@abc.com +33 12345, +44 54321
# 2: Kaspar Villiger       Comm.mngr qwe@rty.com            +1 123456
# 3:    Markus Urben Investment mngr jkl@jkl.com             +1 33333

此 returns 自然顺序中的第一个标题,可能是也可能不是您想要的。它还可以正确合并电子邮件并删除 NA。