R - 基于配对数据条件的子集

时间:2015-07-17 19:30:45

标签: r merge subset

我正在尝试根据条件对配对数据进行分组 包括在2天内观察到的两个人。

我的样本的主要数据是: 'hldid', 'cid', 'pid', 'diary', 'sex', 'day', 'main1'

'hldid'指的是配对数据标识符

'cid'是配对的数据日标识符

'pid'个人识别码 'diary'日记(每个人必须填写2本日记) 'sex' 'day' 'main1'指的是性别,日期和观察到的活动。

我想要做的是根据两个条件对数据进行子集化:

  1. 数据必须配对,这意味着hldid必须是2个人。 每一对都应该由一个男人和一个女人组成。
  2. 个人必须填写2 diary。所以4 {日期hldid
  3. 我发现这样做的唯一方法是执行以下操作:

    按性别分开

    M = filter(dtaSimple, sex == 1)
    W = filter(dtaSimple, sex == 2)
    

    按配对日标识符合并

    dtaSimple_c = merge(M, W, by = 'cid', suffixes = c('_m', '_w'))
    

    然后我会得到

         cid hldid_m  pid_m diary_m sex_m day_m main1_m hldid_w  pid_w diary_w sex_w day_w main1_w
     1 1250_1    1250 1250_2       1     1     1       0    1250 1250_1       1     2     1       0
     2 1250_2    1250 1250_2       2     1     3       0    1250 1250_1       2     2     3       0
     3 1294_1    1294 1294_2       1     1     6       0    1294 1294_1       1     2     6       0
     4 1294_2    1294 1294_2       2     1     1       0    1294 1294_1       2     2     1       0
    

    我认为这并不令人满意。 每行指的是每个hldid的第一个日记,每列都适用于pair的男性或女性。

    我想保留1行一个人和一天的原始数据结构。

       hldid    cid    pid diary sex day main1
    1   1250 1250_1 1250_1     1   2   1     0
    2   1250 1250_2 1250_1     2   2   3     0
    3   1250 1250_1 1250_2     1   1   1     0
    4   1250 1250_2 1250_2     2   1   3     0
     .....
    

    数据:

    dtaSimple = structure(
       list(
           hldid = c(1250, 1250, 1250, 1250, 1294, 1294, 1294, 1294, 1352, 1352), 
           cid = c("1250_1", "1250_2", "1250_1", "1250_2", "1294_1",  "1294_2", "1294_1", "1294_2", "1352_1", "1352_2"), 
           pid = c("1250_1", "1250_1", "1250_2", "1250_2", "1294_1", "1294_1", "1294_2", "1294_2", "1352_1", "1352_1"), 
           diary = c(1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L), 
           sex = c(2L, 2L, 1L, 1L, 2L, 2L, 1L, 1L, 2L, 2L), 
           day = c(1L, 3L, 1L, 3L, 6L, 1L, 6L, 1L, 1L, 3L), 
           main1 = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L)), 
       .Names = c("hldid", "cid", "pid", "diary", "sex", "day", "main1"), 
       row.names = c(NA, 10L), 
       class = "data.frame"
    )
    

2 个答案:

答案 0 :(得分:4)

听起来你需要按分组变量进行过滤。据我了解,对于每个hldid,您要确保sex有2个不同的值,总共有4个观察值。

您可以使用 dplyr 中的filtergroup_by

library(dplyr)

dtaSimple %>% 
    group_by(hldid) %>%
    filter(n_distinct(sex) == 2, n() >= 4)

  hldid    cid    pid diary sex day main1
1  1250 1250_1 1250_1     1   2   1     0
2  1250 1250_2 1250_1     2   2   3     0
3  1250 1250_1 1250_2     1   1   1     0
4  1250 1250_2 1250_2     2   1   3     0
5  1294 1294_1 1294_1     1   2   6     0
6  1294 1294_2 1294_1     2   2   1     0
7  1294 1294_1 1294_2     1   1   6     0
8  1294 1294_2 1294_2     2   1   1     0

更改数据集,使一个hldid没有4个观察结果进行更彻底的测试:

dtaSimple2 = dtaSimple[-4,]

dtaSimple2 %>% 
    group_by(hldid) %>%
    filter(n_distinct(sex) == 2, n() >= 4)

  hldid    cid    pid diary sex day main1
1  1294 1294_1 1294_1     1   2   6     0
2  1294 1294_2 1294_1     2   2   1     0
3  1294 1294_1 1294_2     1   1   6     0
4  1294 1294_2 1294_2     2   1   1     0

如果每个sex必须有2个日记条目,一个性别可以有1个条目,而另一个可能有3个条目,则需要稍微不同的策略。也许只确保每个sex的每个id有两个以上的观察结果?

dtaSimple %>% 
    group_by(hldid) %>%
    filter(sum(sex == 1) >= 2, sum(sex == 2) >= 2)

答案 1 :(得分:1)

plyr库中有一个函数ddply,它适用于通过列值组合进行快速分组和制表。考虑到你想要非常具体的分组计数,我喜欢ddply。这将两个ddply()函数链接在一起,最终根据以下内容筛选出个人: 1)他们没有两个日记值

# calculate the number of diaries by pid (we are looking for exactly two):
diaryByPid <- ddply(dtaSimple,c("pid"),function(x){ length(unique(x$diary))})

# the valid pids have exactly two unique diary values
validPid <- diaryByPid$pid[which(diaryByPid[,2]==2)]

# now subset the original dtaSimple to retain only those matched above
dtaSub <- dtaSimple[which(dtaSimple$pid %in% validPid),]

我们排除了pid没有两个独特日记值的记录。现在我们需要将它们与相应的cid值配对,并确保代表两种性别:

# ddply to group by cid and count the number of unique values of $sex column
sexByCid <- ddply(dtaSub,c("cid"),function(x){ length(unique(x$sex))})

# retain the cids for which we have two unique sexes
validCid <- sexByCid$cid[which(sexByCid[,2]==2)]

# subset the previously subsetted dtaSub to remove records without gender matches.
dtaSub2 <- dtaSub[which(dtaSub$cid %in% validCid),]

由于我们只删除了原始结构中的行,因此它保持相同的格式:

head(dtaSub2)
  hldid    cid    pid diary sex day main1
1  1250 1250_1 1250_1     1   2   1     0
2  1250 1250_2 1250_1     2   2   3     0
3  1250 1250_1 1250_2     1   1   1     0
4  1250 1250_2 1250_2     2   1   3     0
5  1294 1294_1 1294_1     1   2   6     0
6  1294 1294_2 1294_1     2   2   1     0
7  1294 1294_1 1294_2     1   1   6     0
8  1294 1294_2 1294_2     2   1   1     0