元のデータフレーム:
v1 = sample(letters[1:3], 10, replace=TRUE)
v2 = sample(letters[1:3], 10, replace=TRUE)
df = data.frame(v1,v2)
df
v1 v2 1 bc 2 aa 3 cc 4 ba 5 cc 6 cb 7 aa 8 ab 9 ac 10 ab
新しいデータフレーム:
new_df = data.frame(row.names=rownames(df))
for (i in colnames(df)) {
for (x in letters[1:3]) {
#new_df[x] = as.numeric(df[i] == x)
new_df[paste0(i, "_", x)] = as.numeric(df[i] == x)
}
}
v1_a v1_b v1_c v2_a v2_b v2_c 1 0 1 0 0 0 1 2 1 0 0 1 0 0 3 0 0 1 0 0 1 4 0 1 0 1 0 0 5 0 0 1 0 0 1 6 0 0 1 0 1 0 7 1 0 0 1 0 0 8 1 0 0 0 1 0 9 1 0 0 0 0 1 10 1 0 0 0 1 0
小さなデータセットの場合はこれで問題ありませんが、非常に大きなデータセットの場合は遅くなります。
ループを使用せずにこれを行う方法を知っている人はいますか?
@AnandaMahtoの検索機能の助けを借りて、
_model.matrix(~ . + 0, data=df, contrasts.arg = lapply(df, contrasts, contrasts=FALSE))
# v1a v1b v1c v2a v2b v2c
# 1 0 1 0 0 0 1
# 2 1 0 0 1 0 0
# 3 0 0 1 0 0 1
# 4 0 1 0 1 0 0
# 5 0 0 1 0 0 1
# 6 0 0 1 0 1 0
# 7 1 0 0 1 0 0
# 8 1 0 0 0 1 0
# 9 1 0 0 0 0 1
# 10 1 0 0 0 1 0
_
これはあなたが探しているものだと思います。そうでない場合は削除させていただきます。 @ 優れた使用法 の_model.matrix
_について@ G.Grothendieckに感謝します(もう一度)
_cbind(with(df, model.matrix(~ v1 + 0)), with(df, model.matrix(~ v2 + 0)))
# v1a v1b v1c v2a v2b v2c
# 1 0 1 0 0 0 1
# 2 1 0 0 1 0 0
# 3 0 0 1 0 0 1
# 4 0 1 0 1 0 0
# 5 0 0 1 0 0 1
# 6 0 0 1 0 1 0
# 7 1 0 0 1 0 0
# 8 1 0 0 0 1 0
# 9 1 0 0 0 0 1
# 10 1 0 0 0 1 0
_
注:出力は次のとおりです。
_with(df, model.matrix(~ v2 + 0))
_
注2:これはmatrix
を与えます。かなり明白ですが、_data.frame
_が必要な場合は、as.data.frame(.)
でラップしてください。
キャレットのパッケージには、必要な機能を実行する関数dummyVarsがあります。これは、著者のドキュメントからの使用例です: http://topepo.github.io/caret/preprocess.html
library(earth)
data(etitanic)
dummies <- caret::dummyVars(survived ~ ., data = etitanic)
head(predict(dummies, newdata = etitanic))
pclass.1st pclass.2nd pclass.3rd sex.female sex.male age sibsp parch
1 1 0 0 1 0 29.0000 0 0
2 1 0 0 0 1 0.9167 1 2
3 1 0 0 1 0 2.0000 1 2
4 1 0 0 0 1 30.0000 1 2
5 1 0 0 1 0 25.0000 1 2
6 1 0 0 0 1 48.0000 0 0
Model.matrixオプションは、スパースデータがあり、Matrix::sparse.model.matrix
を使用したい場合に役立ちます。
ここに向けられた閉じられた質問を見たところ、dummies
パッケージの使用についてまだ誰も言及していません:
dummy.data.frame()
の上に構築されたmodel.matrix()
関数を使用して変数を再コード化できますが、構文が簡単で、いくつかの優れたオプションがあり、データフレームを返します。
_> dummy.data.frame(df, sep="_")
v1_a v1_b v1_c v2_a v2_b v2_c
1 0 1 0 0 0 1
2 1 0 0 1 0 0
3 0 0 1 0 0 1
4 0 1 0 1 0 0
5 0 0 1 0 0 1
6 0 0 1 0 1 0
7 1 0 0 1 0 0
8 1 0 0 0 1 0
9 1 0 0 0 0 1
10 1 0 0 0 1 0
_
この関数のいくつかの素晴らしい側面は、新しい名前(_sep=
_)の区切り文字を簡単に指定でき、エンコードされていない変数(_all=F
_)を省略でき、独自のオプション_dummy.classes
_を使用して、エンコードする列のクラスを指定します。
dummy()
関数を使用して、これを1つの列だけに適用することもできます。
私は最近別の方法に出くわしました。 contrasts
をFALSE
に設定してコントラスト関数を実行すると、1つのホットエンコーディングが提供されることに気付きました。たとえば、contr.sum(5, contrasts = FALSE)
は
1 2 3 4 5
1 1 0 0 0 0
2 0 1 0 0 0
3 0 0 1 0 0
4 0 0 0 1 0
5 0 0 0 0 1
すべての要因に対してこの動作を実現するには、新しいコントラスト関数を作成し、それをデフォルトとして設定します。例えば、
contr.onehot = function (n, contrasts, sparse = FALSE) {
contr.sum(n = n, contrasts = FALSE, sparse = sparse)
}
options(contrasts = c("contr.onehot", "contr.onehot"))
model.matrix(~ . - 1, data = df)
これは
v1a v1b v1c v2a v2b v2c
1 0 0 1 0 0 1
2 0 1 0 1 0 0
3 0 0 1 0 1 0
4 1 0 0 0 1 0
5 0 1 0 0 1 0
6 0 1 0 0 0 1
7 1 0 0 0 1 0
8 0 1 0 0 1 0
9 0 1 0 1 0 0
10 0 0 1 0 0 1
かなり直接的なアプローチは、各列でtable
を使用し、data.frame
の行数で列の値を集計することです。
allLevels <- levels(factor(unlist(df)))
do.call(cbind,
lapply(df, function(x) table(sequence(nrow(df)),
factor(x, levels = allLevels))))
# a b c a b c
# 1 0 1 0 0 0 1
# 2 1 0 0 1 0 0
# 3 0 0 1 0 0 1
# 4 0 1 0 1 0 0
# 5 0 0 1 0 0 1
# 6 0 0 1 0 1 0
# 7 1 0 0 1 0 0
# 8 1 0 0 0 1 0
# 9 1 0 0 0 0 1
# 10 1 0 0 0 1 0
"x"でfactor
を使用して、たとえば列に "c"値がない場合でも、出力に "c"列があることを確認します。ゼロ付き。
これは、文字数が事前に指定されていない、より一般的なケースの解決策です。
convertABC <- function(x) {
hold <- rep(0,max(match(as.matrix(df),letters))) # pre-format output
codify <- function(x) { # define function for single char
output <- hold # take empty vector
output[match(x,letters)] <- 1 # place 1 according to letter pos
return(output)
}
to.return <- t(sapply(as.character(x),codify)) # apply it to whole vector
rownames(to.return) <- 1:nrow(to.return) # Nice rownames
colnames(to.return) <- do.call(c,list(letters[1:max(match(as.matrix(df),letters))])) # Nice columnnames
return(to.return)
}
この関数は文字のベクトルを取り、それをバイナリ値に再コード化します。 df
のすべての変数を処理するには:
do.call(cbind,lapply(df,convertABC))