データフレーム内の多くの列のクラスを因数分解から数値に変更します


82

多数の列を因数分解から数値に変更する最も速い/最良の方法は何ですか?

次のコードを使用しましたが、データが並べ替えられたようです。

> head(stats[,1:2])
  rk                 team
1  1 Washington Capitals*
2  2     San Jose Sharks*
3  3  Chicago Blackhawks*
4  4     Phoenix Coyotes*
5  5   New Jersey Devils*
6  6   Vancouver Canucks*

for(i in c(1,3:ncol(stats))) {
    stats[,i] <- as.numeric(stats[,i])
}

> head(stats[,1:2])
  rk                 team
1  2 Washington Capitals*
2 13     San Jose Sharks*
3 24  Chicago Blackhawks*
4 26     Phoenix Coyotes*
5 27   New Jersey Devils*
6 28   Vancouver Canucks*

すべての列に次のように名前を付ける以外の最善の方法は何ですか。

df$colname <- as.numeric(ds$colname)

4
一般的な解決策はありませんか?ここで提案されているソリューションの一部は因子でのみ機能し、他のソリューションは常に因子を除いて機能します...
skan 2016年

回答:


56

ラムナスの答えに加えて、あなたが経験している振る舞いは、Rレベルas.numeric(x)での因子の内部の数値表現を返すためxです。(内部表現ではなく)因子のレベルである数値を保持したい場合は、as.character()ラムナスの例のように、最初に文字に変換する必要があります。

あなたのforループはapply呼び出しと同じくらい合理的であり、コードの意図が何であるかに関して少し読みやすいかもしれません。この行を変更するだけです:

stats[,i] <- as.numeric(stats[,i])

読む

stats[,i] <- as.numeric(as.character(stats[,i]))

これは、RFAQのFAQ7.10です。

HTH


2
どんな種類のループも必要ありません。インデックスとunlist()を使用するだけです。編集:私はこれを説明する答えを追加しました。
Joris Meys 2010

このアプローチは、この特定の場合にのみ機能します。これを使用して列をに変換しようとしましたがfactor、機能しませんでした。sapplyまたはmutate_if、より一般的に適用可能なソリューションのようです。
レオ

@Leo Careを拡張します、これが機能するという事実を私は知っています。これ、以下のRamnathapplyがループを実行するために使用し、OPがfor明示的にループを使用していたことを除いて、まったく同じソリューションです。実際、非常に賛成票を投じた回答はすべてas.numeric(as.character())イディオムを使用しています。
Gavin Simpson

はい、複数の列のクラスをに変更することはできますがnumeric、逆に機能することはありません(複数の列のクラスをに変更することfactor)。必要なインデックスを使用unlist()し、文字を含む列に適用すると、すべての文字のリストが解除されるため、出力をに戻すときに機能しなくなりstats[,i]ます。ここで答えを確認してください:stackoverflow.com/questions/45713473/…–
レオ

@Leoもちろん逆には機能しません!いったい何があなたにそれがそうなるという印象を与えましたか?それは決して設計されておらず、OPはそれを要求しませんでした。尋ねられていない質問に答えるのは難しい。ここの代わりにファクターを使用するように変換たい場合は、問題なく動作します。もちろん、列が混在している場合は、選択的に選択する必要がありますが、それも簡単です。as.factor()as.numeric(as.character())i
Gavin Simpson

73

係数を数値に変更するときは注意する必要があります。これは、列のセットを因数分解から数値に変更するコード行です。ここでは、数値に変更する列がそれぞれ1、3、4、5であると想定しています。それに応じて変更できます

cols = c(1, 3, 4, 5);    
df[,cols] = apply(df[,cols], 2, function(x) as.numeric(as.character(x)));

3
これは正しく機能しません。例:x<-as.factor(1:3); df<-data.frame(a=x,y=runif(3),b=x,c=x,d=x)。私はそれapplyがこの種の問題に適切であるとは思いません。
マレク2010

1
適用はこれらの状況で完全に機能します。私のコードのエラーは、関数を列ごとに適用する必要があるため、2ではなくmargin = 1を使用していました。私はそれに応じて私の答えを編集しました。
ラムナス2010

今では動作します。しかし、私はそれがなくてもできると思いますapply。私の編集を確認してください。
マレク2010

2
...またはJorisはunlist。で答えます。またas.character、ソリューションでのapply変換は必要ありません。変換df[,cols]するcharacterため、変換apply(df[,cols], 2, function(x) as.numeric(x))も機能します。
マレク2010

@ Ramnath、なぜ使用するの=ですか?なぜ使用しないの<-ですか?
kittygirl

40

これは1行で実行でき、forループでもapplyでも、ループは必要ありません。代わりにunlist()を使用してください:

# testdata
Df <- data.frame(
  x = as.factor(sample(1:5,30,r=TRUE)),
  y = as.factor(sample(1:5,30,r=TRUE)),
  z = as.factor(sample(1:5,30,r=TRUE)),
  w = as.factor(sample(1:5,30,r=TRUE))
)
##

Df[,c("y","w")] <- as.numeric(as.character(unlist(Df[,c("y","w")])))

str(Df)

編集:あなたのコードの場合、これは:になります

id <- c(1,3:ncol(stats))) 
stats[,id] <- as.numeric(as.character(unlist(stats[,id])))

明らかに、1列のデータフレームがあり、Rの自動次元削減でそれをベクトルに変換したくない場合は、drop=FALSE引数を追加する必要があります。


1
小さな改善は、両方の設定recursiveuse.namesパラメータである可能性があります。unlistFALSE
マレク2010

@マレク:本当。私はこのゲームが大好きです:
Joris Meys 2010

将来的に答えを探している人のために追加します。これは、データフレームが1列しかない場合、op + gavinの方法と同等ではありません。その場合、それはベクトルに変換されますが、opは引き続きデータフレームです。
themartinmcfly 2013

1
tidyverseで作業している人のために:興味深いことに、オブジェクトがtibbleでもある場合、これは機能しないようです:コードは次の後に失敗しますDf <- tibble::as_tibble(Df)
tjebo 2010年

1
@Tjeboでは、tibbleが更新され、tibblesとデータフレームが流用されています。この古いアプローチは、tidyverseでは実際には最良のオプションではありません。tidyselect関数をmutate_if。と組み合わせて使用​​することをお勧めします。または、次の反復で利用できる新しいアプローチは何でもdplyr...
JorisMeys20年

30

私はこの質問が長い間解決されていることを知っていますが、最近同様の問題が発生し、magrittrパッケージが必要ですが、もう少しエレガントで機能的な解決策を見つけたと思います。

library(magrittr)
cols = c(1, 3, 4, 5)
df[,cols] %<>% lapply(function(x) as.numeric(as.character(x)))

%<>%オペレータパイプデータクリーニングおよび変換を簡単に維持するために非常に有用である再割当て。適用したい関数を指定するだけで、リスト適用関数がはるかに読みやすくなりました。


2
きちんとしたソリューション。df[,cols] %<>% lapply(function(x) as.numeric(as.character(x)))

1
私はあなたがそれをラップで包む必要さえないと思いますdf[,cols] %<>% as.numeric(as.character(.))同じように機能します
Nate

このコマンドを実行すると、次のエラーが発生しますError in [.data.table(Results, , cols) : j (the 2nd argument inside [...]) is a single symbol but column name 'cols' is not found. Perhaps you intended DT[,..cols] or DT[,cols,with=FALSE]. This difference to data.frame is deliberate and explained in FAQ 1.1.
Urvah Shabbir 2017

コードは次のようなものですcols <- c("a","b"); df[,cols] %<>% lapply(function(x) as.numeric(as.character(x)))
。– Urvah Shabbir 2017

ブラケットが追加されました。
ジョー

9

ここにいくつかのdplyrオプションがあります:

# by column type:
df %>% 
  mutate_if(is.factor, ~as.numeric(as.character(.)))

# by specific columns:
df %>% 
  mutate_at(vars(x, y, z), ~as.numeric(as.character(.))) 

# all columns:
df %>% 
  mutate_all(~as.numeric(as.character(.))) 

6

ucfaglsが理由を見つけたと思います、ループが機能しないます。

それでもループを使用したくない場合は、次の解決策がありlapplyます。

factorToNumeric <- function(f) as.numeric(levels(f))[as.integer(f)] 
cols <- c(1, 3:ncol(stats))
stats[cols] <- lapply(stats[cols], factorToNumeric)

編集します。もっと簡単な解決策を見つけました。それはそのようでas.matrix文字に変換。そう

stats[cols] <- as.numeric(as.matrix(stats[cols]))

あなたがやりたいことをする必要があります。


5

lapplyはほとんどこのために設計されています

unfactorize<-c("colA","colB")
df[,unfactorize]<-lapply(unfactorize, function(x) as.numeric(as.character(df[,x])))

こんにちは@transcom、そしてstackoverflowへようこそ。この質問は、因子から数値表現への変換に関するものであり、その逆ではないことに注意してください。マレックの解決策を参照してください。
アーロンは2014

@アーロン、理解した。OPのタイトルがあいまいなため、この回答を投稿しました。クラスに関係なく、他の人が複数の列を簡単に変換する方法を探してここに着陸する可能性があることを前提に運用しています。とにかく、私は質問にもっと適切に対処するために私の答えを編集しました:)
transcom 2014

2

私はこの関数を他のいくつかの重複スレッドで見つけ、この問題を解決するためのエレガントで一般的な方法を見つけました。このスレッドは、このトピックに関するほとんどの検索で最初に表示されるので、時間を節約するためにここで共有しています。私はこれを信用していませんので、詳細についてはここここの元の投稿を参照してください。

df <- data.frame(x = 1:10,
                 y = rep(1:2, 5),
                 k = rnorm(10, 5,2),
                 z = rep(c(2010, 2012, 2011, 2010, 1999), 2),
                 j = c(rep(c("a", "b", "c"), 3), "d"))

convert.magic <- function(obj, type){
  FUN1 <- switch(type,
                 character = as.character,
                 numeric = as.numeric,
                 factor = as.factor)
  out <- lapply(obj, FUN1)
  as.data.frame(out)
}

str(df)
str(convert.magic(df, "character"))
str(convert.magic(df, "factor"))
df[, c("x", "y")] <- convert.magic(df[, c("x", "y")], "factor")

1

いずれかの列にNAがある場合、添え字を使用するだけでは機能しないことを指摘しておきます。因子にNAがある場合は、Ramnathが提供する適用スクリプトを使用する必要があります。

例えば

Df <- data.frame(
  x = c(NA,as.factor(sample(1:5,30,r=T))),
  y = c(NA,as.factor(sample(1:5,30,r=T))),
  z = c(NA,as.factor(sample(1:5,30,r=T))),
  w = c(NA,as.factor(sample(1:5,30,r=T)))
)

Df[,c(1:4)] <- as.numeric(as.character(Df[,c(1:4)]))

以下を返します。

Warning message:
NAs introduced by coercion 

    > head(Df)
       x  y  z  w
    1 NA NA NA NA
    2 NA NA NA NA
    3 NA NA NA NA
    4 NA NA NA NA
    5 NA NA NA NA
    6 NA NA NA NA

だが:

Df[,c(1:4)]= apply(Df[,c(1:4)], 2, function(x) as.numeric(as.character(x)))

戻り値:

> head(Df)
   x  y  z  w
1 NA NA NA NA
2  2  3  4  1
3  1  5  3  4
4  2  3  4  1
5  5  3  5  5
6  4  2  4  4

1

unfactor()CRANから「varhandle」パッケージの関数を使用できます。

library("varhandle")

my_iris <- data.frame(Sepal.Length = factor(iris$Sepal.Length),
                      sample_id = factor(1:nrow(iris)))

my_iris <- unfactor(my_iris)

1

私はこのコードがとても便利なので好きです:

  data[] <- lapply(data, function(x) type.convert(as.character(x), as.is = TRUE)) #change all vars to their best fitting data type

それは正確に求められたもの(数値に変換)ではありませんが、多くの場合、さらに適切です。


1

df$colname <- as.numeric(df$colname)

1つの列タイプを変更するためにこの方法を試しましたが、すべての列タイプを変更しない場合は、他の多くのバージョンよりも優れていると思います。

df$colname <- as.character(df$colname)

逆もまた同様です。


0

apply()呼び出しですべての列を数値に変換する際に問題が発生しました:

apply(data, 2, as.numeric)

問題は、一部の文字列にコンマが含まれているためであることが判明しました(たとえば、「1024.63」ではなく「1,024.63」)。Rはこの方法で数値をフォーマットするのが好きではありません。だから私はそれらを削除してから実行しましたas.numeric()

data = as.data.frame(apply(data, 2, function(x) {
  y = str_replace_all(x, ",", "") #remove commas
  return(as.numeric(y)) #then convert
}))

これには、ストリンガーパッケージをロードする必要があることに注意してください。


0

それが私のために働いたものです。このapply()関数は、dfを行列に強制変換しようとし、NAを返します。

numeric.df <- as.data.frame(sapply(df, 2, as.numeric))


0

@SDahmの回答に基づくと、これは私の「最適な」解決策でしたtibble

data %<>% lapply(type.convert) %>% as.data.table()

これが必要ですdplyrmagrittr


0

私は同様の問題でこれらの束を試し、NAを取得し続けました。Base Rには、非常に苛立たしい強制動作がいくつかあります。これらは通常、Tidyverseパッケージで修正されています。依存関係を作りたくなかったので、以前はそれらを避けていましたが、それらは人生をとても楽にしてくれます、今ではほとんどの場合BaseRソリューションを理解しようとさえしません。

これがTidyverseソリューションです。これは非常にシンプルでエレガントです。

library(purrr)

mydf <- data.frame(
  x1 = factor(c(3, 5, 4, 2, 1)),
  x2 = factor(c("A", "C", "B", "D", "E")),
  x3 = c(10, 8, 6, 4, 2))

map_df(mydf, as.numeric)

ほとんどの回答(少なくともすべての上位の回答)は、値から数値への整数レベルのあまりにも一般的な変換as.numeric(as.character())を回避するために、必ず変換を実行してください。あなたがそのオプションを示したら、私は喜んでこの答えに賛成します。
グレゴールトーマス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.