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に変換する方法を教えてください。
おまけの質問:なぜ手動によるアプローチはうまくいくのですか
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に変換し直す必要がなくなります。
要因のみを置き換えるには
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
(覚えておいてくださいそれは新鮮なパッケージです)
グローバルオプション
stringsAsFactors:data.frameおよびread.tableの引数のデフォルト設定。
スタートアップファイルでFALSE
に設定したいものがあるかもしれません(例:〜/ .Rprofile)。 help(options)
をご覧ください。
因子がどのように格納されるかを理解していれば、これを達成するために適用ベースの関数を使用することを避けることができます。適用ソリューションがうまく機能しないことを意味するものではありません。
要因は、「レベル」のリストに関連付けられた数値インデックスとして構成されています。これは、因子を数値に変換するとわかります。そう:
> 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
bobc
の every factorベクトルが文字ベクトルに変換される新しいデータフレームbobf
が欲しいなら、これを試してください:
bobc <- rapply(bobf, as.character, classes="factor", how="replace")
それを元に戻す場合は、どの列が因子であるかの論理ベクトルを作成し、それを使用して因子を選択的に適用できます。
f <- sapply(bobf, class) == "factor"
bobc[,f] <- lapply(bobc[,f], factor)
私は通常、この機能を私のすべてのプロジェクトとは別にしています。早くて簡単。
unfactorize <- function(df){
for(i in which(sapply(df, class) == "factor")) df[[i]] = as.character(df[[i]])
return(df)
}
別の方法はapplyを使って変換することです
bob2 <- apply(bob,2,as.character)
そしてより良いもの(前のクラスは 'matrix'です)
bob2 <- as.data.frame(as.matrix(bob),stringsAsFactors=F)
あるいは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" ...
だからそこに... =)
更新:これはうまくいかないことの例です。私はそう思うと思いましたが、stringsAsFactorsオプションは文字列に対してのみ機能すると私は思います - それは要因だけを残します。
これを試して:
bob2 <- data.frame(bob, stringsAsFactors = FALSE)
一般的に言って、文字であるべき要素に問題があるときはいつでもあなたを助けるためにどこかにstringsAsFactors
設定があります(グローバル設定を含む)。
あなたのデータフレームの始めにすべての誤解を無視するためにstringsAsFactors = FALSE
を含めてください。
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"
この機能はうまくいく
df <- stacomirtools::killfactor(df)
これは私のために働きます - 私はついにワンライナーを考え出しました
df <- as.data.frame(lapply(df,function (y) if(class(y)=="factor" ) as.character(y) else y),stringsAsFactors=F)
convert
には互換性のある読みやすい構文を与えるhablar
でtidyverse
を使用する必要があります。
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
おそらく新しいオプションですか?
library("tidyverse")
bob <- bob %>% group_by_if(is.factor, as.character)
これはすべてを文字に変換し、次に数値を数値に変換するのに役立ちます:
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シートの列タイプを自動的に取得