こんにちは、usagi-sanです。今回は前回の記事に続いて、データ整形の練習をしていきます。
前回は教育用データセットを扱いやすい形に整えました。
今回はデータフレームのnumeric型のデータやfactor型のデータの操作について学んでいきます。
今回用いるプログラミングコードは以下で ダウンロードできます。
R言語 データ整形numeric型やfactor型 Rスクリプト
ぜひぜひ練習用として、ダウンロードしてみてください 。
データセットを読み込む
では早速、教育用データセットを読み込み、前回の記事と同様に整形後のデータフレームを用意します。
次のコードは前回の記事と同様のものとなります。
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 42 43 44 45 46 47 48 49 50 51 | #データ整形の方法 df <- read.csv("SSDSE-2020A.csv", fileEncoding = "CP932") for(i in 1:ncol(df)){ ##データ整形の練習として複数の種類の欠損値を代入 for (j in 1:10){ random <- sample(3:nrow(df), 30) #sample()ベクトルの要素をランダムに返す df[random[1:10], i] <- "" df[random[11:20], i] <- "欠損値" df[random[21:30], i] <- "unknown" } } #NA挿入後のデータフレームを保存(ここでは列数が多いので30列まで扱う) write.csv(df, paste0("SSDSE-2020A(NA挿入後).csv"), fileEncoding = "CP932", row.names = F) #準備が整ったので、再度データを読み込む df <- read.csv(paste0("SSDSE-2020A(NA挿入後).csv"), fileEncoding = "CP932") #データの列名としては、1,2行目のみ必要そうなので、2行を組み合わせて列名とする colnames(df) <- paste0(df[1,], "_" ,df[2,]) #念のため、区切り文字として"_"を用いる df <- df[-c(1,2),] #1,2行目を消去する #欠損値を整理する #for文を用いた例 for(i in 1:ncol(df)){ df[,i] <- replace(df[,i], df[,i] == "" | df[,i] == "欠損値" | df[,i] == "unknown", NA) } #apply関数を用いた例 #df<- apply(df, 2, function(x){ # return(replace(x, x == "" | x == "欠損値" | x == "unknown" , NA)) # } #) #数値データの整理 #for文を用いた例 for(i in 4:ncol(df)){ df[,i] <- as.numeric(df[,i]) } #apply関数を用いた例 #df[,4:ncol(df)]<- apply(df[,4:ncol(df)], 2, function(x){ # return(as.numeric(x)) #} #) #因子データの整理 #for文を用いた例 for(i in 1:3){ df[,i] <- as.factor(df[,i]) } #apply関数を用いた例 #df[,1:3]<- apply(df[,1:3], 2, function(x){ # return(as.factor(x)) #} #) |
実行するとdfに整形後のデータフレームが代入されています。
以降、このdfのnumeric型のデータやfactor型のデータの操作を説明します。
numeric型のデータをカテゴリカルデータに
まず、数値データ(numeric型のデータ)をカテゴリカルデータに変更する方法を紹介します。
カテゴリカルデータの例
例えば、次の身長を意味するheightというデータを次で与えます。
1 | height<- c(155,178,158,165,167,172,159,172) |
このデータを~160、160~170、170~という3つのグループに分けると、heightは次のようになります。
1 2 3 | > catHeight [1] ~160 170~ ~160 160~170 160~170 170~ ~160 170~ Levels: ~160 160~170 170~ |
身長というnumeric型のデータを~160、160~170、170~の3つのグループで分けることで3つ水準からなるfactor型のカテゴリカルデータを作成しました。
このような大小関係をもつfactor型のデータに変更できます。
関数cut
カテゴリカルデータを作成する際には、関数cutを用いると便利です。
dfの"2015_総人口"という列に対して、関数cutを使ってみます。
総人口を「0~5000、5000~10000、10000~15000、15000~20000、20000~」という5つのカテゴリに分けたいときには、次を実行します。
1 2 | bar <- cut(df[,"2015_総人口"], breaks = c(0, 5000, 10000, 15000, 20000,1e+10), labels = c("0~5000", "5000~10000", "10000~15000","15000~20000","20000~"), right = FALSE) |
barを参照すると次のように、df[,"2015総人口"]が「0~5000、5000~10000、10000~15000、15000~20000、20000~」を水準としてもつfactor型のデータに変わっていることが分かります。
cutの引数breaksに分割する区間を指定し、labelsに水準の名前を指定します。
また、引数rightは区間の閉区間、開区間の設定を行います。
上を例に挙げて説明すると、
- right=TRUEのとき「0~5000」という区間は(0, 5000]、すなわち「0より大きく5000以下」
- right = FALSEのとき、「0~5000」という区間は[0, 5000)、すなわち「0以上5000未満」
を意味します。
特にこだわりがないのであれば、right = FALSEをお勧めします。
余談にはなりますが、次のようにbreaksを設定すると、10000個の区間を作ることもできます。
1 2 3 4 5 6 7 8 | > tmp <- cut(df[,"2015_総人口"], breaks = 100*(0:10000), right = FALSE) #1万個の区間で分割 > tmp[1:20] [1] <NA> [2.659e+05,2.66e+05) [1.219e+05,1.22e+05) [3.396e+05,3.397e+05) [5] [8.85e+04,8.86e+04) [1.747e+05,1.748e+05) [1.693e+05,1.694e+05) [1.212e+05,1.213e+05) [9] [8800,8900) [8.44e+04,8.45e+04) [3.9e+04,3.91e+04) [2.22e+04,2.23e+04) [13] [1.727e+05,1.728e+05) [3.63e+04,3.64e+04) [2.3e+04,2.31e+04) [1.46e+04,1.47e+04) [17] [1.206e+05,1.207e+05) [1.11e+04,1.12e+04) [2.31e+04,2.32e+04) [1.99e+04,2e+04) 10000 Levels: [0,100) [100,200) [200,300) [300,400) [400,500) [500,600) [600,700) [700,800) ... [9.999e+05,1e+06) |
関数cut(x, breaks, labels = NULL, include.lowest = FALSE, right = TRUE, dig.lab = 3, ordered_result = FALSE, ...)の引数について、以下の表にまとめました。
breaks | カットポイントの数値ベクトル。またはカットする間隔。 |
labels | カテゴリカルデータの各レベルのラベルを指定する |
include.lowest | 閉区間に等しいデータをその区間のカテゴリに含めるか。デフォルトのright=TRUEの場合、左側の閉区間を含めるかどうか。 |
right | 区間を右側で閉じるか、また閉じないか。right = TRUEの場合、左側を閉じる。 |
dig.lab | ラベルを指定していないときに、levelsに使用される数値の桁数 |
ordered_result | 順序付けられた結果を返すかどうか |
データの挿入
barにdf[,"2015_総人口"]のカテゴリカルデータが入っているので、このベクトルをdfに挿入しましょう。
cbind、data.frameを用いてデータフレームにベクトルを挿入できます。他の方法として、関数transformを用いる方法もあります。
次のように実行することでdfの一番右に、ベクトルを挿入することでできます。
注意として、今回用いるデータの列名は"2015_~"などと数字で始まるため、transformを用いると列名の最初にXが加わります。cbindやdata.frameを用いるのが賢明です。
1 2 | df <- cbind(df, 総人口カテゴリカル = bar) #dfにカテゴリカルデータを追加する #df <- transform(df, 総人口カテゴリカル = bar) #transformを用いた例 |
関数transform(x, tag = y)の引数を以下にまとめました。
y | データフレームxに挿入するベクトル。tagを指定すると、tagが列名となる。 |
factor型のデータの操作
dfの都道府県の列を用いてfactorの操作の練習をしてみます。
factorのlevels(水準)を変更したり、levelsをプール(組み合わせ)したり、levelsの順番を変更したりしていきます。
levelsの参照
まず、df[, "年度_都道府県"]を参照してみます。
1 2 3 4 | > df[1:20,"年度_都道府県"] [1] <NA> 北海道 北海道 北海道 北海道 北海道 北海道 北海道 <NA> <NA> 北海道 北海道 北海道 北海道 [15] 北海道 北海道 北海道 北海道 北海道 北海道 47 Levels: 愛知県 愛媛県 茨城県 岡山県 沖縄県 岩手県 岐阜県 宮崎県 宮城県 京都府 熊本県 群馬県 ... 和歌山県 |
levelsは47都道府県であることが分かります。levelsは関数levelsを用いることで次のようにあることができます。
1 2 3 4 5 6 7 | > levels(df[,"年度_都道府県"]) [1] "愛知県" "愛媛県" "茨城県" "岡山県" "沖縄県" "岩手県" "岐阜県" "宮崎県" "宮城県" [10] "京都府" "熊本県" "群馬県" "広島県" "香川県" "高知県" "佐賀県" "埼玉県" "三重県" [19] "山形県" "山口県" "山梨県" "滋賀県" "鹿児島県" "秋田県" "新潟県" "神奈川県" "青森県" [28] "静岡県" "石川県" "千葉県" "大阪府" "大分県" "長崎県" "長野県" "鳥取県" "島根県" [37] "東京都" "徳島県" "栃木県" "奈良県" "富山県" "福井県" "福岡県" "福島県" "兵庫県" [46] "北海道" "和歌山県" |
上の実行例を見ればわかる通り、辞書順(levelsはアルファベット順、またはあいうえお順)になっていることができます。
levelsの数を参照するときには、関数nlevelsを用います。
1 2 | > nlevels(bar) #水準の数 [1] 8 |
levelsの変更
では、levelsを都道府県別から地方別に変更してみましょう。
準備として、次のように各都道府県に対応する地方のリストを定義します。
1 2 3 4 5 6 7 8 9 | #因子の水準を変更してみる hokkaidou <- list(c("北海道"),region = "北海道地方") touhoku <- list(c("青森県", "岩手県", "宮城県", "秋田県", "山形県", "福島県"), region = "東北地方") kantou <- list(c("茨城県", "栃木県","群馬県" , "埼玉県", "千葉県", "東京都", "神奈川県"), region = "関東地方") tyuubu <- list(c("新潟県", "富山県","石川県" ,"福井県" ,"山梨県" ,"長野県" , "岐阜県", "静岡県", "愛知県"), region = "中部地方") kinki <- list(c("三重県", "滋賀県", "京都府", "大阪府", "兵庫県", "奈良県", "和歌山県"), region = "近畿地方") tyuugoku <- list(c("鳥取県", "島根県", "岡山県","広島県" , "山口県"), region = "中国地方") sikoku <- list(c("徳島県", "香川県", "愛媛県", "高知県"), region = "四国地方") kyuusyuu <- list(c("福岡県", "佐賀県", "長崎県", "熊本県", "大分県", "宮崎県", "鹿児島県", "沖縄県"), region = "九州地方") |
各地方のリストの最初の要素にその地方の都道府県を、2つ目の要素に地方の名前を代入しました。
これらのリストをさらにリストlist_regionに格納することで参照が楽になります(fot文を用いるときに楽になります)。
1 | list_region <- list(hokkaidou, touhoku, kantou, tyuubu, kinki, tyuugoku, sikoku, kyuusyuu) |
levelsを変更する用意が整いました。関数replaceを用いて、都道府県に対応する地方に置き換えてみましょう。
1 2 3 4 5 6 7 8 9 | bar <- as.character(df[,"年度_都道府県"]) #character型に変更する for(i in list_region){ for(j in i[[1]]){ bar <- replace(bar, bar == j, i$region) } } bar <- as.factor(bar) |
for文について、iはlist_regionの要素である各都道府県のリストであり、jは各都道府県のリストiの1番目の要素である都道府県のベクトルを指します。都道府県のベクトルi[[1]]の要素jに等しいbarの要素を地方i$regionで置き換えています。
注意として、最初にfactorであるdf[,"年度_都道府県"]をcharacterに変更してます。
factor型のデータにreplaceを用いるとエラーを出すため、注意しましょう。
最後に9行目でcharacter型のbarをfactor形に戻します。
次を実行すると都道府県のlevelsが地方に置き換わっていることが分かります。
1 2 3 4 5 | > bar[1:20] [1] <NA> 北海道地方 北海道地方 北海道地方 北海道地方 北海道地方 北海道地方 北海道地方 <NA> [10] <NA> 北海道地方 北海道地方 北海道地方 北海道地方 北海道地方 北海道地方 北海道地方 北海道地方 [19] 北海道地方 北海道地方 Levels: 関東地方 近畿地方 九州地方 四国地方 中国地方 中部地方 東北地方 北海道地方 |
また、関数levelsで次のようにも、levelsの順序が変更されたことが分かります。
1 2 | > levels(bar) [1] "北海道地方" "東北地方" "関東地方" "中部地方" "近畿地方" "中国地方" "四国地方" "九州地方" |
levelsの順番の変更
今度はlevelsの順序を変更する方法を説明します。
先ほどの地方のfactorのlevelsの順序を見てみると、辞書順に並んでおり、これを「北海道、東北地方、関東地方、. . . 、九州地方」に変更したい時があると思います。
関数factorの引数levelsを指定してあげることでlevelsの変更が可能です。
下のコード2行目のように、levelsのように順序を指定実行します。
1 2 | #水準の順番を変更する bar <- factor(bar, levels = c("北海道地方", "東北地方", "関東地方", "中部地方", "近畿地方", "中国地方", "四国地方", "九州地方")) |
順序が変更されているか確認してみます。
1 2 3 4 5 | > bar[1:20] [1] 北海道地方 北海道地方 北海道地方 北海道地方 北海道地方 北海道地方 <NA> 北海道地方 北海道地方 [10] 北海道地方 北海道地方 北海道地方 北海道地方 <NA> 北海道地方 北海道地方 北海道地方 北海道地方 [19] 北海道地方 北海道地方 Levels: 北海道地方 東北地方 関東地方 中部地方 近畿地方 中国地方 四国地方 九州地方 |
上のようにLevesの項目が「関東地方 近畿地方 九州地方、. . . 」から「北海道地方 東北地方 関東地方、. . . 」に変更されたことが分かります。
最後に列名"地方"として、このfactorの列をdfの一番右に挿入します。
1 2 | df <- cbind(df, 地方 = bar) #df <- transform(df, 地方 = bar) #transformを用いた例 |
水準のプール
統計解析を行う上で、水準をプール(組み合わせる)したい場合があります。
levelsをプールしたいときには、前にも紹介したreplaceを用います。
北海道地方と東北地方をプールを例に説明していきます。
1 2 3 4 | #北海道地方と東北地方をプールする bar <- as.character(bar) bar <- replace(bar, bar == "東北地方" | bar == "北海道地方", "東北地方.北海道地方") bar <- as.factor(bar) |
2行目でfactorをcharacterに変更後、3行目でreplaceを用いて"東北地方"、または"北海道地方"を"東北地方.北海道地方"に置き換えています。最後に4ぎょうめで再びfactorに戻します。
levelsを用いて確認してみると、次のようにlevelsの項目に東北地方と北海道地方をプールしたlevelが加えられたことが分かります。
1 2 3 | > levels(bar) [1] "関東地方" "近畿地方" "九州地方" "四国地方" [5] "中国地方" "中部地方" "東北地方.北海道地方" |
最後にdfの一番右にプール後の列を挿入します。
1 2 | df <- cbind(df, 地方.東北北海道プール = bar) #df <- transform(df, 地方.東北北海道プール = bar) #transformを用いた例 |
levelsの名前の変更
levelsをの変更方法について紹介します。
「男性、女性」を「Male、Female」や「1、0」に変更したい場合などがあります。
次のように関数factorの引数にlevelsとlabelsを指定することで、変更したいlevelsをlabelsの名前に変更することができます。
1 2 | #factorの水準名の変更 bar <- factor(df[,"総人口カテゴリカル"], levels = levels(df[,"総人口カテゴリカル"]), labels = c("とても少ない" ,"少ない" ,"普通" ,"多い" ,"とても多い")) |
上のコードでは、factorは、labelsがlevelsに対応付けられることを利用しています。
barを参照してみると、「0~5000、5000~10000、10000~15000、15000~20000、20000~」というlevelsが「とても少ない、少ない、普通、多い、とても多い」に変更されたことが確認できます。
1 2 3 4 5 | > bar[1:20] [1] <NA> とても多い とても多い <NA> <NA> とても多い とても多い とても多い 少ない [10] とても多い <NA> とても多い とても多い とても多い とても多い 普通 とても多い 普通 [19] とても多い 多い Levels: とても少ない 少ない 普通 多い とても多い |
levelsに大小関係を持たせる
levelsに大小関係を持たせる方法を紹介します。
先ほどのlevels「とても少ない、少ない、普通、多い、とても多い」を「とても少ない<少ない<普通<多い<とても多い」というように大小関係を持たせ、数値のようにふるまいたい場合があると思います。
levelsに大小関係を持たせるときは、関数orderedを用います。
levelsの変更との違いは、大小関係を持たせることで比較演算子「<、>」が使えるようになることです。
まず準備として、先ほどのbarをcharacterに変更しfactorにすることで、levelsを辞書順にします。
1 2 | #注意characterに変更後factorにすると水準が文字コード順に並ぶ bar <- as.factor(as.character(bar)) |
barを参照すると、levelsの順序がおかしくなっていることが分かります。これを関数orderedを用いて、大小関係を持たせていきます。
orderedの引数は、levelsの変更で行った指定方法と同じです。変更後のlevelsを引数levelsに指定します。