首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何匹配R中+/- 5以内的观测值?

如何匹配R中+/- 5以内的观测值?
EN

Stack Overflow用户
提问于 2020-05-21 03:52:53
回答 3查看 99关注 0票数 3

假设我有一个数据帧,如下所示:

代码语言:javascript
复制
dat <- data.frame("firstName" = c("John", "John", "Mary", "Bob", "Mary", "Bob"), "age"= c(21, 24, 35, 30, 20, 27))

我想创建第三个变量dat$id,如果一个观察值的年龄在另一个观察值的+/- 5年内并且具有相同的firstName,则该变量分配相同的数字。因此,数据帧将如下所示:

代码语言:javascript
复制
dat <- data.frame("firstName" = c("John", "John", "Mary", "Bob", "Mary", "Bob"), "age"= c(21, 24, 35, 30, 20, 27), "id"= c(1,1,2,3,4,3))

我有一个非常大的名字和年龄的数据集,我想找到一种更自动化的分配id的方法。我考虑从20岁开始每5年创建一次年龄箱,但这不会匹配不同箱中的观察值,但仍然在5年内。

EN

回答 3

Stack Overflow用户

发布于 2020-05-21 04:25:16

1) sqldf/igraph sqldf将每行与具有相同名称、年龄在5以内的行进行匹配,并且行本身不是。如果没有这样的匹配,则将行与自身进行匹配,以便将所有行都考虑在内。然后,可以将行及其匹配转换为边缘列表,并且随后将其转换为图形,例如,找到连接的分量并将成员资格ids分配给原始数据帧的行。

在示例数据中,每个连接的组件的大小都是1或2,但这种方法可以处理任何大小,而不仅仅是那些。

代码语言:javascript
复制
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)

给予:

代码语言:javascript
复制
  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

我们可以像这样可视化这个图:

代码语言:javascript
复制
plot(g)

(在图形之后继续)

2) Base R这个解决方案在一定程度上受到其他解决方案的推动,但它有显著的优势,因为它只使用base R,只有2行代码,如(1)也可以处理任何大小的连接组件,生成正确的答案,并且是完全矢量化的。它的工作方式是对数据进行排序,然后根据显示的条件向前拉取id或生成一个新的id。

代码语言:javascript
复制
o <- with(dat, order(firstName, age))
transform(dat[o,], id = cumsum(c(1, diff(xtfrm(firstName)) | diff(age) > 5)))

给予:

代码语言:javascript
复制
  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
票数 1
EN

Stack Overflow用户

发布于 2020-05-21 04:38:37

没有额外的包

代码语言:javascript
复制
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
}

结果

代码语言:javascript
复制
  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
票数 1
EN

Stack Overflow用户

发布于 2020-05-21 04:09:25

下面是来自dplyr的使用lag的方法

代码语言:javascript
复制
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
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61921752

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档