删除重复条目,同时保留唯一信息
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。
我有一个包含多行的数据集,它是一个联系方式数据库。有些条目重复了几次,但包含不同的信息。示例:
> 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。