查找在一列中相同但在另一列中不相同的行
Find rows that are identical in one column but not another
应该有一个相当简单的解决方案,但它给我带来了麻烦。我有一个类似这样的 DF:
> df <- data.frame(name = c("george", "george", "george", "sara", "sara", "sam", "bill", "bill"),
id_num = c(1, 1, 2, 3, 3, 4, 5, 5))
> df
name id_num
1 george 1
2 george 1
3 george 2
4 sara 3
5 sara 3
6 sam 4
7 bill 5
8 bill 5
我正在寻找一种方法来查找在非常大的数据集中名称和 ID 号不一致的行。也就是说,George 应该始终是“1”,但在第三行中有一个错误,他也被分配了 ID 号“2”。
我认为最简单的方法是使用 dplyr::count
两次,因此对于您的示例:
df %>%
count(name, id) %>%
count(name)
第一次计数将得出:
name id n
george 1 2
george 2 1
sara 3 2
sam 4 1
bill 5 2
那么第二次计数将给出:
name n
george 2
sara 1
sam 1
bill 1
当然,您也可以在管道的末尾添加 filter(n > 1)
,或者 arrange(desc(n))
df %>%
count(name, id) %>%
count(name) %>%
arrange(desc(n)) %>%
filter(n > 1)
使用 tapply()
计算每个名称的 ID 数量,然后对大于 1 的 ID 进行子集化。
res <- with(df, tapply(id_num, list(name), \(x) length(unique(x))))
res[res > 1]
# george
# 2
您可能想要更正此问题。一种安全的方法是使用 as.factor()
、
重建数字 ID
df$id_new <- as.integer(as.factor(df$name))
df
# name id_num id_new
# 1 george 1 2
# 2 george 1 2
# 3 george 2 2
# 4 sara 3 4
# 5 sara 3 4
# 6 sam 4 3
# 7 bill 5 1
# 8 bill 5 1
其中数字是根据名称的字母顺序分配的,或 factor()
,按出现顺序阅读级别。
df$id_new2 <- as.integer(factor(df$name, levels=unique(df$name)))
df
# name id_num id_new id_new2
# 1 george 1 2 1
# 2 george 1 2 1
# 3 george 2 2 1
# 4 sara 3 4 2
# 5 sara 3 4 2
# 6 sam 4 3 3
# 7 bill 5 1 4
# 8 bill 5 1 4
注意: R >= 4.1 使用。
数据:
df <- structure(list(name = c("george", "george", "george", "sara",
"sara", "sam", "bill", "bill"), id_num = c(1, 1, 2, 3, 3, 4,
5, 5)), class = "data.frame", row.names = c(NA, -8L))
应该有一个相当简单的解决方案,但它给我带来了麻烦。我有一个类似这样的 DF:
> df <- data.frame(name = c("george", "george", "george", "sara", "sara", "sam", "bill", "bill"),
id_num = c(1, 1, 2, 3, 3, 4, 5, 5))
> df
name id_num
1 george 1
2 george 1
3 george 2
4 sara 3
5 sara 3
6 sam 4
7 bill 5
8 bill 5
我正在寻找一种方法来查找在非常大的数据集中名称和 ID 号不一致的行。也就是说,George 应该始终是“1”,但在第三行中有一个错误,他也被分配了 ID 号“2”。
我认为最简单的方法是使用 dplyr::count
两次,因此对于您的示例:
df %>%
count(name, id) %>%
count(name)
第一次计数将得出:
name id n
george 1 2
george 2 1
sara 3 2
sam 4 1
bill 5 2
那么第二次计数将给出:
name n
george 2
sara 1
sam 1
bill 1
当然,您也可以在管道的末尾添加 filter(n > 1)
,或者 arrange(desc(n))
df %>%
count(name, id) %>%
count(name) %>%
arrange(desc(n)) %>%
filter(n > 1)
使用 tapply()
计算每个名称的 ID 数量,然后对大于 1 的 ID 进行子集化。
res <- with(df, tapply(id_num, list(name), \(x) length(unique(x))))
res[res > 1]
# george
# 2
您可能想要更正此问题。一种安全的方法是使用 as.factor()
、
df$id_new <- as.integer(as.factor(df$name))
df
# name id_num id_new
# 1 george 1 2
# 2 george 1 2
# 3 george 2 2
# 4 sara 3 4
# 5 sara 3 4
# 6 sam 4 3
# 7 bill 5 1
# 8 bill 5 1
其中数字是根据名称的字母顺序分配的,或 factor()
,按出现顺序阅读级别。
df$id_new2 <- as.integer(factor(df$name, levels=unique(df$name)))
df
# name id_num id_new id_new2
# 1 george 1 2 1
# 2 george 1 2 1
# 3 george 2 2 1
# 4 sara 3 4 2
# 5 sara 3 4 2
# 6 sam 4 3 3
# 7 bill 5 1 4
# 8 bill 5 1 4
注意: R >= 4.1 使用。
数据:
df <- structure(list(name = c("george", "george", "george", "sara",
"sara", "sam", "bill", "bill"), id_num = c(1, 1, 2, 3, 3, 4,
5, 5)), class = "data.frame", row.names = c(NA, -8L))