如何将数据框的行与 R 中的第一个可用匹配项合并?
How to merge a rows of a dataframe with the first available match in R?
我有两个数据框:一个(称为 df_persons
)的记录具有唯一的 person_id
,但 stratum_id
的记录不唯一,另一个(称为 df_population
) 和相同的 stratum_id
,以及它们的多个重复行。下面重新创建它们的代码:
df_persons = data.frame(person_id=c(101, 102, 103), stratum_id=c(1,2,1))
df_population = data.frame(stratum_id=c(1,1,1,1,2,2,2,2,3,3))
现在我想要一种方法来将 df_persons 中的数据与 df_population 中的数据合并,以便 df_persons 中的每一行都与第一个匹配项(key = stratum_id
) df_population
行之前没有被匹配。在下面找到所需的解决方案:
# manual way to merge first available match
df_population$person = c(101, 103, NA, NA, 102, NA, NA, NA, NA, NA)
我为此编写了一个有效的循环(见下文)。问题是 df_persons
有 83.000 条记录,而 df_population
有 1300 万条记录。因此循环时间太长+我的电脑无法处理它。
# create empty person column in df_population
df_population$person = NA
# order both df's to speed up
df_population = df_population[order(df_population$stratum_id),]
df_persons = df_persons[order(df_persons$stratum_id),]
# loop through all persons in df_person, and for each find the first available match
for(i_person in 1:nrow(df_persons))
{
match = F
i_pop = 0
while(!match)
{
i_pop = i_pop+1
if(df_population$stratum_id[i_pop] == df_persons$stratum_id[i_person] & is.na(df_population$person[i_pop]))
{
match = T
df_population$person[i_pop] = df_persons$person[i_person]
}
}
}
如果您能帮助我们加快速度,我们将不胜感激。我已经查看了 data.frame 包,到目前为止无济于事,但我确实认为我需要摆脱循环才能执行代码。
这是一个data.table
方法。更多解释在代码的注释中。
library(data.table)
# make them data.table
setDT(df_persons)
setDT(df_population)
# create dummy values to join on
df_persons[, id := rowid(stratum_id)]
df_population[, id := rowid(stratum_id)]
# join by refence
df_population[df_persons, person_id := i.person_id, on = .(stratum_id, id)][]
# drop the dummy id column
df_population[, id := NULL][]
# stratum_id person_id
# 1: 1 101
# 2: 1 103
# 3: 1 NA
# 4: 1 NA
# 5: 2 102
# 6: 2 NA
# 7: 2 NA
# 8: 2 NA
# 9: 3 NA
#10: 3 NA
1) dplyr 使用dplyr为每个数据帧添加一个序列号,然后合并它们:
library(dplyr)
df_population %>%
group_by(stratum_id) %>%
mutate(seq = 1:n()) %>%
ungroup %>%
left_join(df_persons %>% group_by(stratum_id) %>% mutate(seq = 1:n()))
给予:
Joining, by = c("stratum_id", "seq")
# A tibble: 10 x 3
stratum_id seq person_id
<dbl> <int> <dbl>
1 1 1 101
2 1 2 103
3 1 3 NA
4 1 4 NA
5 2 1 102
6 2 2 NA
7 2 3 NA
8 2 4 NA
9 3 1 NA
10 3 2 NA
2) 基数 R 或基数 R:
p1 <- transform(df_population, seq = ave(stratum_id, stratum_id, FUN = seq_along))
p2 <- transform(df_persons, seq = ave(stratum_id, stratum_id, FUN = seq_along))
merge(p1, p2, all.x = TRUE, all.y = FALSE)
3) sqldf 在 SQL 中我们有以下内容。 dbname= 参数使它在 R 之外执行处理,但如果你有足够的内存,那么它可以被省略,它将使用 R 中的内存。
library(sqldf)
seqno <- "sum(1) over (partition by stratum_id rows unbounded preceding)"
fn$sqldf("
with
p1 as (select *, $seqno seq from df_population),
p2 as (select *, $seqno seq from df_persons)
select * from p1 left join p2 using (stratum_id, seq)
", dbname = tempfile())
只需使用pmatch
如下图:
df_population$person_id <- df_persons$person_id[pmatch(df_population$stratum_id, df_persons$stratum_id)]
df_population
stratum_id person_id
1 1 101
2 1 103
3 1 NA
4 1 NA
5 2 102
6 2 NA
7 2 NA
8 2 NA
9 3 NA
10 3 NA
我有两个数据框:一个(称为 df_persons
)的记录具有唯一的 person_id
,但 stratum_id
的记录不唯一,另一个(称为 df_population
) 和相同的 stratum_id
,以及它们的多个重复行。下面重新创建它们的代码:
df_persons = data.frame(person_id=c(101, 102, 103), stratum_id=c(1,2,1))
df_population = data.frame(stratum_id=c(1,1,1,1,2,2,2,2,3,3))
现在我想要一种方法来将 df_persons 中的数据与 df_population 中的数据合并,以便 df_persons 中的每一行都与第一个匹配项(key = stratum_id
) df_population
行之前没有被匹配。在下面找到所需的解决方案:
# manual way to merge first available match
df_population$person = c(101, 103, NA, NA, 102, NA, NA, NA, NA, NA)
我为此编写了一个有效的循环(见下文)。问题是 df_persons
有 83.000 条记录,而 df_population
有 1300 万条记录。因此循环时间太长+我的电脑无法处理它。
# create empty person column in df_population
df_population$person = NA
# order both df's to speed up
df_population = df_population[order(df_population$stratum_id),]
df_persons = df_persons[order(df_persons$stratum_id),]
# loop through all persons in df_person, and for each find the first available match
for(i_person in 1:nrow(df_persons))
{
match = F
i_pop = 0
while(!match)
{
i_pop = i_pop+1
if(df_population$stratum_id[i_pop] == df_persons$stratum_id[i_person] & is.na(df_population$person[i_pop]))
{
match = T
df_population$person[i_pop] = df_persons$person[i_person]
}
}
}
如果您能帮助我们加快速度,我们将不胜感激。我已经查看了 data.frame 包,到目前为止无济于事,但我确实认为我需要摆脱循环才能执行代码。
这是一个data.table
方法。更多解释在代码的注释中。
library(data.table)
# make them data.table
setDT(df_persons)
setDT(df_population)
# create dummy values to join on
df_persons[, id := rowid(stratum_id)]
df_population[, id := rowid(stratum_id)]
# join by refence
df_population[df_persons, person_id := i.person_id, on = .(stratum_id, id)][]
# drop the dummy id column
df_population[, id := NULL][]
# stratum_id person_id
# 1: 1 101
# 2: 1 103
# 3: 1 NA
# 4: 1 NA
# 5: 2 102
# 6: 2 NA
# 7: 2 NA
# 8: 2 NA
# 9: 3 NA
#10: 3 NA
1) dplyr 使用dplyr为每个数据帧添加一个序列号,然后合并它们:
library(dplyr)
df_population %>%
group_by(stratum_id) %>%
mutate(seq = 1:n()) %>%
ungroup %>%
left_join(df_persons %>% group_by(stratum_id) %>% mutate(seq = 1:n()))
给予:
Joining, by = c("stratum_id", "seq")
# A tibble: 10 x 3
stratum_id seq person_id
<dbl> <int> <dbl>
1 1 1 101
2 1 2 103
3 1 3 NA
4 1 4 NA
5 2 1 102
6 2 2 NA
7 2 3 NA
8 2 4 NA
9 3 1 NA
10 3 2 NA
2) 基数 R 或基数 R:
p1 <- transform(df_population, seq = ave(stratum_id, stratum_id, FUN = seq_along))
p2 <- transform(df_persons, seq = ave(stratum_id, stratum_id, FUN = seq_along))
merge(p1, p2, all.x = TRUE, all.y = FALSE)
3) sqldf 在 SQL 中我们有以下内容。 dbname= 参数使它在 R 之外执行处理,但如果你有足够的内存,那么它可以被省略,它将使用 R 中的内存。
library(sqldf)
seqno <- "sum(1) over (partition by stratum_id rows unbounded preceding)"
fn$sqldf("
with
p1 as (select *, $seqno seq from df_population),
p2 as (select *, $seqno seq from df_persons)
select * from p1 left join p2 using (stratum_id, seq)
", dbname = tempfile())
只需使用pmatch
如下图:
df_population$person_id <- df_persons$person_id[pmatch(df_population$stratum_id, df_persons$stratum_id)]
df_population
stratum_id person_id
1 1 101
2 1 103
3 1 NA
4 1 NA
5 2 102
6 2 NA
7 2 NA
8 2 NA
9 3 NA
10 3 NA