R - 基于配对数据条件的子集
R - Subset based on conditions for paired data
我正在尝试根据条件对配对数据进行子集化。
对 包括在 2 天内观察到的两个人。
我的样本的主要数据是:
'hldid', 'cid', 'pid', 'diary', 'sex', 'day', 'main1'
。
'hldid'
指配对数据标识符,
'cid'
是配对的数据日标识符
'pid'
个人标识符
'diary'
日记本(每人必须填写2本日记本)
'sex' 'day' 'main1'
指的是观察到的性别、日期和活动。
我想做的是根据 2 个条件对数据进行子集化:
- 数据必须配对意味着
hldid
必须是2个人。
每对应该由一男一女组成。
- 个人必须填写2个
diary
。所以 4 日记 hldid
我发现这样做的唯一方法是执行以下操作:
按性别分开
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行1个人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"
)
在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
听起来您需要按分组变量进行过滤。据我了解,对于每个 hldid
,您要确保 sex
有 2 个不同的值,总共有 4 个观察值。
您可以使用 dplyr 中的 filter
和 group_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 个条目,那么您需要一个稍微不同的策略。也许只是确保每个 id
每个 sex
有 2 个以上的观察值?
dtaSimple %>%
group_by(hldid) %>%
filter(sum(sex == 1) >= 2, sum(sex == 2) >= 2)
我正在尝试根据条件对配对数据进行子集化。
对 包括在 2 天内观察到的两个人。
我的样本的主要数据是:
'hldid', 'cid', 'pid', 'diary', 'sex', 'day', 'main1'
。
'hldid'
指配对数据标识符,
'cid'
是配对的数据日标识符
'pid'
个人标识符
'diary'
日记本(每人必须填写2本日记本)
'sex' 'day' 'main1'
指的是观察到的性别、日期和活动。
我想做的是根据 2 个条件对数据进行子集化:
- 数据必须配对意味着
hldid
必须是2个人。 每对应该由一男一女组成。 - 个人必须填写2个
diary
。所以 4 日记hldid
我发现这样做的唯一方法是执行以下操作:
按性别分开
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行1个人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"
)
在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
听起来您需要按分组变量进行过滤。据我了解,对于每个 hldid
,您要确保 sex
有 2 个不同的值,总共有 4 个观察值。
您可以使用 dplyr 中的 filter
和 group_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 个条目,那么您需要一个稍微不同的策略。也许只是确保每个 id
每个 sex
有 2 个以上的观察值?
dtaSimple %>%
group_by(hldid) %>%
filter(sum(sex == 1) >= 2, sum(sex == 2) >= 2)