こんにちは、usagi-sanです。
今回はデータ解析に役立つ関数を作ってみました。
自分がアルバイトをする中で、データ整形(データクレンジング)に用いる時間が勤務時間の9割に及び、肝心な統計解析にミスがあったり、そもそも疲れて解析のチェックを行えなかったりしたので作りました。
R言語 データ整形練習やnumeric型やfactor型でも解説しましたが、統計解析を行う前提として、欠損値の処理やnumeric型のデータをカテゴリカルデータにしたり、factor型のlevelsの変更を行ったりなど、統計解析以上にやることがいっぱいあります。
今回紹介する関数は、上で述べたデータ整形をすべて自動で行い、統計解析に用いやすいデータセットに変換してくれるものとなっています。
また、この関数は次の記事のパッケージや、この記事の下でダウンロード可能なので、ぜひぜひダウンロードしてください。
R言語 自作パッケージ UsagiSan
こんにちは、usagi-sanです。 R言語の自作パッケージを紹介します。 統計解析のアルバイトをしている中、暇な時間を見つけて自分でパッケージを作ってみました。 Rのパッケージには、統計解析用のパッ ...
続きを見る
アップデート
2020/9/19に不具合を修正しました。定義されていない変数を除去しました。
2020/12/04 日付型の変数の判別アルゴリズムを変更しました。日付の区切り文字の引数を指定する必要がなくなりました。
2020/12/04 factor型のlevelをNAに置き換える際の形式を"NA"からN/Aに変更しました。
関数dataCleanserの説明
関数dataCleanserの概要を説明します。
関数dataCleanserには以下の4つ機能があります。
- character型の列ベクトルが、numeric型かfactor型かDate型かであるかを判別する
- その判別に基づき、列ベクトルを対応する型(numeric型かfactor型かDate型のいずれか)に変更する。
- オプションとしてnumeric型のデータをカテゴリカルデータに変更可能。numericと判定されなかったデータを数値に置き換えることが可能
- factor型のデータのlevelsの変更、levelsのプール、levelsの順序変更が可能。
分かりやすく、実行結果を用いて説明すると、1の「numeric型かfactor型かDate型かであるかを判別する」とは、次のようなデータセットの各列はどの型であるべきかを判定してくれます。
1 2 3 4 5 6 7 8 | > head(read.csv("iris改.csv")) Sepal.Length Sepal.Width Petal.Length Petal.Width Species Sep.Len.mean.or..mean time 1 5.1 3.5 1.4 0.2 setosa Sepal<mean 1913年3月4日 2 4.9 3.0 1.4 0.2 setosa Sepal<mean 1909年1月3日 3 4.7 3.2 1.3 0.2 setosa Sepal<mean 1939年4月10日 4 4.6 3.1 1.5 0.2 setosa Sepal<mean 1903年12月6日 5 5.0 3.6 1.4 0.2 setosa Sepal<mean 1912年7月13日 6 5.4 3.9 1.7 0.4 setosa Sepal<mean 1930年2月6日 |
ポイント1
1~4列目の"Sepal.Length"、"Sepal.Width"、"Petal.Length"、"Petal.Width"には"欠損値"、"測定なし"という2種類のNAにあたる欠損値が入っているためcharacter型となっています。今回紹介する関数は1~4列目をnumeric型であると判定します。
ポイント2
5、6列目はfactor型である必要がありますが、read.tableなどでファイルを読み込む際に、stringsAsFactors=FALSEとしていると、factor型のデータはcharacter型として扱われます。この列をfactor型であると判定してくれます。
ポイント3
最後に7列目の日付データに関しても、R上ではcharacter型として扱われます。また日付データといっても"%Y/%m/%d"や""%Y年%m月%d日"といった色々な書式があります。これらの書式に関係なく、Date型であると判定してくれます。
ポイント4
次に2に関して、1で3種類に分けたデータをもとに、データセットを統計解析で扱いやすい形にデータ整形してくれます。すなわちcharacter型のデータをnumeric型、factor型、Date型の3種類のデータに変更してくれます。
ポイント5
3のオプションについて、numeric型のデータをカテゴリカルデータに変更することができます。cut関数と同じ機能を持ちます。また、c("2", 3", "<5")のデータについて、numeric型として判定されないデータ"<5"を5に置き換える機能もあります。
ポイント1
最後に4について、factor型のデータのlevelsの変更、levelsのプール、levelsの順序の変更といったR言語データ整形numeric型やfactorで解説したfactor型の操作に関する機能をすべて搭載しています。
関数dataCleanser
データ整形用の関数dataCleanserは以下となります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | dataCleanser <- function(dataName, dateFormat = list("/", "-"), append = FALSE, numOrFac = 10, leastNumOfDate = 10, fileEncoding = "CP932") { files <- list.files() if (any(files == paste0("dataCleansingForm_", dataName, "_.xlsx")) == FALSE) { data <- as.data.frame(readData(dataName, fileEncoding)) tableTime <- c("ColName", "Change the colName") tableNumeric <- c("ColName", "Change the colName", rep("", 6)) tableFactor <- c("ColName", "Change the colName", rep("", 7)) for (i in colnames(data)) { if (!is.null(mkTimeTable(data, dateFormat, i, tableTime, leastNumOfDate))) { tableTime <- mkTimeTable(data, dateFormat, i, tableTime, leastNumOfDate) next () } tableNum_Fac <- mkTableNum_Fac(data, i, numOrFac, tableNumeric, tableFactor) tableNumeric <- tableNum_Fac$num tableFactor <- tableNum_Fac$fac } writeTablesOnExcel(tableNumeric, tableFactor, tableTime, dataName) } else { data <- as.data.frame(readData(dataName, fileEncoding)) dataList <- NULL sheetList <- c("numeric", "factor", "Date") for (i in seq_len(length(sheetList))) { dataList[[i]] <- openxlsx::read.xlsx(paste0("dataCleansingForm_", dataName, "_.xlsx"), sheet = sheetList[i], colNames = F, skipEmptyRows = FALSE, skipEmptyCols = FALSE, na.strings = c("NA", "")) } for (i in colnames(data)) { if (!is.na(any(dataList[[1]][, 1] == i))) { data <- cleansNumeric(data, i, dataList[[1]], append) } if (!is.na(any(dataList[[2]][, 1] == i))) { data <- cleansFactor(data, i, dataList[[2]], append) } if (!is.na(any(dataList[[3]][, 1] == i))) { data <- cleansDate(data, i, dataList[[3]], dateFormat) } } return(data) } } |
"データセット.csv"というcsvファイルをデータ整形したい場合、下の表の引数dataNameをdataName = "データセット"のようにcharacter型を代入することで、データ整形を行うことができます。
append = TRUEとすると、オプション機能のlevelsのプールを適用した列は、プール前とプール後が残るように元のデータセットにアペンドする機能を付与します。
また、NumOrFacやleastNumOfDateはnumeric型、factor型、Date型を判定する際に用います。例えばNumOfFacについてlevelsのがデータセットの行数のどのくらいの割合を占めているかでnumeric型かfactor型であるかを判定しています。
作業ディレクトリ中に"dataCleanserForm_データセット_.xlsx"というエクセルファイルが存在しない場合、データ整形の入力フォーム用のエクセルファイルが作成されます。このエクセルファイルを書き換えることで、上で紹介したオプション機能を扱うことができます。
エクセルファイルがデフォルトの状態で実行すると、オプションなしの通常のデータ整形が行われます。これらのオプションやエクセルファイルの記述法については、次の関数dataCleanserの使用例を参照してください。
ココに注意
dataCleanserは、他にも10個の関数を用いており、上のコードをコピペしても使用することができないため、必ずダウンロードしてください。zipファイルを開くとわかりますが、dataCleansing.Rの中には上の関数の他にも、Date型を判定する関数や、factor型の操作に関する関数が一通り入っています。
dataCleanser(dataName, dateFormat = list("/","-", c("年","月","日")), append = FALSE, NumOrFac = 10, leastNumOfDate = 10, fileEncoding = "CP932")の引数の説明を以下にまとめました。
dataName | データ整形するcsvファイルの名前。 |
append | levelsをプールした列などをappendするかどうか。 |
NumOrFac | numeric 型かfactor型か判断する際のfactor型のlevelsの数。初期値は10であり、行数の1/10以上のlevelsがあれば、numeric型であると判断される。 |
leastNumOfDate | Date型と判断する際の行数と日付を表す文字列の比。初期値は10であり、行数の1/10以上の日付を表す文字列があれば、Date型と判断される。 |
fileEncoding | ファイルエンコーディング。初期値は"CP932" |
関数の使用例
データセットirisにfactor型の列"Sepal.Length<mean or ≧mean"とDate型の列"time"を加えた次のデータセットを例に解説していきます。
データ整形の流れ
上の関数の概要で紹介したように、今回用いるデータセットは次となります。
1 2 3 4 5 6 7 8 | > head(read.csv("iris改.csv")) Sepal.Length Sepal.Width Petal.Length Petal.Width Species Sep.Len.mean.or..mean time 1 5.1 3.5 1.4 0.2 setosa Sepal<mean 1913年3月4日 2 4.9 3.0 1.4 0.2 setosa Sepal<mean 1909年1月3日 3 4.7 3.2 1.3 0.2 setosa Sepal<mean 1939年4月10日 4 4.6 3.1 1.5 0.2 setosa Sepal<mean 1903年12月6日 5 5.0 3.6 1.4 0.2 setosa Sepal<mean 1912年7月13日 6 5.4 3.9 1.7 0.4 setosa Sepal<mean 1930年2月6日 |
このデータに対して、データ整形用の関数dataCleanserを用います。
以下のように、引数にデータセットが保存されているファイル名(csvファイル名)を代入します。
1 | > dataCleanser("iris改") |
実行すると、作業ディレクトリに"dataCleansingForm_iris改_.xlsx"というファイルが作成されています。
"dataCleansingForm_iris改_.xlsx"には以下の画像のように、iris改.csvのデータがnumeric型、factor型、Date型3種類のエクセルシートに分けられていることが分かります。
"iris改.csv"の各列が正しく整頓されていることを確認したら、改めてdataCleanserを実行します。
"dataCleansingForm_iris改_.xlsx"が作業ディレクトリにある状態でもう一度実行すると、dataCleanserはそのクレンジングフォームをもとにデータ整形を行ってくれます。
1 2 3 4 5 6 7 8 9 10 11 12 | > dataCleanser("iris改")[1:10,] Sepal.Length Sepal.Width Petal.Length Petal.Width Species Sep.Len<mean or ≧mean time 1 5.1 3.5 1.4 0.2 setosa Sepal<mean 1913-03-04 2 4.9 3.0 1.4 0.2 setosa Sepal<mean 1909-01-03 3 4.7 3.2 1.3 0.2 setosa Sepal<mean 1939-04-10 4 4.6 3.1 1.5 0.2 setosa Sepal<mean 1903-12-06 5 5.0 3.6 1.4 0.2 setosa Sepal<mean 1912-07-13 6 5.4 3.9 1.7 0.4 setosa Sepal<mean 1930-02-06 7 4.6 3.4 NA 0.3 setosa Sepal<mean 1961-10-02 8 5.0 3.4 1.5 0.2 setosa Sepal<mean 1985-12-13 9 4.4 2.9 1.4 0.2 setosa Sepal<mean 1969-05-10 10 4.9 3.1 1.5 0.1 setosa Sepal<mean 1955-09-19 |
上の結果のように、numeric型のデータに関して、"欠損値"、"測定なし"はNAに置き換わります。
また、Date型の列"time"に関して、"1913年3月4日"のようなデータは扱いやすい"1913-03-04"という形に変換されています。
オプション機能
オプション機能である。データの列名の変更、numeric型のカテゴリカルデータ化や欠損値の置き換え、factor型のlevelsの変更やプールやlevelsの順序の変更の方法をみていきます。
列名の変更
データの列名の変更は、次の画像のようにnumeric型、factor型の場合は、ColNameの横にある"Change the colName"に変更後の列名を書きます。
"Sepal.Length"という列名を"セパルの長さ"に変更します。
書き終えたら、エクセルファイルを保存し閉じたら、dataCleanserを実行すると、列名が変わっていることが確認できます。
1 2 3 4 5 6 7 8 | > colnames(dataCleanser("iris改")) [1] "セパルの長さ" [2] "Sepal.Width" [3] "Petal.Length" [4] "Petal.Width" [5] "Species" [6] "Sep.Len<mean or ≧mean" [7] "time" |
また、Date型のデータも同様に、"ColName"と"Change the colName"の列があるのでColNameの横に変更後の列名を書くことで変更することができます。
欠損値の置き換え
欠損値の置き換えをみていきます。上の"dataCleansingFrom_iris改_.xlsx"を例に説明していきます。
numeric 型のデータ"Sepal.Length"には、"欠損値"と"測定なし"が"Missing Values"であると判定されています。dataCleanserにより、これら2つのデータがNAであると判定されています。
これらのデータをNAにしたくないとき、例えば"欠損値"と"測定なし"を0に変更したい場合があると思います。
"欠損値"と"測定なし"を0に変更したいときは、次の画像のように、"dataCleansingFrom_iris改_.xlsx"の4列目の"Replace the column B with the spesific numbers"を置き換え後の値を代入します。
代入したら、保存してエクセルファイルを閉じます。
dataCleanserを実行してみましょう。実行すると、次のようにSepal.Lengthにあった欠損値がすべて0に置き換わっています。
1 2 3 4 5 6 7 8 | > dataCleanser("iris改")[, "Sepal.Length"] [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9 5.4 4.8 4.8 4.3 5.8 5.7 5.4 5.1 5.7 5.1 5.4 5.1 [23] 4.6 5.1 4.8 5.0 5.0 5.2 0.0 4.7 4.8 5.4 5.2 0.0 4.9 5.0 0.0 4.9 4.4 5.1 5.0 0.0 4.4 5.0 [45] 5.1 4.8 5.1 4.6 0.0 0.0 7.0 6.4 6.9 5.5 6.5 5.7 6.3 4.9 6.6 5.2 5.0 5.9 6.0 6.1 5.6 6.7 [67] 5.6 5.8 6.2 5.6 5.9 6.1 6.3 6.1 6.4 6.6 6.8 6.7 6.0 5.7 5.5 5.5 5.8 6.0 5.4 6.0 6.7 6.3 [89] 5.6 5.5 5.5 6.1 5.8 5.0 5.6 5.7 5.7 6.2 5.1 5.7 6.3 5.8 7.1 6.3 6.5 7.6 4.9 7.3 6.7 7.2 [111] 6.5 6.4 6.8 5.7 5.8 6.4 6.5 7.7 7.7 6.0 6.9 5.6 7.7 6.3 6.7 7.2 6.2 6.1 6.4 7.2 7.4 7.9 [133] 6.4 6.3 6.1 7.7 6.3 6.4 6.0 6.9 6.7 6.9 5.8 6.8 6.7 6.7 6.3 6.5 6.2 0.0 |
ココに注意
置き換え後の値が数値以外の場合は通常通りNAになります。
numericをカテゴリカルデータに変更
numeric型をカテゴリカルデータに変更したい場合を考えます。
1列目の"Sepal.Length"を(-∞, 5)と[5, ∞)という区間に分けてみます。
"dataCleansingForm_iris改_.xlsx"の6行目と8行目にそれぞれ、cut関数のbreaksとlabelsの引数に対応するように書いていきます。
上の区間に分けたい場合、次のように","区切りでbreaksを代入します(" "は入れないでください)。
エクセルファイルを保存し、閉じます。dataCleanserを再び実行すると次のように、"Sepal.Length"を参照するとカテゴリカルデータに変更されていることが確認できます。
1 2 3 4 5 6 7 8 9 10 11 | > dataCleanser("iris改")[,"Sepal.Length"] [1] ≧5 <5 <5 <5 ≧5 ≧5 <5 ≧5 <5 <5 ≧5 <5 <5 <5 ≧5 ≧5 ≧5 ≧5 [19] ≧5 ≧5 ≧5 ≧5 <5 ≧5 <5 ≧5 ≧5 ≧5 <NA> <5 <5 ≧5 ≧5 <NA> <5 ≧5 [37] <NA> <5 <5 ≧5 ≧5 <NA> <5 ≧5 ≧5 <5 ≧5 <5 <NA> <NA> ≧5 ≧5 ≧5 ≧5 [55] ≧5 ≧5 ≧5 <5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 [73] ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 [91] ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 <5 ≧5 [109] ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 [127] ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 ≧5 [145] ≧5 ≧5 ≧5 ≧5 ≧5 <NA> Levels: <5 ≧5 |
factorのlevelsの変更
次にfactorのlevelsの変更方法を説明します。
"dataCleansingForm_iris改_.xlsx"のシート"factor"には、levelsの列があり"Species"のlevelsが整理されていることが分かります。
Speciesののlevels"setosa"、"versicolor"、"virginica"を"セトナ"、"バーシクル"、"バージニカ"に変更してみます。
次のように、シート"factor"の"Replace the column B with"に置き換え後の値を代入してください。
エクセルファイルを保存し閉じたら、dataCleanserを実行してください。
次のように、列"Species"のlevelsが英語から日本語に変更されていることが確認できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | > dataCleanser("iris改")[,"Species"] [1] セトナ セトナ セトナ セトナ セトナ セトナ セトナ セトナ [9] セトナ セトナ セトナ セトナ セトナ セトナ セトナ セトナ [17] セトナ セトナ セトナ セトナ セトナ セトナ セトナ セトナ [25] セトナ セトナ セトナ セトナ セトナ セトナ セトナ セトナ [33] セトナ セトナ セトナ セトナ セトナ セトナ セトナ セトナ [41] セトナ セトナ セトナ セトナ セトナ セトナ セトナ セトナ [49] セトナ セトナ バーシクル バーシクル バーシクル バーシクル バーシクル バーシクル [57] バーシクル バーシクル バーシクル バーシクル バーシクル バーシクル バーシクル バーシクル [65] バーシクル バーシクル バーシクル バーシクル バーシクル バーシクル バーシクル バーシクル [73] バーシクル バーシクル バーシクル バーシクル バーシクル バーシクル バーシクル バーシクル [81] バーシクル バーシクル バーシクル バーシクル バーシクル バーシクル バーシクル バーシクル [89] バーシクル バーシクル バーシクル バーシクル バーシクル バーシクル バーシクル バーシクル [97] バーシクル バーシクル バーシクル バーシクル バージニカ バージニカ バージニカ バージニカ [105] バージニカ バージニカ バージニカ バージニカ バージニカ バージニカ バージニカ バージニカ [113] バージニカ バージニカ バージニカ バージニカ バージニカ バージニカ バージニカ バージニカ [121] バージニカ バージニカ バージニカ バージニカ バージニカ バージニカ バージニカ バージニカ [129] バージニカ バージニカ バージニカ バージニカ バージニカ バージニカ バージニカ バージニカ [137] バージニカ バージニカ バージニカ バージニカ バージニカ バージニカ バージニカ バージニカ [145] バージニカ バージニカ バージニカ バージニカ バージニカ バージニカ Levels: セトナ バーシクル バージニカ |
ココに注意
変更したいlevelsと変更後の値はエクセルファイル上で対応する(横に並ぶ)ようにしてください。
また、あるlevelsをNAにしたいときは、次の画像のようにNAにしたいlevelの横にN/Aを入れます。
factorのlevelsのプール
facorのlevesのプール方法について説明します。
levelsをプールするには、"dataCleansingForm_iris改_.xlsx"の6行目の"Pool the column B"の列に、プールしたいlevelsの番号を"+"を用いて書きます。
levelsの番号は2列に"No.1"、"No.2"、"No.3"のように、各levelsに対応する番号が並んであります。
例として、セトナとバージクルをプールしてみましょう。次の画像のように、4列目に"1+2"を代入します。
エクセルファイルを保存し閉じたら、dataCleanserを実行します。
実行すると次のように、"Species"のlevelsのセトナとバーシクルがプールされていることが分かります。