情報を失わずに因数を整数\数値に変換する方法は?


599

因子を数値または整数に変換すると、値を数値としてではなく、基礎となるレベルコードを取得します。

f <- factor(sample(runif(5), 20, replace = TRUE))
##  [1] 0.0248644019011408 0.0248644019011408 0.179684827337041 
##  [4] 0.0284090070053935 0.363644931698218  0.363644931698218 
##  [7] 0.179684827337041  0.249704354675487  0.249704354675487 
## [10] 0.0248644019011408 0.249704354675487  0.0284090070053935
## [13] 0.179684827337041  0.0248644019011408 0.179684827337041 
## [16] 0.363644931698218  0.249704354675487  0.363644931698218 
## [19] 0.179684827337041  0.0284090070053935
## 5 Levels: 0.0248644019011408 0.0284090070053935 ... 0.363644931698218

as.numeric(f)
##  [1] 1 1 3 2 5 5 3 4 4 1 4 2 3 1 3 5 4 5 3 2

as.integer(f)
##  [1] 1 1 3 2 5 5 3 4 4 1 4 2 3 1 3 5 4 5 3 2

私はpaste本当の価値を得るために頼らなければなりません:

as.numeric(paste(f))
##  [1] 0.02486440 0.02486440 0.17968483 0.02840901 0.36364493 0.36364493
##  [7] 0.17968483 0.24970435 0.24970435 0.02486440 0.24970435 0.02840901
## [13] 0.17968483 0.02486440 0.17968483 0.36364493 0.24970435 0.36364493
## [19] 0.17968483 0.02840901

因子を数値に変換するより良い方法はありますか?


6
因子のレベルはとにかく(attributes(f))の文字データ型として保存されるので、に問題はないと思いますas.numeric(paste(f))。おそらく、(特定のコンテキストで)そもそもなぜ要因を得ているのかを考えて、それを止めようとする方が良いでしょう。たとえば、dec引数はread.table正しく設定されていますか?
CJB 2016年

データフレームを使用する場合、hablarからの変換を使用できます。df %>% convert(num(column))。または、使用できる因子ベクトルがある場合as_reliable_num(factor_vector)
davsjob

回答:


711

の警告セクションを参照してください?factor

特に、as.numeric因子への適用は無意味であり、暗黙の強制によって発生する可能性があります。係数fをほぼ元の数値に変換することをas.numeric(levels(f))[f]お勧めします。これは、よりもわずかに効率的です as.numeric(as.character(f))

Rに関するFAQにも同様のアドバイスがあります。


なぜas.numeric(levels(f))[f]より効率的ですas.numeric(as.character(f))か?

as.numeric(as.character(f))は事実上なas.numeric(levels(f)[f])ので、length(x)値ではなく値に対して数値への変換を実行していnlevels(x)ます。速度の違いは、レベルが少ない長いベクトルで最も顕著になります。値がほとんど一意である場合、速度に大きな違いはありません。どのように変換しても、この操作がコードのボトルネックになる可能性は低いので、あまり気にしないでください。


いくつかのタイミング

library(microbenchmark)
microbenchmark(
  as.numeric(levels(f))[f],
  as.numeric(levels(f)[f]),
  as.numeric(as.character(f)),
  paste0(x),
  paste(x),
  times = 1e5
)
## Unit: microseconds
##                         expr   min    lq      mean median     uq      max neval
##     as.numeric(levels(f))[f] 3.982 5.120  6.088624  5.405  5.974 1981.418 1e+05
##     as.numeric(levels(f)[f]) 5.973 7.111  8.352032  7.396  8.250 4256.380 1e+05
##  as.numeric(as.character(f)) 6.827 8.249  9.628264  8.534  9.671 1983.694 1e+05
##                    paste0(x) 7.964 9.387 11.026351  9.956 10.810 2911.257 1e+05
##                     paste(x) 7.965 9.387 11.127308  9.956 11.093 2419.458 1e+05

4
タイミングについては、この答えを参照してください。stackoverflow.com/questions/6979625/...
アリB.フリードマン

3
ソリューションに感謝します。as.numeric(levels(f))[f]がより正確で高速な理由を尋ねることはできますか?ありがとう。
サム

7
@Sam as.character(f)は、as.numeric(levels(f))[f]として定義されている関数as.character.factor()を見つけるための「プリミティブルックアップ」を必要とします。
ジョナサン

12
as.numeric(levels(f))[f]またはas.numeric(as.character(f))を適用すると、次の警告メッセージが表示されます。警告メッセージ:強制によって導入されたNA。問題がどこにあるか知っていますか?ありがとうございました !
Maycca

@mayccaこの問題を克服しましたか?
user08041991 2017年

91

Rには、係数を変換するための(文書化されていない)便利な関数がいくつかあります。

  • as.character.factor
  • as.data.frame.factor
  • as.Date.factor
  • as.list.factor
  • as.vector.factor
  • ...

しかしうるさく、扱いには何もありません>数値-要因変換が。ジョシュア・ウルリッヒの答えの延長として、私はあなた自身の慣用的な関数の定義でこの省略を克服することを提案します:

as.numeric.factor <- function(x) {as.numeric(levels(x))[x]}

スクリプトの最初に保存することも、.Rprofileファイルに保存することもできます。


14
as.integer(factor)(の例のセクションに示すように)基になる整数コードを返すことが期待されているため、係数から整数(または数値)への変換を処理するものはありません?factor。この関数をグローバル環境で定義してもかまいませんが、実際にS3メソッドとして登録すると問題が発生する可能性があります。
Joshua Ulrich 14

1
それは良い点であり、私も同意します。因数->数値変換の完全な再定義は、多くのことを台無しにする可能性があります。実際にRの欠点であることに気づく前に、私は面倒なfactor->numeric変換をたくさん書いていることに気付きました。いくつかの便利な関数が利用可能である必要がありますas.numeric.factor
Jealie 2014

4
自分がそれをたくさんしていることに気づいたら、それを完全に回避するために上流で何かをすべきです。
Joshua Ulrich 14

2
as.numeric.factorはNAを返しますか?
jO。

@jO .: v=NA;as.numeric.factor(v)またはのようなものを使用した場合v='something';as.numeric.factor(v)は、そうする必要があります。そうでない場合は、どこかで奇妙なことが起こっています。
ジーリー2014

33

最も簡単な方法は、varhandleunfactorパッケージの関数を使用することです。

unfactor(your_factor_variable)

この例は、すぐに始めることができます。

x <- rep(c("a", "b", "c"), 20)
y <- rep(c(1, 1, 0), 20)

class(x)  # -> "character"
class(y)  # -> "numeric"

x <- factor(x)
y <- factor(y)

class(x)  # -> "factor"
class(y)  # -> "factor"

library(varhandle)
x <- unfactor(x)
y <- unfactor(y)

class(x)  # -> "character"
class(y)  # -> "numeric"

このunfactor関数は、最初に文字データ型に変換し、次に数値に変換します。unfactorコンソールで入力すると、関数の中央に表示されます。したがって、それは実際には質問者がすでに持っていたものよりも良い解決策を提供しません。
CJB 2016年

とは言っても、因子のレベルはとにかく文字タイプなので、このアプローチによって何も失われることはありません。
CJB 2016年

このunfactor関数は、数値に変換できないものを処理します。例を確認してくださいhelp("unfactor")
Mehrad Mahmoudian 2016

2
@Selracこの関数はvarhandleパッケージで使用できることlibrary("varhandle")を述べました。つまり、最初にパッケージ()をロードする必要があります(私の回答の最初の行で述べたように!!)
Mehrad Mahmoudian

1
@Gregorが軽い依存関係を追加しても、通常は害はありません。もちろん、最も効率的な方法を探している場合は、自分でより高速に実行できるコードを記述できます。しかし、コメントでもわかるように、as.numeric()as.character()を間違った順序で配置しているため、これは簡単ではありません;)コードチャンクが行うことは、因子のレベルインデックスを文字行列に変換することです。因子の特定のレベルに一度割り当てられたいくつかの数値を含む文字ベクトルです。そのパッケージ内の関数は、これらの混乱を防ぐためにあります
Mehrad Mahmoudian

23

注:この特定の答えは、数値因子を数値に変換するためのものではなく、カテゴリー因子を対応するレベル番号に変換するためのものです。


この投稿のすべての回答が私にとって結果を生成することに失敗し、NAが生成されていました。

y2<-factor(c("A","B","C","D","A")); 
as.numeric(levels(y2))[y2] 
[1] NA NA NA NA NA Warning message: NAs introduced by coercion

私のために働いたのはこれです-

as.integer(y2)
# [1] 1 2 3 4 1

要因があると確信していますか?この例を見てください。y<-factor(c("5","15","20","2")); unclass(y) %>% as.numericこれは、5,15,20,2ではなく、4,1,3,2を返します。これは誤った情報のようです。
MrFlick 2017

OK、これは私が今日やろうとしていたことと似ています:-y2 <-factor(c( "A"、 "B"、 "C"、 "D"、 "A")); as.numeric(levels(y2))[y2] [1] NA NA NA NA NA警告メッセージ:強制によって導入されたNAに対して、unclass(y2)%>%as.numericは、必要な結果をもたらしました。
インディ2017

4
さて、それは上で尋ねられた質問ではありません。この質問では、因子レベルはすべて「数値」です。あなたの場合、as.numeric(y)はうまくいくはずで、は必要ありませんunclass()。しかし、繰り返しになりますが、それはこの質問の目的ではありません。この答えはここでは適切ではありません。
MrFlick 2017

3
まあ、それが私のように急いでいて、タイトルだけを読んでいる人を助けることを本当に望んでいます!
インディ

1
整数を表す文字を要素として持っている場合、これが私がお勧めする文字です。これは私のために働いた唯一のものです。
aimme

9

因子ラベルが元の値と一致する場合にのみ可能です。例を挙げて説明します。

データがvectorであると仮定しますx

x <- c(20, 10, 30, 20, 10, 40, 10, 40)

次に、4つのラベルを持つ因子を作成します。

f <- factor(x, levels = c(10, 20, 30, 40), labels = c("A", "B", "C", "D"))

1)xタイプがdoubleで、fタイプがintegerです。これは情報の最初の不可避の損失です。係数は常に整数として保存されます。

> typeof(x)
[1] "double"
> typeof(f)
[1] "integer"

2)使用可能な値のみの元の値(10、20、30、40)に戻すことはできませfん。にfは整数値1、2、3、4と2つの属性(ラベルのリスト( "A"、 "B"、 "C"、 "D")とクラス属性 "factor")のみが保持されていることがわかります。これ以上何もない。

> str(f)
 Factor w/ 4 levels "A","B","C","D": 2 1 3 2 1 4 1 4
> attributes(f)
$levels
[1] "A" "B" "C" "D"

$class
[1] "factor"

元の値に戻すには、因子の作成に使用されたレベルの値を知る必要があります。この場合c(10, 20, 30, 40)。(正しい順序で)元のレベルがわかっている場合は、元の値に戻すことができます。

> orig_levels <- c(10, 20, 30, 40)
> x1 <- orig_levels[f]
> all.equal(x, x1)
[1] TRUE

そして、これは、元のデータのすべての可能な値に対してラベルが定義されている場合にのみ機能します。

したがって、元の値が必要な場合は、それらを保持する必要があります。さもなければ、要因からだけではそれらに戻ることができない可能性が高くなります。


2

hablar::convertデータフレームがある場合に使用できます。構文は簡単です:

サンプルdf

library(hablar)
library(dplyr)

df <- dplyr::tibble(a = as.factor(c("7", "3")),
                    b = as.factor(c("1.5", "6.3")))

解決

df %>% 
  convert(num(a, b))

あなたにあげる:

# A tibble: 2 x 2
      a     b
  <dbl> <dbl>
1    7.  1.50
2    3.  6.30

または、1つの列を整数、1つの数値にする場合:

df %>% 
  convert(int(a),
          num(b))

結果は:

# A tibble: 2 x 2
      a     b
  <int> <dbl>
1     7  1.50
2     3  6.30

0

ソリューションas.numeric(levels(f))[f]はR 4.0では動作しなくなったようです。

代替ソリューション:

factor2number <- function(x){
    data.frame(levels(x), 1:length(levels(x)), row.names = 1)[x, 1]
}

factor2number(yourFactor)

-1

私が読むことができる多くの答えから、唯一の与えられた方法は、因子の数に従って変数の数を拡大することでした。レベルが「dog」と「cat」の変数「pet」がある場合、pet_dogとpet_catになります。

私の場合、因子変数を数値に変換するだけで、同じ数の変数を維持したいと思いました。これは、たとえばcat = 1やdog = 0のように、多くのレベルを持つ多くの変数に適用できます。

以下の対応する解決策を見つけてください:

crime <- data.frame(city = c("SF", "SF", "NYC"),
                    year = c(1990, 2000, 1990),
                    crime = 1:3)

indx <- sapply(crime, is.factor)

crime[indx] <- lapply(crime[indx], function(x){ 
  listOri <- unique(x)
  listMod <- seq_along(listOri)
  res <- factor(x, levels=listOri)
  res <- as.numeric(res)
  return(res)
}
)

-2

ゲームに遅れて、誤って、にtrimws()変換できることがわかりましfactor(3:5)c("3","4","5")。その後、を呼び出すことができますas.numeric()。あれは:

as.numeric(trimws(x_factor_var))

3
受け入れられた回答に記載されているように使用trimwsを推奨する理由はありas.characterますか?削除する必要のある空白が実際にない限りtrimws、同じ結果を返すために不要な正規表現の処理を実行するだけのようです。
MrFlick 2018年

as.numeric(levels(f))[f]は少しわかりにくく、初心者には覚えにくいかもしれません。trimwsは害を及ぼしません。
Jerry T
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.