Давайте посмотрим на лес сначала, прежде чем смотреть на деревья.
Здесь есть много информативных ответов с большими подробностями, я не буду повторять ни одного из них. Ключ к программированию в JavaScript имеет сначала правильную ментальную модель общего исполнения.
Хорошие новости заключается в том, что, если вы хорошо понимаете этот момент, вам никогда не придется беспокоиться о гоночных условиях. Прежде всего вы должны понимать, как вы хотите упорядочить свой код как по существу ответ на разные дискретные события, и как вы хотите объединить их в логическую последовательность. Вы можете использовать обещания или новые асинхронные / ожидающие более высокие уровни в качестве инструментов для этой цели, или вы можете откатывать свои собственные.
Но вы не должны использовать какие-либо тактические инструменты для решения проблемы, пока вам не понравится актуальная проблемная область. Нарисуйте карту этих зависимостей, чтобы знать, что нужно запускать, когда. Попытка ad-hoc подхода ко всем этим обратным вызовам просто не поможет вам.
Все, что вам нужно сделать, это снова применить множитель () к вашей переменной после подмножества:
> subdf$letters
[1] a b c
Levels: a b c d e
subdf$letters <- factor(subdf$letters)
> subdf$letters
[1] a b c
Levels: a b c
ИЗМЕНИТЬ
Пример примера с параметрами:
factor(ff) # drops the levels that do not occur
Для удаления уровней из всех столбцов факторов в кадре данных вы можете использовать:
subdf <- subset(df, numbers <= 3)
subdf[] <- lapply(subdf, function(x) if(is.factor(x)) factor(x) else x)
Вот еще один способ, который, я считаю, эквивалентен подходу factor(..)
:
> df <- data.frame(let=letters[1:5], num=1:5)
> subdf <- df[df$num <= 3, ]
> subdf$let <- subdf$let[ , drop=TRUE]
> levels(subdf$let)
[1] "a" "b" "c"
Для полноты, теперь есть fct_drop
в пакете forcats
http://forcats.tidyverse.org/reference/fct_drop.html .
Он отличается от droplevels
тем, как он имеет дело с NA
:
f <- factor(c("a", "b", NA), exclude = NULL)
droplevels(f)
# [1] a b <NA>
# Levels: a b <NA>
forcats::fct_drop(f)
# [1] a b <NA>
# Levels: a b
Я написал служебные функции для этого. Теперь, когда я знаю о drop.levels gdata, он выглядит довольно похожим. Здесь они (из здесь ):
present_levels <- function(x) intersect(levels(x), x)
trim_levels <- function(...) UseMethod("trim_levels")
trim_levels.factor <- function(x) factor(x, levels=present_levels(x))
trim_levels.data.frame <- function(x) {
for (n in names(x))
if (is.factor(x[,n]))
x[,n] = trim_levels(x[,n])
x
}
Другой способ сделать то же самое, но с dplyr
library(dplyr)
subdf <- df %>% filter(numbers <= 3) %>% droplevels()
str(subdf)
Изменить:
Также работает! Благодаря agenis
subdf <- df %>% filter(numbers <= 3) %>% droplevels
levels(subdf$letters)
здесь есть способ сделать это
varFactor <- factor(letters[1:15])
varFactor <- varFactor[1:5]
varFactor <- varFactor[drop=T]
Очень интересная нить, мне особенно понравилась идея просто подставить подзаголовок снова. Раньше у меня была аналогичная проблема, и я просто перешел к символу, а затем вернулся к коэффициенту.
df <- data.frame(letters=letters[1:5],numbers=seq(1:5))
levels(df$letters)
## [1] "a" "b" "c" "d" "e"
subdf <- df[df$numbers <= 3]
subdf$letters<-factor(as.character(subdf$letters))
Это известная проблема, и одно возможное решение предоставляется drop.levels()
в пакете gdata , где ваш пример становится
> drop.levels(subdf)
letters numbers
1 a 1
2 b 2
3 c 3
> levels(drop.levels(subdf)$letters)
[1] "a" "b" "c"
Существует также dropUnusedLevels
в пакете Hmisc . Однако он работает только путем изменения оператора подмножества [
и здесь неприменим.
В качестве следствия прямой подход на основе столбца является простым as.factor(as.character(data))
:
> levels(subdf$letters)
[1] "a" "b" "c" "d" "e"
> subdf$letters <- as.factor(as.character(subdf$letters))
> levels(subdf$letters)
[1] "a" "b" "c"
Если вы не хотите этого поведения, не используйте факторы, используйте вместо него векторы символов. Я думаю, что это имеет больше смысла, чем исправление. Попробуйте выполнить следующие действия перед загрузкой данных с помощью read.table
или read.csv
:
options(stringsAsFactors = FALSE)
Недостатком является то, что вы ограничены алфавитным порядком. (переупорядочить ваш друг для сюжетов)
Глядя на код droplevels
методов в источнике R, вы можете видеть , он обтекает функцию factor
. Это означает, что вы можете в основном воссоздать столбец с функцией factor
. Ниже data.table способ сбросить уровни из всех столбцов факторов.
library(data.table)
dt = data.table(letters=factor(letters[1:5]), numbers=seq(1:5))
levels(dt$letters)
#[1] "a" "b" "c" "d" "e"
subdt = dt[numbers <= 3]
levels(subdt$letters)
#[1] "a" "b" "c" "d" "e"
upd.cols = sapply(subdt, is.factor)
subdt[, names(subdt)[upd.cols] := lapply(.SD, factor), .SDcols = upd.cols]
levels(subdt$letters)
#[1] "a" "b" "c"
Это неприятно. Так я обычно делаю это, чтобы не загружать другие пакеты:
levels(subdf$letters)<-c("a","b","c",NA,NA)
, который получает вас:
> subdf$letters
[1] a b c
Levels: a b c
Обратите внимание, что новые уровни заменят все, что занимает их индекс в старые значения (subdf $ letters), поэтому что-то вроде:
levels(subdf$letters)<-c(NA,"a","c",NA,"b")
не будет работать.
Это, очевидно, не идеально, когда у вас много уровней, но для Несколько, это быстро и легко.
Поскольку R версии 2.12, есть функция droplevels()
.
levels(droplevels(subdf$letters))