【问题标题】:Merge 2 data sets in long format based on a condition根据条件合并 2 个长格式数据集
【发布时间】:2020-07-24 03:34:56
【问题描述】:

我有 2 个要合并的数据框。数据集之间的区别在于观察的数量和它们收集的方式。在df1observation 中记录了 2 个不同的日子。每条记录都有一个索引,id1 个人识别号,id2 指的是录制的日期(天必须不同)。还有一个 Day 变量记录录制的星期几。

在df2 中仅根据序列号和 id1 个人识别号记录观察结果。每人只有一次观察。同样,这里还有一个 Day 变量,用于记录录制开始的时间。

我想确定 df2 中与 df1 同一天记录的观察结果。

我尝试创建一个新索引(对索引和 id1 进行分组)以根据天数进行长期合并。

Df1:- day 表示进行观察的时间(例如,索引 12;id1 - 仅表示 1 个人;id2 表示 2 天 -Wednesday id2 1 和 Sunday id2 2)

    index id1 id2  Day         obs1 obs2 obs3
     12    1   1   Wednesday    1    11   12
     12    1   2   Sunday       2     0    0
    123    1   1   Tuesday      1     0    1
    123    1   2   Saturday     3     0    3
    123    2   1   Monday       2     2    4
    123    2   2   Saturday     1     0    8

df2: - 这里 day 变量表示观察的开始日期(例如 id 12 day2 和 id 123 day1)

index   id1  Day       day1 day2 day3 day4 day5 day6  day7   
 12      1    Tuesday     2    1    2    1    1    3    1    
123      1    Friday      0    3    0    3    3    0    3     

结果:

 index id1 id2   obs1 obs2 obs3 
 12      1   1     1   11    12   
 12      1   2     2    0     0
 123     1   2     3    0     3        
 123     2   2     1    0     8

样本数据

df1:

structure(list(index = c(12, 12, 123, 123, 123, 123), id1 = c(1, 
1, 1, 1, 2, 2), id2 = c(1, 2, 1, 2, 1, 2), Day = structure(c(5L, 
3L, 4L, 2L, 1L, 2L), .Label = c("Monday", "Saturday", "Sunday", 
"Tuesday", "Wednesday"), class = "factor"), obs1 = c(1, 2, 1, 
3, 2, 1), obs2 = c(11, 0, 0, 0, 2, 0), obs3 = c(12, 0, 1, 3, 
4, 8)), class = "data.frame", row.names = c(NA, -6L))

df2:

structure(list(index = c(12, 123), id1 = c(1, 1), Day = structure(2:1, .Label = c("Friday", 
"Tuesday"), class = "factor"), day1 = c(2, 0), day2 = c(1, 3), 
    day3 = c(2, 0), day4 = c(1, 3), day5 = c(1, 3), day6 = c(3, 
    0), day7 = c(1, 3)), class = "data.frame", row.names = c(NA, 
-2L))

【问题讨论】:

  • 当您说从 day61-da696 和 day71-day796 开始时。它是 7 天的顺序,对吧?

标签: r dataframe


【解决方案1】:

我们可以得到df2lin long 格式,group_byindex 保留观察后发生的行,并根据index 和Day 将其与df1 连接起来。

library(dplyr)
weekday <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", 
             "Saturday", "Sunday")


df2 %>%
  mutate_at(vars(matches('day\\d+')), as.numeric) %>%
  tidyr::pivot_longer(cols = matches('day\\d+')) %>%
  group_by(index) %>%
  filter(row_number() >= match(Day, weekday)[1L]) %>%
  summarise(Day = match(Day, weekday)[1]) %>%
  inner_join(df1 %>%mutate(Day = match(Day, weekday)), by = 'index') %>%
  filter(Day.y >= Day.x)


#  index Day.x   id1   id2 Day.y  obs1  obs2  obs3
#  <dbl> <int> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
#1    12     2     1     1     3     1    11    12
#2    12     2     1     2     7     2     0     0
#3   123     5     1     2     6     3     0     3
#4   123     5     2     2     6     1     0     8

然后您可以使用select 仅保留所需的列。

【讨论】:

    【解决方案2】:

    melt 的选项来自data.table

    library(data.table)
    weekday <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    

    如果数据集是havenlabelled'Day',我们首先将factor转换为as_factor

    library(haven)
    df1$Day <- as.character(as_factor(df1$Day))
    df2$Day <- as.character(as_factor(df2$Day))
    df1$Day <- match(df1$Day, weekday) 
    dt2 <- melt(setDT(df2), measure = patterns('^day\\d+$'))[seq_len(.N) >=
        match(Day, weekday)[1L]][, .(Day = match(Day, weekday)[1]), index]
    merge(setDT(df1), dt2, by = 'index')[Day.y < Day.x]
    #   index id1 id2 Day.x obs1 obs2 obs3 Day.y
    #1:    12   1   1     3    1   11   12     2
    #2:    12   1   2     7    2    0    0     2
    #3:   123   1   2     6    3    0    3     5
    #4:   123   2   2     6    1    0    8     5
    

    或者使用tidyverse,最好在summarise中返回一个list列,然后unnest(以防长度与行数不匹配)

    library(dplyr)
    library(tidyr)
    df2 %>%
         pivot_longer(cols = day1:day7) %>%
         group_by(index) %>% 
         slice(match(Day, weekday)[1L]:n()) %>%
         summarise(Day = match(Day, weekday)[1]) %>%
         inner_join(df1 %>%
         mutate(Day = match(Day, weekday)), by = 'index') %>%
         filter(Day.y >= Day.x)
    # A tibble: 4 x 8
    #  index Day.x   id1   id2 Day.y  obs1  obs2  obs3
    #  <dbl> <int> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
    #1    12     2     1     1     3     1    11    12
    #2    12     2     1     2     7     2     0     0
    #3   123     5     1     2     6     3     0     3
    #4   123     5     2     2     6     1     0     8
    

    【讨论】:

    • @user11964604 嗨,可以。你请检查我更新的 tidyverse
    • @user11964604。看起来你正在使用一个。不同于 dput 中显示的属性(避风港)
    • @user11964604 我是。没有从 cmets 获得逻辑。你能把它作为一个新问题发帖吗
    • @user11964604 我的意思是您能否发布一个新主题/问题,因为其他人也根据之前的问题回答了
    • @user11964604 你可以创建一个命名向量并进行匹配
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-23
    • 2019-08-10
    • 2020-10-13
    • 2017-12-30
    • 1970-01-01
    • 2021-10-28
    • 1970-01-01
    相关资源
    最近更新 更多