在 df 中找到两个变量中的第一次出现

find first occurrence in two variables in df

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

但是,我的代码是从第一组 试验中找到 c(1,4) 并为每个组重复该过程试验:

   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 行。

谢谢,

我想这就是你想要的:

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 版本)

要尝试更接近您迄今为止尝试过的解决方案,我们可以执行以下操作

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, ]
})

一些解释

您提供的代码的一个问题是您在 ddply 中使用了 df。因此,您定义了 fun= function(x),但您没有在 x 中而是在 df 中查找 x> 30 & y> 30 的情况。此外,您的代码使用 i 作为 x,但 i 是用 df 定义的。最后,根据我的理解,不需要 if (!is.na(i)) x[i, ]。如果只有一行符合你的条件,你会得到一行 NAs 无论如何,因为你使用 which(df_temp$x > 30 & df_temp$y >30 )[1:2].

我建议使用 dplyrdata.table 而不是 plyr。来自 plyr github 页面:

plyr is retired: this means only changes necessary to keep it on CRAN will be made. We recommend using dplyr (for data frames) or purrr (for lists) instead.

由于有人已经提供了 dplyr 的解决方案,这里是 data.table 的一个选项。

在选择 df[i, j, k] 中,我在 i 中选择符合您的条件的行,在 k 中按给定变量分组,然后选择前两行(head) 数据 .SD 的每个 group-specific 个子集。括号内的所有这些都是 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

由于此处涵盖的所有其他内容是使用 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

使用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