如何匹配+;/-在R中彼此有5个?
假设我有一个如下所示的数据帧:如何匹配+;/-在R中彼此有5个?,r,string-matching,R,String Matching,假设我有一个如下所示的数据帧: dat <- data.frame("firstName" = c("John", "John", "Mary", "Bob", "Mary", "Bob"), "age"= c(21, 24, 35, 30, 20, 27)) 我有一个非常大的姓名和年龄数据集,希望找到一种更自动化的分配id的方法。我考虑过从20岁开始每5年创建一次年龄箱,但这与在不同箱中但仍在5岁以内的观察结果不匹配 这里有一个从dplyr开始的lag方法: library(dplyr
dat <- data.frame("firstName" = c("John", "John", "Mary", "Bob", "Mary", "Bob"), "age"= c(21, 24, 35, 30, 20, 27))
我有一个非常大的姓名和年龄数据集,希望找到一种更自动化的分配id的方法。我考虑过从20岁开始每5年创建一次年龄箱,但这与在不同箱中但仍在5岁以内的观察结果不匹配 这里有一个从
dplyr
开始的lag
方法:
library(dplyr)
dat %>%
group_by(firstName) %>%
arrange(firstName,age) %>%
mutate(id = cumsum(!(age - (lag(age,default = -Inf) ) <= 5)))
# A tibble: 6 x 3
# Groups: firstName [3]
firstName age id
<fct> <dbl> <int>
1 Bob 27 1
2 Bob 30 1
3 John 21 1
4 John 24 1
5 Mary 20 1
6 Mary 35 2
库(dplyr)
dat%>%
分组人(名字)%>%
排列(名字、年龄)%>%
变异(id=cumsum(!(age-(lag(age,default=-Inf))1)sqldf/igraph将每一行与具有相同名称的行进行匹配,年龄在5岁以内,且该行不是自身。如果不存在此类匹配,则将该行与自身进行匹配,以便对所有行进行说明。然后,这些行及其匹配可以转换为edgelist,然后再转换为igraph,g。查找的连接组件并分配原始数据帧行的成员身份ID
在示例数据中,每个连接的组件的大小为1或2,但这种方法可以处理任何大小,而不仅仅是那些大小
library(igraph)
library(sqldf)
s <- sqldf("select a.rowid, a.*, b.rowid as match
from dat a left join dat b
on a.firstname = b.firstname and
abs(a.age - b.age) < 5 and
a.rowid != b.rowid")
e <- cbind(s$rowid, s$match) # edgelist
e[is.na(s$match), 2] <- e[is.na(s$match), 1]
g <- graph_from_edgelist(e)
transform(dat, id = components(g)$membership)
我们可以将图形可视化如下:
plot(g)
(图后续)
2)Base R此解决方案在一定程度上受其他解决方案的推动,但其显著优势在于它只使用Base R,只使用两行代码,如(1)还可以处理任何大小的连接组件,生成正确答案并完全矢量化。它的工作原理是对数据进行排序,然后根据显示的条件向前拉id或生成新id
o <- with(dat, order(firstName, age))
transform(dat[o,], id = cumsum(c(1, diff(xtfrm(firstName)) | diff(age) > 5)))
没有附加包
dat <- data.frame("firstName" = c("John", "John", "Mary", "Bob", "Mary", "Bob"), "age"= c(21, 24, 35, 30, 20, 27))
n <- length(dat$firstName)
vals <- list()
for (i in 1:n) {
fname <- dat$firstName[i]
age <- dat$age[i]
index <- which(fname == dat$firstName &
(age > dat$age - 5) &
(age < dat$age + 5))
vals[[i]] <- index
}
vals <- unique(vals)
dat$id <- NA
for (i in 1:length(vals)) {
dat$id[vals[[i]]] <- i
}
这是按“名字”分组的吗?我想将相同的id分配给具有相同名字且年龄在+/-5范围内的观察值。它们当前没有按名字分组。如果有一个年龄为29岁的John的条目,会发生什么情况?它是同时匹配其他John的条目还是仅匹配第二个条目?如果您有其他OB,会发生什么包含相同的名字,但差异在部分而非全部的范围内?例如,John1在John2的5范围内,John2在John3的5范围内,但John1不在John3的5范围内。如果您认为您实际上拥有唯一的Johns,那么您可能需要首先对名称进行唯一分类,然后在完成范围测试后重新分类。I假设两个或多个观察者的名字相同,年龄在+/-5以内,他们是相同的观察者,将被分配相同的id。我将组成一个id,从1到“匹配”的数量@Chuck P如果有两个John's的年龄=29,它将与两个John's匹配。您的解决方案将在30岁时仅向数据帧添加一个John而崩溃。dat不确定为什么会发生这种情况,但添加dat$id添加了基本解决方案。
o <- with(dat, order(firstName, age))
transform(dat[o,], id = cumsum(c(1, diff(xtfrm(firstName)) | diff(age) > 5)))
firstName age id
6 Bob 27 1
4 Bob 30 1
1 John 21 2
2 John 24 2
5 Mary 20 3
3 Mary 35 4
dat <- data.frame("firstName" = c("John", "John", "Mary", "Bob", "Mary", "Bob"), "age"= c(21, 24, 35, 30, 20, 27))
n <- length(dat$firstName)
vals <- list()
for (i in 1:n) {
fname <- dat$firstName[i]
age <- dat$age[i]
index <- which(fname == dat$firstName &
(age > dat$age - 5) &
(age < dat$age + 5))
vals[[i]] <- index
}
vals <- unique(vals)
dat$id <- NA
for (i in 1:length(vals)) {
dat$id[vals[[i]]] <- i
}
firstName age id
1 John 21 1
2 John 24 1
3 Mary 35 2
4 Bob 30 3
5 Mary 20 4
6 Bob 27 3