web-dev-qa-db-ja.com

Data.frame列を因子から文字に変換

データフレームがあります。彼をbobと呼びましょう。

> head(bob)
                 phenotype                         exclusion
GSM399350 3- 4- 8- 25- 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399351 3- 4- 8- 25- 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399352 3- 4- 8- 25- 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399353 3- 4- 8- 25+ 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399354 3- 4- 8- 25+ 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399355 3- 4- 8- 25+ 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-

このデータフレームの行を連結したいのですが(これは別の質問になるでしょう)。でも、見てください:

> class(bob$phenotype)
[1] "factor"

Bobのカラムは要素です。だから、例えば:

> as.character(head(bob))
[1] "c(3, 3, 3, 6, 6, 6)"       "c(3, 3, 3, 3, 3, 3)"      
[3] "c(29, 29, 29, 30, 30, 30)"

私はこれを理解し始めていません、しかし、私はこれらがbobの(王カラクタカスの法廷の)コラムの要素のレベルへの指標であると思いますか?必要なものではありません。

不思議なことに私はbobの列を手で調べて、

bob$phenotype <- as.character(bob$phenotype)

これはうまくいきます。そして、入力した後、列が要素ではなく文字であるdata.frameを取得できます。だから私の質問は:どうすればこれを自動的に行うことができますか?手動で各列を通過しなくても、因子列を含むdata.frameを文字列を含むdata.frameに変換する方法を教えてください。

おまけの質問:なぜ手動によるアプローチはうまくいくのですか

307
Mike Dewar

Matt and Dirkをフォローするだけです。グローバルオプションを変更せずに既存のデータフレームを再作成したい場合は、applyステートメントを使用して再作成できます。

bob <- data.frame(lapply(bob, as.character), stringsAsFactors=FALSE)

これはすべての変数をクラス "character"に変換します。もし因子だけを変換したいのであれば、下記の Marekの解決策を見てください

@hadleyが指摘するように、以下はより簡潔です。

bob[] <- lapply(bob, as.character)

どちらの場合も、lapplyはリストを出力します。しかし、Rの魔法の性質により、2番目のケースで[]を使用すると、bobオブジェクトのdata.frameクラスが保持されるため、as.data.frameを引数stringsAsFactors = FALSEと共に使用してdata.frameに変換し直す必要がなくなります。

331
Shane

要因のみを置き換えるには

i <- sapply(bob, is.factor)
bob[i] <- lapply(bob[i], as.character)

パッケージdplyr のバージョン0.5.0では、新しい関数mutate_ifが導入されました

library(dplyr)
bob %>% mutate_if(is.factor, as.character) -> bob

RStudioのpurrrパッケージ には、別の選択肢があります。

library(purrr)
library(dplyr)
bob %>% map_if(is.factor, as.character) %>% as_data_frame -> bob

(覚えておいてくださいそれは新鮮なパッケージです)

269
Marek

グローバルオプション

stringsAsFactors:data.frameおよびread.tableの引数のデフォルト設定。

スタートアップファイルでFALSEに設定したいものがあるかもしれません(例:〜/ .Rprofile)。 help(options)をご覧ください。

37

因子がどのように格納されるかを理解していれば、これを達成するために適用ベースの関数を使用することを避けることができます。適用ソリューションがうまく機能しないことを意味するものではありません。

要因は、「レベル」のリストに関連付けられた数値インデックスとして構成されています。これは、因子を数値に変換するとわかります。そう:

> fact <- as.factor(c("a","b","a","d")
> fact
[1] a b a d
Levels: a b d

> as.numeric(fact)
[1] 1 2 1 3

最後の行に返される数字は、因子のレベルに対応しています。

> levels(fact)
[1] "a" "b" "d"

levels()が文字の配列を返すことに注意してください。この事実を使用して、因子を文字列または数値に簡単かつコンパクトに変換できます。

> fact_character <- levels(fact)[as.numeric(fact)]
> fact_character
[1] "a" "b" "a" "d"

式をas.numeric()でラップする場合、これは数値に対しても機能します。

> num_fact <- factor(c(1,2,3,6,5,4))
> num_fact
[1] 1 2 3 6 5 4
Levels: 1 2 3 4 5 6
> num_num <- as.numeric(levels(num_fact)[as.numeric(num_fact)])
> num_num
[1] 1 2 3 6 5 4
21
Kikapp

bobc every factorベクトルが文字ベクトルに変換される新しいデータフレームbobfが欲しいなら、これを試してください:

bobc <- rapply(bobf, as.character, classes="factor", how="replace")

それを元に戻す場合は、どの列が因子であるかの論理ベクトルを作成し、それを使用して因子を選択的に適用できます。

f <- sapply(bobf, class) == "factor"
bobc[,f] <- lapply(bobc[,f], factor)
17
scentoni

私は通常、この機能を私のすべてのプロジェクトとは別にしています。早くて簡単。

unfactorize <- function(df){
  for(i in which(sapply(df, class) == "factor")) df[[i]] = as.character(df[[i]])
  return(df)
}
12
by0

別の方法はapplyを使って変換することです

bob2 <- apply(bob,2,as.character)

そしてより良いもの(前のクラスは 'matrix'です)

bob2 <- as.data.frame(as.matrix(bob),stringsAsFactors=F)
7
George Dontas

あるいはtransformを試すこともできます。

newbob <- transform(bob, phenotype = as.character(phenotype))

文字に変換したいすべての要素を必ず入れてください。

あるいは、このようなことをして一撃ですべての害虫を殺すこともできます。

newbob_char <- as.data.frame(lapply(bob[sapply(bob, is.factor)], as.character), stringsAsFactors = FALSE)
newbob_rest <- bob[!(sapply(bob, is.factor))]
newbob <- cbind(newbob_char, newbob_rest)

このようにコードでデータを突き出すのは not 良い考えです。sapplyの部分は別にすることができます(実際、そうする方がはるかに簡単です)が、要点はわかります。コードをチェックしていません、 '私は家にいないので、うまくいくことを願っています! =)

ただし、このアプローチには欠点があります。後で列を再編成する必要があります。transformを使用すると、好きなことをすべて実行できますが、 "pedestrian-style-code-writing" ...

だからそこに... =)

6
aL3xa

更新:これはうまくいかないことの例です。私はそう思うと思いましたが、stringsAsFactorsオプションは文字列に対してのみ機能すると私は思います - それは要因だけを残します。

これを試して:

bob2 <- data.frame(bob, stringsAsFactors = FALSE)

一般的に言って、文字であるべき要素に問題があるときはいつでもあなたを助けるためにどこかにstringsAsFactors設定があります(グローバル設定を含む)。

6
Matt Parker

あなたのデータフレームの始めにすべての誤解を無視するためにstringsAsFactors = FALSEを含めてください。

5
user5462317

Data.frameの操作にdata.tableパッケージを使用するのであれば、問題はありません。

library(data.table)
dt = data.table(col1 = c("a","b","c"), col2 = 1:3)
sapply(dt, class)
#       col1        col2 
#"character"   "integer" 

データセットにすでに因子列があり、それらを文字に変換したい場合は、次のようにします。

library(data.table)
dt = data.table(col1 = factor(c("a","b","c")), col2 = 1:3)
sapply(dt, class)
#     col1      col2 
# "factor" "integer" 
upd.cols = sapply(dt, is.factor)
dt[, names(dt)[upd.cols] := lapply(.SD, as.character), .SDcols = upd.cols]
sapply(dt, class)
#       col1        col2 
#"character"   "integer" 
3
jangorecki

この機能はうまくいく

df <- stacomirtools::killfactor(df)
2
Cedric

これは私のために働きます - 私はついにワンライナーを考え出しました

df <- as.data.frame(lapply(df,function (y) if(class(y)=="factor" ) as.character(y) else y),stringsAsFactors=F)
2
user1617979

convertには互換性のある読みやすい構文を与えるhablartidyverseを使用する必要があります。

library(dplyr)
library(hablar)

df <- tibble(a = factor(c(1, 2, 3, 4)),
             b = factor(c(5, 6, 7, 8)))

df %>% convert(chr(a:b))

これはあなたに与えます:

  a     b    
  <chr> <chr>
1 1     5    
2 2     6    
3 3     7    
4 4     8   
1
davsjob

おそらく新しいオプションですか?

library("tidyverse")

bob <- bob %>% group_by_if(is.factor, as.character)
0
rachelette

これはすべてを文字に変換し、次に数値を数値に変換するのに役立ちます:

makenumcols<-function(df){
  df<-as.data.frame(df)
  df[] <- lapply(df, as.character)
  cond <- apply(df, 2, function(x) {
    x <- x[!is.na(x)]
    all(suppressWarnings(!is.na(as.numeric(x))))
  })
  numeric_cols <- names(df)[cond]
  df[,numeric_cols] <- sapply(df[,numeric_cols], as.numeric)
  return(df)
}

適応元: Excelシートの列タイプを自動的に取得

0
Ferroao