Подмножество фрейма данных на основе количества строк в группе
У меня есть такие данные, где некоторые "имя" встречаются более 3 раз:
df <- data.frame(name = c("a", "a", "a", "b", "b", "c", "c", "c", "c"), x = 1:9)
Я хочу поместить (отфильтровать) данные на основе количества строк (наблюдений) в пределах каждого уровня переменной "имя". Если определенный уровень "name" встречается более 3 раз, я хочу удалить все строки, принадлежащие этому уровню.
Я написал этот код, но не могу заставить его работать.
as.data.frame(table(unique(df)$name))
subset(df, name > 3)
2 ответа
Первые два base
альтернативы. Один полагается на table
и другой на ave
а также length
, Тогда два 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]), ]
Если вы хотите пройти это шаг за шагом:
# 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]), ]
2. ave
а также length
Как предложено @flodel:
df[ave(df$x, df$name, FUN = length) < 3, ]
3. data.table
: .N
а также .SD
:
library(data.table)
setDT(df)[, if (.N < 3) .SD, by = name]
4. data.table
: .N
а также .I
:
setDT(df)
df[df[, .I[.N < 3], name]$V1]
См. Также число вопросов и ответов, относящихся к количеству наблюдений / строк на группу, и добавьте результат во фрейм данных.
С использованием dplyr
пакет:
df %>%
group_by(name) %>%
filter(n() < 4)
Еще один способ использования dpylr
пакет использует count
функция, а затем выполнить полусоединение с исходным фреймом данных:
library(dplyr)
df %>%
count(name) %>%
filter(n <= 3) %>%
semi_join(df, ., by = "name")
В пакете inops есть несколько полезных инфиксных операторов. В этом частном случае оператор
%in#%
могут выбирать элементы в зависимости от того, сколько раз они встречаются.
library(inops)
df[df$name %in#% 1:3,]
Что возвращает:
name x
1 a 1
2 a 2
3 a 3
4 b 4
5 b 5
Вот
df$name %in#% 1:3
возвращается
TRUE
только для элементов, встречающихся 1, 2 или 3 раза. Если бы вместо этого мы хотели выбрать элементы, которые встречаются 4 раза, мы бы сделали:
df[df$name %in#% 4,]
Со следующим результатом:
name x
6 c 6
7 c 7
8 c 8
9 c 9