数値列と順序付けられた因子列を持つデータフレームがあります。多くのNA値があるため、レベルは割り当てられません。 NAを「無回答」に変更しましたが、因子列のレベルにそのレベルが含まれていないため、ここで始めましたが、エレガントな方法で終了する方法がわかりません。
addNoAnswer = function(df) {
factorOrNot = sapply(df, is.factor)
levelsList = lapply(df[, factorOrNot], levels)
levelsList = lapply(levelsList, function(x) c(x, "No Answer"))
...
因子列に新しいレベルを直接適用する方法はありますか?
df[, factorOrNot] = lapply(df[, factorOrNot], factor, levelsList)
もちろん、これは正しく機能しません。
レベルの順序を保持し、最後の場所に「無回答」レベルを追加したい。
因子にレベルを追加する関数を定義することもできますが、それ以外のものを返すだけです:
addNoAnswer <- function(x){
if(is.factor(x)) return(factor(x, levels=c(levels(x), "No Answer")))
return(x)
}
次に、この関数を列にlapply
するだけです
df <- as.data.frame(lapply(df, addNoAnswer))
それはあなたが望むものを返すはずです。
levels
関数は、levels(x) <- value
呼び出しを受け入れます。したがって、異なるレベルを追加するのは非常に簡単です。
f1 <- factor(c("a", "a", NA, NA, "b", NA, "a", "c", "a", "c", "b"))
str(f1)
Factor w/ 3 levels "a","b","c": 1 1 NA NA 2 NA 1 3 1 3 ...
levels(f1) <- c(levels(f1),"No Answer")
f1[is.na(f1)] <- "No Answer"
str(f1)
Factor w/ 4 levels "a","b","c","No Answer": 1 1 4 4 2 4 1 3 1 3 ...
次に、data.frame内のすべての変数をループします。
f1 <- factor(c("a", "a", NA, NA, "b", NA, "a", "c", "a", "c", "b"))
f2 <- factor(c("c", NA, "b", NA, "b", NA, "c" ,"a", "d", "a", "b"))
f3 <- factor(c(NA, "b", NA, "b", NA, NA, "c", NA, "d" , "e", "a"))
df1 <- data.frame(f1,n1=1:11,f2,f3)
str(df1)
'data.frame': 11 obs. of 4 variables:
$ f1: Factor w/ 3 levels "a","b","c": 1 1 NA NA 2 NA 1 3 1 3 ...
$ n1: int 1 2 3 4 5 6 7 8 9 10 ...
$ f2: Factor w/ 4 levels "a","b","c","d": 3 NA 2 NA 2 NA 3 1 4 1 ...
$ f3: Factor w/ 5 levels "a","b","c","d",..: NA 2 NA 2 NA NA 3 NA 4 5 ...
for(i in 1:ncol(df1)) if(is.factor(df1[,i])) levels(df1[,i]) <- c(levels(df1[,i]),"No Answer")
df1[is.na(df1)] <- "No Answer"
str(df1)
'data.frame': 11 obs. of 4 variables:
$ f1: Factor w/ 4 levels "a","b","c","No Answer": 1 1 4 4 2 4 1 3 1 3 ...
$ n1: int 1 2 3 4 5 6 7 8 9 10 ...
$ f2: Factor w/ 5 levels "a","b","c","d",..: 3 5 2 5 2 5 3 1 4 1 ...
$ f3: Factor w/ 6 levels "a","b","c","d",..: 6 2 6 2 6 6 3 6 4 5 ...
ilir's answer とそのコメントを展開すると、列が要素であり、新しいレベルがまだ含まれていないことを確認し、レベルを追加して、関数を再実行可能にすることができます。
addLevel <- function(x, newlevel=NULL) {
if(is.factor(x)) {
if (is.na(match(newlevel, levels(x))))
return(factor(x, levels=c(levels(x), newlevel)))
}
return(x)
}
その後、次のように適用できます。
dataFrame$column <- addLevel(dataFrame$column, "newLevel")
この質問への最後の回答以来、forcats
パッケージのfct_explicit_na()
を使用してこれが可能になりました。ここにドキュメントに記載されている例を追加します。
f1 <- factor(c("a", "a", NA, NA, "a", "b", NA, "c", "a", "c", "b"))
table(f1)
# f1
# a b c
# 4 2 2
f2 <- forcats::fct_explicit_na(f1)
table(f2)
# f2
# a b c (Missing)
# 4 2 2 3
デフォルト値は(Missing)
しかし、これはna_level
引数。
列を文字に変換し、次に条件に基づいて新しいレベルを追加し、最後に列を係数に変換する必要があります。
手順1.最初のファクター列の文字への変換:
df$column2 <- as.character(column2)
2.新しいレベルを追加する
df[df$column1=="XYZ",]column2 <- "new_level"
3.再び因子に変換
df$column2 <- as.factor(df$column2)
私はあなたの特定のシナリオに直接対処しないかもしれない非常に簡単な答えを持っていますが、これを一般的に行う簡単な方法です
levels(df$column) <- c(levels(df$column), newFactorLevel)
因子の場合、レベルは因子変数の一意の各値に割り当てられた数値です。要因を使用する利点は、カテゴリ変数が視覚化に適していることです。因子変数の元の値は、数値であっても文字として保存されます。したがって、元の値を取得するには、as.characterの変換を最初に使用します。これは、ゼロで始まるレベル番号ではなく、因子値を返します。文字形式の値を取得したら、as.numericを使用して元の数値を取得します。
factor_var.values = as.numeric(as.character(df $ factor_var))