我需要找到前两次我的df满足由两个变量分组的特定条件。我正在尝试使用ddply函数,但使用“ .variables”命令却出错了。
因此,在此示例中,我试图在每个组/试验中找到前两次x> 30和y> 30。
我使用ddply的方式是在数据集中给我头两次,然后对每个组重复一次。
set.seed(1)
df <- data.frame((matrix(nrow=200,ncol=5)))
colnames(df) <- c("group","trial","x","y","hour")
df$group <- rep(c("A","B","C","D"),each=50)
df$trial <- rep(c(rep(1,times=25),rep(2,times=25)),times=4)
df[,3:4] <- runif(400,0,50)
df$hour <- rep(1:25,time=8)
library(plyr)
ddply(.data=df, .variables=c("group","trial"), .fun=function(x) {
i <- which(df$x > 30 & df$y >30 )[1:2]
if (!is.na(i)) x[i, ]
})
预期结果:
group trial x y hour
13 A 1 34.3511423 38.161134 13
15 A 1 38.4920710 40.931734 15
36 A 2 33.4233369 34.481392 11
37 A 2 39.7119930 34.470671 12
52 B 1 43.0604738 46.645491 2
65 B 1 32.5435234 35.123126 15
但是,相反,我的代码是从第一个组 trial中找到c(1,4),然后在每个组中重复该过程 trial:
group trial x y hour
1 A 1 34.351142 38.161134 13
2 A 1 38.492071 40.931734 15
3 A 2 5.397181 27.745031 13
4 A 2 20.563721 22.636003 15
5 B 1 22.953286 13.898301 13
6 B 1 32.543523 35.123126 15
如果在组*试用中不存在第二次出现,我还希望有NA行。
谢谢
答案 0 :(得分:3)
我想这就是你想要的:
library(tidyverse)
df %>% group_by(group, trial) %>% filter(x > 30 & y > 30) %>% slice(1:2)
结果:
# A tibble: 16 x 5
# Groups: group, trial [8]
group trial x y hour
<chr> <dbl> <dbl> <dbl> <int>
1 A 1 33.5 46.3 4
2 A 1 32.6 42.7 11
3 A 2 35.9 43.6 4
4 A 2 30.5 42.7 14
5 B 1 33.0 38.1 2
6 B 1 40.5 30.4 7
7 B 2 48.6 33.2 2
8 B 2 34.1 30.9 4
9 C 1 33.0 45.1 1
10 C 1 30.3 36.7 17
11 C 2 44.8 33.9 1
12 C 2 41.5 35.6 6
13 D 1 44.2 34.3 12
14 D 1 39.1 40.0 23
15 D 2 39.4 47.5 4
16 D 2 42.1 40.1 10
(与您的结果略有不同,可能是不同的R版本)
答案 1 :(得分:3)
我建议使用dplyr
或data.table
而不是plyr
。在plyr
github页面上:
plyr已退休:这意味着仅需更改即可将其保留在CRAN上 将被制作。我们建议使用dplyr(用于数据帧)或purrr(用于 列表)。
由于某人已经提供了dplyr
解决方案,因此data.table是一个选项。
在选择df[i, j, k]
中,我选择的行与i
中的条件相匹配,并按k
中的给定变量分组,然后选择前两行(head
数据.SD
的每个特定于组的子集)。括号内的所有这些都是data.table特定的,并且仅能正常工作,因为我首先使用setDT
将df转换为data.table。
library(data.table)
setDT(df)
df[x > 30 & y > 30, head(.SD, 2), by = .(group, trial)]
# group trial x y hour
# 1: A 1 34.35114 38.16113 13
# 2: A 1 38.49207 40.93173 15
# 3: A 2 33.42334 34.48139 11
# 4: A 2 39.71199 34.47067 12
# 5: B 1 43.06047 46.64549 2
# 6: B 1 32.54352 35.12313 15
# 7: B 2 48.03090 38.53685 5
# 8: B 2 32.11441 49.07817 18
# 9: C 1 32.73620 33.68561 1
# 10: C 1 32.00505 31.23571 20
# 11: C 2 32.13977 40.60658 9
# 12: C 2 34.13940 49.47499 16
# 13: D 1 36.18630 34.94123 19
# 14: D 1 42.80658 46.42416 23
# 15: D 2 37.05393 43.24038 3
# 16: D 2 44.32255 32.80812 8
答案 2 :(得分:2)
要尝试更接近您到目前为止尝试过的解决方案,我们可以执行以下操作
ddply(.data=df, .variables=c("group","trial"), .fun=function(df_temp) {
i <- which(df_temp$x > 30 & df_temp$y >30 )[1:2]
df_temp[i, ]
})
一些解释
您提供的代码的一个问题是您在df
内使用了ddply
。因此,您定义了fun= function(x)
,但您没有在x> 30 & y> 30
中寻找x
中的df
情况。此外,您的代码将i
用于x
,但是i
是用df
定义的。最后,据我了解,不需要if (!is.na(i)) x[i, ]
。如果只有一行满足您的条件,则您将使用NA
来获得一行,因为您使用了which(df_temp$x > 30 & df_temp$y >30 )[1:2]
。
答案 3 :(得分:1)
使用dplyr
,您还可以执行以下操作:
df %>%
group_by(group, trial) %>%
slice(which(x > 30 & y > 30)[1:2])
group trial x y hour
<chr> <dbl> <dbl> <dbl> <int>
1 A 1 34.4 38.2 13
2 A 1 38.5 40.9 15
3 A 2 33.4 34.5 11
4 A 2 39.7 34.5 12
5 B 1 43.1 46.6 2
6 B 1 32.5 35.1 15
7 B 2 48.0 38.5 5
8 B 2 32.1 49.1 18
答案 4 :(得分:0)
由于这里介绍的所有其他内容都是使用split
output <- do.call(rbind, lapply(split(df, list(df$group, df$trial)),
function(new_df) new_df[with(new_df, head(which(x > 30 & y > 30), 2)), ]
))
rownames(output) <- NULL
output
# group trial x y hour
#1 A 1 34.351 38.161 13
#2 A 1 38.492 40.932 15
#3 B 1 43.060 46.645 2
#4 B 1 32.544 35.123 15
#5 C 1 32.736 33.686 1
#6 C 1 32.005 31.236 20
#7 D 1 36.186 34.941 19
#8 D 1 42.807 46.424 23
#9 A 2 33.423 34.481 11
#10 A 2 39.712 34.471 12
#11 B 2 48.031 38.537 5
#12 B 2 32.114 49.078 18
#13 C 2 32.140 40.607 9
#14 C 2 34.139 49.475 16
#15 D 2 37.054 43.240 3
#16 D 2 44.323 32.808 8