質問

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

これにより、ファセットのプロットを行う、または因子レベルに依存する機能を使用すると、頭痛が生じます。

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

これが私の例です:

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    

## but the levels are still there!
levels(subdf$letters)
## [1] "a" "b" "c" "d" "e"
役に立ちましたか?

解決

あなたがしなければならないのは、サブセット後に再度変数に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)

他のヒント

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

levels(droplevels(subdf$letters))

この動作が必要ない場合は、要因を使用しないでください。代わりに文字ベクトルを使用してください。これは、後で物事をパッチアップするよりも理にかなっていると思います。データをロードする前に、以下を試してください read.table また read.csv:

options(stringsAsFactors = FALSE)

欠点は、アルファベット順の注文に制限されていることです。 (Reorderはあなたの友人ですプロットは)

それは既知の問題であり、1つの考えられる治療法がによって提供されます 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"

同じことをする別の方法があるが dplyr

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

編集:

また動作します!ありがとう アジェニス

subdf <- df %>% filter(numbers <= 3) %>% droplevels
levels(subdf$letters)

完全性のために、今も 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

これが別の方法です。 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"

を見ています 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")

うまくいきません。

これは明らかに多くのレベルがある場合に理想的ではありませんが、数回は迅速かつ簡単です。

これを行うためにユーティリティ関数を書きました。 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
}

これがそれを行う方法です

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

残念ながら、RevoscalerのrxDatastepを使用する場合、要因()は機能しないようです。 2つのステップで行います。1)文字に変換し、一時的な外部データフレーム(.xdf)に保存します。 2)ファクターに戻し、決定的な外部データフレームに保存します。これにより、すべてのデータをメモリにロードすることなく、使用されていない因子レベルが排除されます。

# Step 1) Converts to character, in temporary xdf file:
rxDataStep(inData = "input.xdf", outFile = "temp.xdf", transforms = list(VAR_X = as.character(VAR_X)), overwrite = T)
# Step 2) Converts back to factor:
rxDataStep(inData = "temp.xdf", outFile = "output.xdf", transforms = list(VAR_X = as.factor(VAR_X)), overwrite = T)

私の場合、すべてではないにしても、ここでほとんどの例を試してみましたが、誰も機能していないようです。かなり長い間苦労した後、私は使用しようとしました as.character() 係数列で、それをコルに変更して、弦が正常に機能するように見える文字列を備えています。

パフォーマンスの問題がわからない。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top