19

元のデータ フレーム:

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年
2 単三
3cc
4バ
5cc
6cb
7AA
8 ab
9ac
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

小さなデータセットの場合はこれで問題ありませんが、はるかに大きなデータセットの場合は遅くなります。

ループを使用せずにこれを行う方法を知っている人はいますか?

4

7 に答える 7

24

@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

これがあなたが探しているものだと思います。違っていたら削除していただけると幸いです。@G.Grothendieck (もう一度) の優れた使い方に感謝しますmodel.matrix!

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。かなり明白ですが、それでも、as.data.frame(.)必要な場合は でラップしますdata.frame

于 2013-04-24T19:19:10.643 に答える
9

必要なことを行うキャレットのパッケージには、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

于 2015-01-17T03:54:39.660 に答える
4

ここに向けられたクローズドな質問を見たところ、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 つの列だけに適用することもできます。

于 2017-12-18T15:58:24.283 に答える
3

私は最近、別の方法に出くわしました。contrastsに設定してコントラスト関数のいずれかを実行すると、FALSE1 つのホット エンコーディングが得られることに気付きました。たとえば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
于 2016-03-31T21:43:37.400 に答える
3

かなり直接的なアプローチは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」列が存在することを確認しました。

于 2013-04-25T07:10:29.753 に答える