基于每组行数的子集数据帧

SJS*_*013 23 r subset dataframe r-faq

我有这样的数据,其中一些"名称"出现超过3次:

df <- data.frame(name = c("a", "a", "a", "b", "b", "c", "c", "c", "c"), x = 1:9)

  name x
1    a 1
2    a 2
3    a 3
4    b 4
5    b 5
6    c 6
7    c 7
8    c 8
9    c 9
Run Code Online (Sandbox Code Playgroud)

我希望根据"name"变量的每个级别内的行数(观察值)对数据进行子集化(过滤).如果某个级别的"名称"出现超过3次,我想删除属于该级别的所有行.

我写了这段代码,但无法让它工作.

  name x
1    a 1
2    a 2
3    a 3
4    b 4
5    b 5
Run Code Online (Sandbox Code Playgroud)

Hen*_*rik 50

首先,两个base替代方案.一个依靠table,和其他的avelength.然后,两种data.table方式.


1. table

tt <- table(df$name)

df2 <- subset(df, name %in% names(tt[tt < 3]))
# or
df2 <- df[df$name %in% names(tt[tt < 3]), ]
Run Code Online (Sandbox Code Playgroud)

如果你想逐步完成它:

# count each 'name', assign result to an object 'tt'
tt <- table(df$name)

# which 'name' in 'tt' occur more than three times?
# Result is a logical vector that can be used to subset the table 'tt'
tt < 3

# from the table, select 'name' that occur < 3 times
tt[tt < 3]

# ...their names
names(tt[tt < 3])

# rows of 'name' in the data frame that matches "the < 3 names"
# the result is a logical vector that can be used to subset the data frame 'df'
df$name %in% names(tt[tt < 3])

# subset data frame by a logical vector
# 'TRUE' rows are kept, 'FALSE' rows are removed.
# assign the result to a data frame with a new name
df2 <- subset(df, name %in% names(tt[tt < 3]))
# or
df2 <- df[df$name %in% names(tt[tt < 3]), ]
Run Code Online (Sandbox Code Playgroud)

2. avelength

正如@flodel所建议的那样:

df[ave(df$x, df$name, FUN = length) < 3, ]
Run Code Online (Sandbox Code Playgroud)

3 data.table.:.N.SD:

library(data.table)
setDT(df)[, if (.N < 3) .SD, by = name]
Run Code Online (Sandbox Code Playgroud)

4 data.table:.N.I:

setDT(df)
df[df[, .I[.N < 3], name]$V1] 
Run Code Online (Sandbox Code Playgroud)

另请参阅每组的相关Q&A 计数观察/行数,并将结果添加到数据框.

  • 更短的是:`df [ave(df $ x,df $ name,FUN = length)<3,]` (3认同)
  • @flodel,谢谢!我同意,我只是试图保持它非常简单并建立在已经尝试过的OP上,因为它们似乎是一个初学者 (2认同)

Joe*_*Joe 31

使用dplyr包:

df %>%
  group_by(name) %>%
  filter(n() < 4)

# A tibble: 5 x 2
# Groups:   name [2]
  name      x
  <fct> <int>
1 a         1
2 a         2
3 a         3
4 b         4
5 b         5
Run Code Online (Sandbox Code Playgroud)