折りたたむ必要がある複数のレベルを含む要因をクリーンアップする最も効果的な(つまり効率的/適切な)方法は何ですか?つまり、2つ以上の因子レベルを1つに結合する方法です。
次に、2つのレベル「はい」と「Y」を「はい」に、「いいえ」と「N」を「いいえ」に折りたたむ例を示します。
## Given:
x <- c("Y", "Y", "Yes", "N", "No", "H") # The 'H' should be treated as NA
## expectedOutput
[1] Yes Yes Yes No No <NA>
Levels: Yes No # <~~ NOTICE ONLY **TWO** LEVELS
もちろん、1つのオプションは、sub
とフレンドを使用して、文字列を事前にクリーンアップすることです。
別の方法は、ラベルの重複を許可してからドロップすることです
## Duplicate levels ==> "Warning: deprecated"
x.f <- factor(x, levels=c("Y", "Yes", "No", "N"), labels=c("Yes", "Yes", "No", "No"))
## the above line can be wrapped in either of the next two lines
factor(x.f)
droplevels(x.f)
ただし、より効果的な方法はありますか?
levels
とlabels
の引数はベクトルでなければならないことは知っていますが、リストと名前付きリストと名前付きベクトルを試して、何が起こるかを確認しました。私の目標。
factor(x, levels=list(c("Yes", "Y"), c("No", "N")), labels=c("Yes", "No"))
factor(x, levels=c("Yes", "No"), labels=list(c("Yes", "Y"), c("No", "N")))
factor(x, levels=c("Y", "Yes", "No", "N"), labels=c(Y="Yes", Yes="Yes", No="No", N="No"))
factor(x, levels=c("Y", "Yes", "No", "N"), labels=c(Yes="Y", Yes="Yes", No="No", No="N"))
factor(x, levels=c("Yes", "No"), labels=c(Y="Yes", Yes="Yes", No="No", N="No"))
levels
関数を使用して、名前のリストを渡します。名前はレベルの目的の名前で、要素は名前を変更する必要がある現在の名前です。
x <- c("Y", "Y", "Yes", "N", "No", "H")
x <- factor(x)
levels(x) <- list(Yes=c("Y", "Yes"), No=c("N", "No"))
x
## [1] Yes Yes Yes No No <NA>
## Levels: Yes No
levels
のドキュメントに記載されているとおり。例を参照してください。
値: 'factor'メソッドの場合、少なくとも 'x'のレベル数の長さを持つ文字列のベクトル、またはレベルの名前を変更する方法を指定する名前付きリスト。
これは、Marekがここで行うように、1行で行うこともできます。 https://stackoverflow.com/a/10432263/21067 ; levels<-
ソーサリーはここで説明されています https://stackoverflow.com/a/10491881/21067 。
> `levels<-`(factor(x), list(Yes=c("Y", "Yes"), No=c("N", "No")))
[1] Yes Yes Yes No No <NA>
Levels: Yes No
質問のタイトルはファクタレベルのクリーンアップ(複数のレベル/ラベルの折りたたみ)であるため、完全を期すためにforcats
パッケージもここに記載する必要があります。 forcats
は2016年8月にCRANに登場しました。
因子レベルのクリーンアップに使用できる便利な機能がいくつかあります。
_x <- c("Y", "Y", "Yes", "N", "No", "H")
library(forcats)
_
_fct_collapse(x, Yes = c("Y", "Yes"), No = c("N", "No"), NULL = "H")
#[1] Yes Yes Yes No No <NA>
#Levels: No Yes
_
_fct_recode(x, Yes = "Y", Yes = "Yes", No = "N", No = "No", NULL = "H")
#[1] Yes Yes Yes No No <NA>
#Levels: No Yes
_
_fun <- function(z) {
z[z == "Y"] <- "Yes"
z[z == "N"] <- "No"
z[!(z %in% c("Yes", "No"))] <- NA
z
}
fct_relabel(factor(x), fun)
#[1] Yes Yes Yes No No <NA>
#Levels: No Yes
_
fct_relabel()
は因子レベルで機能するため、最初の引数としてfactorを想定していることに注意してください。他の2つの関数fct_collapse()
とfct_recode()
は、文書化されていない機能である文字ベクトルも受け入れます。
OPによって提供される期待される出力は
_[1] Yes Yes Yes No No <NA>
Levels: Yes No
_
ここで、レベルは、デフォルトとは異なるx
に表示される順序になっています(_?factor
_:因子のレベルはデフォルトでソートされています)。
期待される出力に合わせて、これはfct_inorder()
beforeを使用してレベルを縮小することで実現できます。
_fct_collapse(fct_inorder(x), Yes = c("Y", "Yes"), No = c("N", "No"), NULL = "H")
fct_recode(fct_inorder(x), Yes = "Y", Yes = "Yes", No = "N", No = "No", NULL = "H")
_
両方とも、同じ順序のレベルで期待される出力を返すようになりました。
キーとしての名前付きベクトルが役に立つかもしれません:
> factor(unname(c(Y = "Yes", Yes = "Yes", N = "No", No = "No", H = NA)[x]))
[1] Yes Yes Yes No No <NA>
Levels: No Yes
これはあなたの最後の試みに非常に似ています...しかし、これは動作します:-)
別の方法は、マッピングを含むテーブルを作成することです:
# stacking the list from Aaron's answer
fmap = stack(list(Yes = c("Y", "Yes"), No = c("N", "No")))
fmap$ind[ match(x, fmap$values) ]
# [1] Yes Yes Yes No No <NA>
# Levels: No Yes
# or...
library(data.table)
setDT(fmap)[x, on=.(values), ind ]
# [1] Yes Yes Yes No No <NA>
# Levels: No Yes
私はこの方法を好みます。なぜなら、それは地図を要約する簡単に検査されたオブジェクトを残すからです。 data.tableコードは、その構文の他の結合と同じように見えます。
もちろん、変更を要約するfmap
などのオブジェクトが必要ない場合は、「ワンライナー」にすることができます。
library(data.table)
setDT(stack(list(Yes = c("Y", "Yes"), No = c("N", "No"))))[x, on=.(values), ind ]
# [1] Yes Yes Yes No No <NA>
# Levels: No Yes
この回答を追加して、データフレーム内の特定の要素で機能する受け入れられた回答を示します。これは、最初は明らかではなかったためです(おそらくそうなっているはずですが)。
levels(df$var1)
# "0" "1" "Z"
summary(df$var1)
# 0 1 Z
# 7012 2507 8
levels(df$var1) <- list("0"=c("Z", "0"), "1"=c("1"))
levels(df$var1)
# "0" "1"
summary(df$var1)
# 0 1
# 7020 2507
私はあなたの本当のユースケースを知りませんが、strtrim
はここで役に立つでしょう...
factor( strtrim( x , 1 ) , levels = c("Y" , "N" ) , labels = c("Yes" , "No" ) )
#[1] Yes Yes Yes No No <NA>
#Levels: Yes No
@Aaronのアプローチに似ていますが、もう少し簡単です:
x <- c("Y", "Y", "Yes", "N", "No", "H")
x <- factor(x)
# levels(x)
# [1] "H" "N" "No" "Y" "Yes"
# NB: the offending levels are 1, 2, & 4
levels(x)[c(1,2,4)] <- c(NA, "No", "Yes")
x
# [1] Yes Yes Yes No No <NA>
# Levels: No Yes
以下の機能を使用して、複数の要素を結合/折りたたみできます。
combofactor <- function(pattern_vector,
replacement_vector,
data) {
levels <- levels(data)
for (i in 1:length(pattern_vector))
levels[which(pattern_vector[i] == levels)] <-
replacement_vector[i]
levels(data) <- levels
data
}
例:
Xを初期化する
x <- factor(c(rep("Y",20),rep("N",20),rep("y",20),
rep("yes",20),rep("Yes",20),rep("No",20)))
構造を確認する
str(x)
# Factor w/ 6 levels "N","No","y","Y",..: 4 4 4 4 4 4 4 4 4 4 ...
次の機能を使用します。
x_new <- combofactor(c("Y","N","y","yes"),c("Yes","No","Yes","Yes"),x)
構造を再確認します。
str(x_new)
# Factor w/ 2 levels "No","Yes": 2 2 2 2 2 2 2 2 2 2 ...
最初に、この特定のケースでは部分一致を使用できることに注意しましょう。
x <- c("Y", "Y", "Yes", "N", "No", "H")
y <- c("Yes","No")
x <- factor(y[pmatch(x,y,duplicates.ok = TRUE)])
# [1] Yes Yes Yes No No <NA>
# Levels: No Yes
より一般的なケースでは、dplyr::recode
:
library(dplyr)
x <- c("Y", "Y", "Yes", "N", "No", "H")
y <- c(Y="Yes",N="No")
x <- recode(x,!!!y)
x <- factor(x,y)
# [1] Yes Yes Yes No No <NA>
# Levels: Yes No
開始点が要因の場合、わずかに変更されます。
x <- factor(c("Y", "Y", "Yes", "N", "No", "H"))
y <- c(Y="Yes",N="No")
x <- recode_factor(x,!!!y)
x <- factor(x,y)
# [1] Yes Yes Yes No No <NA>
# Levels: Yes No
R 3.5.0(2018-04-23)以降、これを明確でシンプルな1行で実行できます。
x = c("Y", "Y", "Yes", "N", "No", "H") # The 'H' should be treated as NA
tmp = factor(x, levels= c("Y", "Yes", "N", "No"), labels= c("Yes", "Yes", "No", "No"))
tmp
# [1] Yes Yes Yes No No <NA>
# Levels: Yes No
1行、複数の値を同じレベルにマッピングし、欠落レベルのNAを設定します」– h/t @Aaron