R 基于行数较少的级别,每个级别的子集n行

R 基于行数较少的级别,每个级别的子集n行,r,R,假设我有一些具有一定级别数的数据帧: x1 x2 ... xi Level 1 1 1 1 A 2 2 2 4 A 3 1 4 2 B . . . . B . . . . B . . . . C . . .

假设我有一些具有一定级别数的数据帧:

    x1    x2  ...  xi   Level
1    1     1        1       A    
2    2     2        4       A
3    1     4        2       B
.    .     .        .       B 
.    .     .        .       B
.    .     .        .       C
.    .     .        .       C
.    .     .        .       C
我试图以一种所有级别都有n行的方式对数据帧进行子集划分,其中n是具有较少实例的级别的行数。在上面的示例中,A是填充较少的级别(2行),因此所需的输出为:

    x1    x2  ...  xi   Level
1    1     1        1       A    
2    2     2        4       A
3    1     4        2       B
.    .     .        .       B
.    .     .        .       C
.    .     .        .       C
级别和行数是可变的,因此每次都需要检查行数较少的级别。此外,需要以(伪)随机方式选择每个级别的n行,例如,如果我有:

    x1    x2  ...  xi   Level
1    1     1        1       A    
.    .     .        .       .
.    .     .        .       .
.    .     .        .       .
10   1     2        3       C  
11   3     2        1       C  
12   2     1        3       C  
13   3     1        2       C  
14   2     3        1       C
n=3时,我希望避免选择级别C(10,11,12)的前3行。
提前感谢。

这里有一个
dplyr
解决方案:

library(dplyr)
df %>% group_by(Level) %>%  ## group by level
  mutate(count = n()) %>% ## count number of rows for each group
  ungroup() %>%          
  mutate(count = min(count)) %>%  ## select the minimal number of rows 
  group_by(Level) %>%             ## group again to get X rows for each group
  slice(sample(1:n(), min(count))) %>%    ## get the  X random rows
  ungroup() %>% 
  select(-count)             ## remove the added count variable

下面是一个
dplyr
解决方案:

library(dplyr)
df %>% group_by(Level) %>%  ## group by level
  mutate(count = n()) %>% ## count number of rows for each group
  ungroup() %>%          
  mutate(count = min(count)) %>%  ## select the minimal number of rows 
  group_by(Level) %>%             ## group again to get X rows for each group
  slice(sample(1:n(), min(count))) %>%    ## get the  X random rows
  ungroup() %>% 
  select(-count)             ## remove the added count variable

以下解决方案仅使用基本R

n <- min(tapply(Level, Level, length))
inx <- unlist(tapply(seq_along(Level), Level, FUN = function(x) sample(x, n)))
dat[inx, ]
#              x Level
#2   0.414641434     A
#3  -1.539950042     A
#5  -0.294720447     B
#6  -0.005767173     B
#9  -0.799009249     C
#8   0.763593461     C
#14  0.252223448     D
#11 -0.289461574     D
#16  0.435683299     E
#17 -1.237538422     E

n以下解决方案仅使用基本R

n <- min(tapply(Level, Level, length))
inx <- unlist(tapply(seq_along(Level), Level, FUN = function(x) sample(x, n)))
dat[inx, ]
#              x Level
#2   0.414641434     A
#3  -1.539950042     A
#5  -0.294720447     B
#6  -0.005767173     B
#9  -0.799009249     C
#8   0.763593461     C
#14  0.252223448     D
#11 -0.289461574     D
#16  0.435683299     E
#17 -1.237538422     E

nA
dplyr
采用
sample\u frac
方法进行随机化:

library(dplyr)

df %>%
  add_count(Level) %>%
  mutate(
    n = min(n)
  ) %>%
  group_by(Level) %>%
  sample_frac(1) %>%
  slice(1:n) %>%
  select(-n)

采用
dplyr
方法和
sample\u frac
进行随机化:

library(dplyr)

df %>%
  add_count(Level) %>%
  mutate(
    n = min(n)
  ) %>%
  group_by(Level) %>%
  sample_frac(1) %>%
  slice(1:n) %>%
  select(-n)

数据表
解决方案
dat[,.N,Level]
给出每个
级别
组的行数,然后
min(N)
minN
是最小的行数。下一行从每组中获取顶部的
minN

library(data.table)
setDT(dat)

minN <- dat[, .N, Level][, min(N)]
dat[, head(.SD, minN), Level]

#     Level          x
#  1:     A  1.2724293
#  2:     A  0.4146414
#  3:     B -0.9285670
#  4:     B -0.2947204
#  5:     C  2.4046534
#  6:     C  0.7635935
#  7:     D -0.2894616
#  8:     D -0.2992151
#  9:     E  0.4356833
# 10:     E -1.2375384
或者使用arg0naut评论中的解决方案

dat[, .SD[sample(.N, minN)], by = Level]
如果你愿意牺牲一些可读性来提高速度,另一个选择是

dat[dat[, sample(.I, minN), Level]$V1]
使用的数据(来自Rui Barradas的回答)

set.seed(1)

s
数据。表
解决方案
dat[,.N,Level]
给出每个
级别
组的行数,然后
min(N)
minN
是最小的行数。下一行从每组中获取顶部的
minN

library(data.table)
setDT(dat)

minN <- dat[, .N, Level][, min(N)]
dat[, head(.SD, minN), Level]

#     Level          x
#  1:     A  1.2724293
#  2:     A  0.4146414
#  3:     B -0.9285670
#  4:     B -0.2947204
#  5:     C  2.4046534
#  6:     C  0.7635935
#  7:     D -0.2894616
#  8:     D -0.2992151
#  9:     E  0.4356833
# 10:     E -1.2375384
或者使用arg0naut评论中的解决方案

dat[, .SD[sample(.N, minN)], by = Level]
如果你愿意牺牲一些可读性来提高速度,另一个选择是

dat[dat[, sample(.I, minN), Level]$V1]
使用的数据(来自Rui Barradas的回答)

set.seed(1)

它可以正常工作,但是它会选择每个级别的前n行(它应该以随机方式选择n行),可能是使用“createDataPartition()”?谢谢@Pepv请看下面我的答案,这是一个简洁的版本,带有用于随机化的
sample\u frac
。添加了一个
sample
。它工作正常,但它选择每个级别的前n行(它应该以随机方式选择n行),可能使用“createDataPartition()”?谢谢@Pepv请看下面我的答案,这是一个简洁的版本,带有用于随机化的
sample\u frac
。添加了一个
sample
1
的一小部分就是一切。是的,但它会排列行,以便随后随机切片。否则,只对初始数据集的前两行进行切片。
1
的一小部分就是一切。是的,但它会排列这些行,以便随后对它们进行随机切片。否则,只对初始数据集的前两行进行切片。
minN
minN