580

を含むデータ フレームがありfactorます。subsetまたは別のインデックス関数を使用してこのデータフレームのサブセットを作成すると、新しいデータ フレームが作成されます。ただし、factor変数は、新しいデータフレームに存在しない場合でも、元のレベルをすべて保持します。

これは、ファセット プロットを実行するとき、または因子レベルに依存する関数を使用するときに問題を引き起こします。

新しいデータフレームの因子からレベルを削除する最も簡潔な方法は何ですか?

次に例を示します。

df <- data.frame(letters=letters[1:5],
                    numbers=seq(1:5))

levels(df$letters)
## [1] "a" "b" "c" "d" "e"

subdf <- subset(df, numbers <= 3)
##   letters numbers
## 1       a       1
## 2       b       2
## 3       c       3    

# all levels are still there!
levels(subdf$letters)
## [1] "a" "b" "c" "d" "e"
4

16 に答える 16

515

R バージョン 2.12 以降、droplevels()関数があります。

levels(droplevels(subdf$letters))
于 2010-11-26T11:37:26.927 に答える
447

あなたがしなければならないのは、サブセット化後に再びfactor()を変数に適用することです:

> 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)
于 2009-07-28T22:41:31.177 に答える
47

この動作が望ましくない場合は、係数を使用せず、代わりに文字ベクトルを使用してください。これは後でパッチを当てるよりも理にかなっていると思います。read.tableまたはを使用してデータをロードする前に、次のことを試してくださいread.csv

options(stringsAsFactors = FALSE)

欠点は、アルファベット順に制限されることです。(再注文はプロットの友達です)

于 2009-07-28T23:53:43.217 に答える
40

これは既知の問題であり、考えられる解決策の 1 つはgdataパッケージで提供さdrop.levels()れ、例は次のようになります。

> drop.levels(subdf)
  letters numbers
1       a       1
2       b       2
3       c       3
> levels(drop.levels(subdf)$letters)
[1] "a" "b" "c"

HmiscパッケージにもそのdropUnusedLevels機能があります。ただし、サブセット演算子を変更することによってのみ機能し、ここでは適用できません。[

結果として、列ごとの直接的なアプローチは単純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"
于 2009-07-28T18:37:13.697 に答える
26

同じことを行う別の方法ですが、dplyr

library(dplyr)
subdf <- df %>% filter(numbers <= 3) %>% droplevels()
str(subdf)

編集:

また動作します!アニスのおかげで

subdf <- df %>% filter(numbers <= 3) %>% droplevels
levels(subdf$letters)
于 2015-07-15T11:14:54.800 に答える
15

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"
于 2009-07-29T03:40:37.317 に答える
8

これは不快です。これは、他のパッケージのロードを回避するために、私が通常行う方法です。

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")

動作しません。

レベルがたくさんある場合、これは明らかに理想的ではありませんが、少数の場合は、すばやく簡単に実行できます。

于 2009-07-28T18:44:32.980 に答える
8

R ソースdroplevelsのメソッドコードを見ると、関数にラップされていることがわかります。つまり、基本的に関数を使用して列を再作成できます。 すべての因子列からレベルを削除する data.table の方法の下。 factorfactor

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"
于 2015-12-09T14:56:58.950 に答える
7

ここにそれを行う方法があります

varFactor <- factor(letters[1:15])
varFactor <- varFactor[1:5]
varFactor <- varFactor[drop=T]
于 2014-01-31T03:25:56.747 に答える
6

これを行うためのユーティリティ関数を作成しました。gdata の drop.levels について知ったので、かなり似ているように見えます。ここにそれらがあります(ここから):

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
}
于 2009-09-01T20:37:36.437 に答える
4

非常に興味深いスレッドです。サブセレクションを再び因数分解するというアイデアが特に気に入りました。以前も同様の問題があり、文字に変換してから因子に戻しました。

   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))
于 2015-05-25T12:08:08.590 に答える
0

この質問を投稿していただきありがとうございます。ただし、上記の解決策はどれもうまくいきませんでした。この問題の回避策を作成し、他の人がこの問題に遭遇した場合に備えて共有しました。

値がゼロのレベルを含むすべてのfactor列について、最初にそれらの列をcharacter型に変換し、次にそれらを に戻すことができfactorsます。

上記の質問については、次のコード行を追加するだけです。

# Convert into character
subdf$letters = as.character(subdf$letters)

# Convert back into factor
subdf$letters = as.factor(subdf$letters)

# Verify the levels in the subset
levels(subdf$letters)
于 2021-12-29T00:53:13.640 に答える