#追記 2017/11/30
非常にスマートなやり方をコメントにて教えていただきました。
データへのアクセスのところでcharacter型のベクトルを入れてあげれば一発でできるみたいでして。とてもスマートです。
> data[, columnList]
id col1 col4 col6
1 1 3.6 5.0 6.1
2 2 4.7 4.0 7.8
3 3 2.7 2.7 6.2
4 4 2.8 4.7 3.7
5 5 2.5 2.4 5.5
6 6 3.9 4.6 5.6
7 7 2.2 6.0 6.5
8 8 4.2 4.0 5.3
9 9 1.3 4.5 6.0
10 10 3.2 4.0 7.6
こんな単純なことに気付けなかった自分が恥ずかしい…。とても遠回りしていたみたいで余計なことを書いてしまい申し訳ありません。
これを使えばとても短くなりました。ご指摘いただいた方には特別の感謝を。
#preparation
data <- read.csv("input/data.csv") #input data
options(digits=2) #change digit
#extraction based on columnList
columnList <- c("id", "col1", "col4", "col6") #make columnList
data.selected <- data[, columnList] #access data
追記. 2017/11/30
#はじめに
読み込んだデータの抽出を行う際に列名を指定してできたらと思って作ってみました。
注)さらっと探して参考が見つからなくてとりあえずで作ったのでブラッシュアップ前のものになります。より良い方法に関するアドバイス等いただければ幸いです。
#完成品
長さとしてはこのくらいです。
data定義時のread.csvの指定先と、columnListでの列名の定義さえ変えてもらえればコピペして使えます。
#preparation
data <- read.csv("input/data.csv") #input data
options(digits=2) #change digit
#biding
columnList <- c("id", "col1", "col4", "col6") #make columnList
data.selected <- data.frame(matrix(nrow=nrow(data))) #make empty dataframe
for (i in 1:length(columnList)){
data.selected <- cbind(data.selected, data[, columnList[i]]) #bind data by referring columnList
}
#coordination
data.selected <- data.selected[, -1] #remove empty column
colnames(data.selected) <- columnList #rename
#用いたデータ
以下のような表から"id", "col1", "col4", "col6"の列のみを抽出したいと思います。
id | col1 | col2 | col3 | col4 | col5 | col6 | |
---|---|---|---|---|---|---|---|
1 | 1 | 3.6 | 3.2 | 3.4 | 5.0 | 4.1 | 6.1 |
2 | 2 | 4.7 | 4.0 | 2.8 | 4.0 | 4.4 | 7.8 |
3 | 3 | 2.7 | 2.8 | 2.3 | 2.7 | 8.6 | 6.2 |
4 | 4 | 2.8 | 1.6 | 2.2 | 4.7 | 5.2 | 3.7 |
5 | 5 | 2.5 | 2.4 | 3.4 | 2.4 | 6.8 | 5.5 |
6 | 6 | 3.9 | 3.7 | 3.1 | 4.6 | 6.1 | 5.6 |
7 | 7 | 2.2 | 3.8 | 3.3 | 6.0 | 6.2 | 6.5 |
8 | 8 | 4.2 | 4.0 | 3.4 | 4.0 | 2.7 | 5.3 |
9 | 9 | 1.3 | 1.9 | 2.1 | 4.5 | 5.7 | 6.0 |
10 | 10 | 3.2 | 2.5 | 4.5 | 4.0 | 5.7 | 7.6 |
もし"col1", "col2", "col3"という2列〜4列目という連続した列を抽出したい場合は以下のような処理ですぐできるので以下から読む必要は無くなります。
> data.col1to3 <- data[, 2:4]
> print(data.col1to3)
col1 col2 col3
1 3.6 3.2 3.4
2 4.7 4.0 2.8
3 2.7 2.8 2.3
4 2.8 1.6 2.2
5 2.5 2.4 3.4
6 3.9 3.7 3.1
7 2.2 3.8 3.3
8 4.2 4.0 3.4
9 1.3 1.9 2.1
10 3.2 2.5 4.5
#指定した列にアクセスする
data["行番号", "列番号"] によって特定のデータにアクセスする方法1はここから多用します。
例えば"col3"の列にのみを抽出する場合は、以下のようにデータにアクセスします。
> data[, "col3"]
[1] 3.4 2.8 2.3 2.2 3.4 3.1 3.3 3.4 2.1 4.5
これは列番号でも可能です。"col3"は4列目なので
> data[, 4]
[1] 3.4 2.8 2.3 2.2 3.4 3.1 3.3 3.4 2.1 4.5
もし"col1", "col2", "col3"のように、2〜4列目で連続したような列に対してアクセス(抽出)したい場合は以下のような処理ですぐできるのでこれより下は読む必要は無くなります。
> data[, 2:4]
col1 col2 col3
1 3.6 3.2 3.4
2 4.7 4.0 2.8
3 2.7 2.8 2.3
4 2.8 1.6 2.2
5 2.5 2.4 3.4
6 3.9 3.7 3.1
7 2.2 3.8 3.3
8 4.2 4.0 3.4
9 1.3 1.9 2.1
10 3.2 2.5 4.5
ただし複数の列名を指定して抽出することはできないのでご注意ください。
> data[, "col1","col2","col3"]
`[.data.frame`(data, , "col1", "col2", "col3") でエラー:
使われていない引数 ("col3")
#列名リストを利用してデータを抽出する
個別に列名を指定して抽出する方法はあったので、それを利用して列名リスト基準にデータを抽出します。
まずはc関数を用いて列名リストのベクトルを作成
> columnList <- c("id", "col1", "col4", "col6")
> columnList
[1] "id" "col1" "col4" "col6"
ベクトルも列の番号を指定してアクセスできます。ここまでの手法を組み合わせるとこのようなこともできます。
> columnList[2]
[1] "col1"
> data[, columnList[2]]
[1] 3.6 4.7 2.7 2.8 2.5 3.9 2.2 4.2 1.3 3.2
#指定した列名のみのデータフレームを作成する
ここからはforループを使った力技になります。もっとスマートな方法があればなぁ…。
まずは元のデータと同じ行数の空のデータフレームを作成します。このデータフレームが最終的にできるものの元となります。
> data.selected <- data.frame(matrix(nrow=nrow(data)))
> data.selected
matrix.nrow...nrow.data..
1 NA
2 NA
3 NA
4 NA
5 NA
6 NA
7 NA
8 NA
9 NA
10 NA
ちょっとブサイクですが後で消すので気にしないでください。
ここではnrow(data)によって元のデータの行数を取得し、matrix関数で行数を指定して10行1列の行列を作成し、それをデータフレームとしました。
> nrow(data)
[1] 10
> matrix(nrow=nrow(data), ncol=1)
[,1]
[1,] NA
[2,] NA
[3,] NA
[4,] NA
[5,] NA
[6,] NA
[7,] NA
[8,] NA
[9,] NA
[10,] NA
そして最後にforループにより今作った空のデータフレームに欲しい列名の列を結合させていきます。
cbind関数は横に並べてデータを結合する方法2です。
for (i in 1:length(columnList)){
data.selected <- cbind(data.selected, data[, columnList[i]])
}
ここでlength(columnList)とは、columnListというベクトルに順次アクセスするための最大値を取得するためです。
> length(columnList)
[1] 4
#体裁を整える
現在のデータはこのようにまだブサイクなままです。綺麗にしていきましょう。
> data.selected
matrix.nrow...nrow.data.. data[, columnList[i]] data[, columnList[i]] data[, columnList[i]] data[, columnList[i]]
1 NA 1 3.6 5.0 6.1
2 NA 2 4.7 4.0 7.8
3 NA 3 2.7 2.7 6.2
4 NA 4 2.8 4.7 3.7
5 NA 5 2.5 2.4 5.5
6 NA 6 3.9 4.6 5.6
7 NA 7 2.2 6.0 6.5
8 NA 8 4.2 4.0 5.3
9 NA 9 1.3 4.5 6.0
10 NA 10 3.2 4.0 7.6
先ほどのデータへのアクセスを利用して、data[, -列番号]によって特定の列の削除もできます。
そして最後にcolnames関数を用いてデータフレームの列名を変更3します。
> data.selected <- data.selected[, -1]
> colnames(data.selected) <- columnList
> data.selected
id col1 col4 col6
1 1 3.6 5.0 6.1
2 2 4.7 4.0 7.8
3 3 2.7 2.7 6.2
4 4 2.8 4.7 3.7
5 5 2.5 2.4 5.5
6 6 3.9 4.6 5.6
7 7 2.2 6.0 6.5
8 8 4.2 4.0 5.3
9 9 1.3 4.5 6.0
10 10 3.2 4.0 7.6
はい、完成です。
ご指摘やコメント等お待ちしております。
#参考
#NG集[No.1]
cbind()の際に列名を指定してみたけどうまくいかなかった。
> for (i in 1:length(columnList)){
+ data.selected <- cbind(data.selected, columnList[i]=data[, columnList[i]])
エラー: 予想外の '=' です in:
"for (i in 1:length(columnList)){
data.selected <- cbind(data.selected, columnList[i]="
> }
エラー: 予想外の '}' です in "}"
うーん、columnList[i]みたいなの使わなければ行けるんだけどなぁ。
> cbind(data.selected, test=matrix(nrow=10))
matrix.nrow...nrow.data.. test
1 NA NA
2 NA NA
3 NA NA
4 NA NA
5 NA NA
6 NA NA
7 NA NA
8 NA NA
9 NA NA
10 NA NA
> cbind(data.selected, "test"=matrix(nrow=10))
matrix.nrow...nrow.data.. test
1 NA NA
2 NA NA
3 NA NA
4 NA NA
5 NA NA
6 NA NA
7 NA NA
8 NA NA
9 NA NA
10 NA NA
as.character(columnList[i])で指定してみてもダメでした。
#NG集[No.2]
assign関数を使って列名の変数を定義し結合したけどダメだった。
厳密にはデータフレームの列名の定義がうまくいかず結局最後の"colnames(data.selected) <- columnList"が必要で省力化できない。
> for (i in 1:length(columnList)){
+ data.selected <- cbind(data.selected, assign(columnList[i], data[, columnList[i]]))
+ }
> data.selected
matrix.nrow...nrow.data.. assign(columnList[i], data[, columnList[i]]) assign(columnList[i], data[, columnList[i]]) assign(columnList[i], data[, columnList[i]]) assign(columnList[i], data[, columnList[i]])
1 NA 1 3.6 5.0 6.1
2 NA 2 4.7 4.0 7.8
3 NA 3 2.7 2.7 6.2
4 NA 4 2.8 4.7 3.7
5 NA 5 2.5 2.4 5.5
6 NA 6 3.9 4.6 5.6
7 NA 7 2.2 6.0 6.5
8 NA 8 4.2 4.0 5.3
9 NA 9 1.3 4.5 6.0
10 NA 10 3.2 4.0 7.6
列名長すぎんよー。