在df

时间:2019-07-15 12:02:04

标签: r vector subset plyr

我需要找到前两次我的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行。

谢谢

5 个答案:

答案 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)

我建议使用dplyrdata.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

的基本R版本
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