<<目次へ


データフレームの作成と編集





■ データフレームを作成する

 例えば、Excelのワークシート上に図1のようなデータが保存されていたとします。このデータをRに取り込み、それからデータフレームを作成することを考えます。その場合、方法としては2つあります。1つはCSV(カンマで区切られたデータ)形式のファイルとして保存しなおし、それを取り込むという方法です。もう1つはRのコンソールウィンドウ上で直接データを打ち込んで作成するという方法です。


図1 Excelに保存されているデータ

 扱うデータの量が多い場合はCSVファイルを作成し、それを読み込む方が良いでしょう。そうではなく、今回のように少量のデータであれば直接コマンドしてデータフレームを作成した方が速いかもしれません。


CSVファイルの読み込みによる方法 read.table()を使う

 まずはCSVファイルの作り方から説明します。Excelのワークシート上に入力されているデータ範囲(A1:D8)をコピーして、それをメモ帳などのテキストエディタにペーストします。そうしたら、[名前をつけて保存]し、適当なファイル名(ここではsample_data.csvとします)をつけて保存するだけです。このとき、[ファイルの種類]を[全てのファイル]にしておいて、拡張子(.csv)を付け忘れないようにしましょう。

 CSVファイルが用意できたならば、今度はRのread.table()という関数を用いてデータを読み込みます。ここではsample_data.csvがDドライブに保存されていたとします。

# データの読み込み
> dat <- read.table("D://sample_data.csv", header=TRUE)
> dat # datの中身を表示
  気温 天候 曜日 売上
1   20   曇   日   86
2   21   曇   月  107
3   17   曇   火  111
4   16   晴   水   86
5   19   曇   木  109
6   14   晴   金   91
7   22   雨   土   99

 read.table()の引数であるheaderをFALSEにすると、先頭にあるラベル(列名)が1行目のデータとして読み込まれてしまいます。なお、デフォルト(最初の状態)でFALSEになっていますので、何も指定しない場合は自動的にheader=FALSEになります。

# headerを省略した場合(FALSEとした場合)
> dat2 <- read.table("D://sample_data.csv")
> dat2
    V1   V2   V3   V4
1 気温 天候 曜日 売上
2   20   曇   日   86
3   21   曇   月  107
4   17   曇   火  111
5   16   晴   水   86
6   19   曇   木  109
7   14   晴   金   91
8   22   雨   土   99


直接コマンドして作る方法 data.frame()を使う

 いくつか方法はありますが、私がやりやすいと思う方法を1つ紹介します。

# それぞれのデータベクトルを作る
> Temperature <- c(20, 21, 17, 16, 19, 14, 22)
> Weather <- c("曇", "曇", "曇", "晴", "曇", "晴", "雨")
> Week <- c("日", "月", "火", "水", "木", "金", "土")
> Sales <- c(86, 107, 111, 86, 109, 91, 99)

# データフレームの作成
> dat3 <- data.frame(TEMPERATURE = Temperature, WEATHER = Weather,
+ WEEK = Week, SALES = Sales)

# dat3の中身を表示
> dat3
  TEMPERATURE WEATHER WEEK SALES
1          20      曇   日    86
2          21      曇   月   107
3          17      曇   火   111
4          16      晴   水    86
5          19      曇   木   109
6          14      晴   金    91
7          22      雨   土    99



■ 列名(変数名)をつける、変更する

 ところで、コンピュータ上で日本語を使うのはあまり好ましくありません。ファイル名も極力、半角英数で入力されたものにしましょう。R上であっても、なるべく日本語は使わないようにしましょう。

# names()で変数名を表示できます
> names(dat)
[1] "気温" "天候" "曜日" "売上"

# 新たな名前をつけます
> names(dat) <- c("TEMPERATURE", "WEATHER", "WEEK", "SALES")

# 再びnames()を使用
> names(dat)
[1] "TEMPERATURE" "WEATHER"     "WEEK"        "SALES"      

# 中身を表示して確認
> dat
  TEMPERATURE WEATHER WEEK SALES
1          20      曇   日    86
2          21      曇   月   107
3          17      曇   火   111
4          16      晴   水    86
5          19      曇   木   109
6          14      晴   金    91
7          22      雨   土    99

 ちなみに、names(dat)とするとdatの列名が表示されますが、これはcolnames(dat)としても同じ結果が得られます。また、rownames(dat)とすると、行名が表示されることになります。つまり、

> rownames(dat) <- c("", "", ..., "")

とすることによって、列名の変更と同じように、行名の変更ができるわけです。

 なお、今回用いたsample_data.csvは行名がなかったため、読み込んだ際には行名が1から7という数字が自動的に割り振られていました。もし行名が最初からついているデータであった場合は、read.table()の引数にrow.names=1と指定してあげれば良いのです。

> dat <- read.table(D://sample_data.csv, header=TRUE, row.names=1)



■ データフレームの中身の置換 *ややこしいのここは別に読まなくても良いです

 ところで、WEATHERとWEEKは文字型です。データフレームを作成する際に、文字型のデータベクトルは因子として扱われます。因子(factor)には水準(level)があり、例えば、WEATHERの水準は

> dat$WEEK
[1] 日 月 火 水 木 金 土
Levels: 火 金 月 水 土 日 木

とされています。水準1(Levels 1)は火、水準2は金のようになっているわけです。私たちの感覚だと、日、月、火、水、木、金、土の順番にそれぞれ水準1、水準2、、、のように割り当てられるのが普通ですが、R側では文字コードによって優先順位が変わるので、このようになっています。

 もし漢字(全角)ではなくて英語(半角)にしたい(置き換えたい)場合は次のような関数を定義しておくと便利です。

myfunc <- function(a, myn){
        mydata <- c()
        n <- length(a)
        n2 <- length(myn)
        for(i in 1:n){
                for(j in 1:n2){
                        if(a[i] == levels(a)[j]) mydata[i] <- myn[j]
                }
        }
        mydata <- as.factor(mydata)
}

 使い方は次の通りです。

# データフレームdatにおけるWEEKの中身を確認
> dat$WEEK
[1] 日 月 火 水 木 金 土
Levels: 火 金 月 水 土 日 木

# 英語に置き換える
> chikan <- myfunc(dat$WEEK, c("Tue", "Fri", "Mon", "Wed", "Sat", "Sun", "Thu"))

# データフレームdatのWEEKにchikanのデータを挿入
> dat$WEEK <- chikan
> dat # 中身の確認
  TEMPERATURE WEATHER WEEK SALES
1          20      曇  Sun    86
2          21      曇  Mon   107
3          17      曇  Tue   111
4          16      晴  Wed    86
5          19      曇  Thu   109
6          14      晴  Fri    91
7          22      雨  Sat    99

 ここで改めてWEEKの水準がどうなっているかを見てみましょう。

> dat$WEEK
[1] Sun Mon Tue Wed Thu Fri Sat
Levels: Fri Mon Sat Sun Thu Tue Wed

 すると、このようにSun, Mon, Tue, ...という順番ではなくて、やはりR側が勝手に水準の順番を解釈してしまいます。別に、水準の順番は解析においては関係ないので問題はありませんが、少ししっくり来ない感じがあります。

 そういう場合は先ほど使ったmyfunc()を使って、次のようにします。

> chikan2 <- myfunc(dat$WEEK, c(6, 2, 7, 1, 5, 3, 4))
> dat$WEEK <- chikan2
> dat
  TEMPERATURE WEATHER WEEK SALES
1          20      曇    1    86
2          21      曇    2   107
3          17      曇    3   111
4          16      晴    4    86
5          19      曇    5   109
6          14      晴    6    91
7          22      雨    7    99
> dat$WEEK
[1] 1 2 3 4 5 6 7
Levels: 1 2 3 4 5 6 7

 実はデータフレームを作成する際に、因子の扱いにはいくつかややこしいことがあります。ですから、Excelなどに原データを入力する際に、最初から数値を割り当てて入力してしまい、それを(Rでデータフレームを作成するときに)as.factor()を用いて因子として指定してやった方がいいでしょう(→補足1)。

 最後にWEATHERも数値を割り当てておきます。

> dat$WEATHER
[1] 曇 曇 曇 晴 曇 晴 雨
Levels: 雨 晴 曇
> chikan3 <- myfunc(dat$WEATHER, c(3, 1, 2))
> dat$WEATHER <- chikan3
> dat$WEATHER
[1] 2 2 2 1 2 1 3
Levels: 1 2 3

 すると、結局はこうなりました。

> dat
  TEMPERATURE WEATHER WEEK SALES
1          20       2    1    86
2          21       2    2   107
3          17       2    3   111
4          16       1    4    86
5          19       2    5   109
6          14       1    6    91
7          22       3    7    99

補足1

 どこかのデータベースから引っ張ってきたデータとかだと、今回のような曜日のデータ(月火水木金土日)を自分で数値に置換しなければなりません(もちろん、そのまま使っても良いですが)。その場合は置換機能をもったテキストエディタを使えばラクに作業を行うことができます。

 例えば、TeraPadが便利です。まずExcelなどからコピペした1次データがあります(図2)。


図2 1次データ

 これが用意できたら、[Ctrl] + [R]をタイプするか、[検索] -> [置換]の順にクリックしてください。すると、図3のようなウィンドウが開かれます。[検索する文字列]に「曇」を入力し、[置換後の文字列]に「2」を入力して、[すべて置換]をクリックします。


図3 TeraPadの置換機能

 すると、「曇」が「2」に置換されます(図4)。


図4 置換後のデータ

 しかし、実はこのようなことをしなくてもfactor()という関数を上手く使うことによって、上手にカテゴリカル型のデータを扱うことができます。

# 男性と女性を表すデータベクトル
> x <- c("男性", "男性", "女性", "男性", "女性")

# この時点では文字型のベクトル
> x
[1] "男性" "男性" "女性" "男性" "女性"

# カテゴリカル型のデータにする
> y <- factor(x, level=c("男性", "女性"))
> y
[1] 男性 男性 女性 男性 女性
Levels: 男性 女性

# 男性はMに、女性はFに置換
> z <- factor(y, level=c("男性", "女性"), label=c("M", "F"))
> z
[1] M M F M F
Levels: M F

# 文字を数値に置換することもできる。逆ももちろんできる。
> xx <- factor(z, level=c("F", "M"), label=c(1, 2))
> xx
[1] 2 2 1 2 1
Levels: 1 2

# ちなみにas.factor()には引数にlevelsやlabelsはない。
> yy <- as.factor(x)

# 中身を見るとやはり文字コード順になっている
> yy
[1] 男性 男性 女性 男性 女性
Levels: 女性 男性



■ データの抽出

 データフレームを作成して、それからある行のみのデータ(あるいは列のデータ)、特定の条件を満たす行(あるいは列)データを抽出したいこともあるでしょう。例えば、天候が晴れで、かつ売上が80万円以上のデータとかですね。

 データフレームを扱う場合、attach()を使ってパスを通しておくと便利です。

# パスを通す
> attach(dat3)

 データフレームにパスを通すことによって、そのデータフレームに含まれる変数へ直接アクセスすることができます。

> TEMPERATURE
[1] 20 21 17 16 19 14 22
> WEEK
[1] 日 月 火 水 木 金 土
Levels: 火 金 月 水 土 日 木

 パスを解除するためにはdetach()を使います。

# パスを解除
> detach(dat3)

# パスが通っていないので、変数TEMPERATUREは存在しないことになっている
> TEMPERATURE
 エラー:  オブジェクト "TEMPERATURE" は存在しません 

# WEEKも同様。
> WEEK
 エラー:  オブジェクト "WEEK" は存在しません

 いくつかの例を紹介しましょう。

# 例1
> dat3[dat3$WEATHER == "晴", ]
  TEMPERATURE WEATHER WEEK SALES
4          16      晴   水    86
6          14      晴   金    91

# 例2
> dat3[dat3$SALES >= 100, ]
  TEMPERATURE WEATHER WEEK SALES
2          21      曇   月   107
3          17      曇   火   111
5          19      曇   木   109

# 例3
> dat3[dat3$WEATHER == "曇" & dat3$TEMPERATURE >= 20, ]
  TEMPERATURE WEATHER WEEK SALES
1          20      曇   日    86
2          21      曇   月   107

# 例4
> dat3$SALES[dat3$SALES >= 90]
[1] 107 111 109  91  99

# 例5
> dat3$SALES[dat3$SALES >= 90 & dat3$WEATHER == "雨"]
[1] 99

 もしパスを通した状態であれば、[ ]のなかで

> dat3[WEATHER=="晴", ]
  TEMPERATURE WEATHER WEEK SALES
4          16      晴   水    86
6          14      晴   金    91

とするだけでよいのです。わざわざdat3$WEATHERとする必要はないわけです。

 ちなみに、&は「かつ」を意味しており、|は「または」という意味です。A & Bならば「AかつB」でAとBの両方ということになります。A | Bならば「AまたはB」で、AとBのどちらか一方ということになります。



■ データの編集

行、列の削除

 ある特定の列(変数)を削除するのは簡単です。

> my.data
  TEMPERATURE WEATHER WEEK SALES
1          20      曇   日    86
2          21      曇   月   107
3          17      曇   火   111
4          16      晴   水    86
5          19      曇   木   109
6          14      晴   金    91
7          22      雨   土    99

# 特定の列にNULLを代入する
> my.data[, 2] <- NULL

# NULLが代入された変数が削除されている
> my.data
  TEMPERATURE WEEK SALES
1          20   日    86
2          21   月   107
3          17   火   111
4          16   水    86
5          19   木   109
6          14   金    91
7          22   土    99

 行を削除するためには、たぶん、ちょっとの工夫が必要です。

> my.data
  TEMPERATURE WEATHER WEEK SALES
1          20      曇   日    86
2          21      曇   月   107
3          17      曇   火   111
4          16      晴   水    86
5          19      曇   木   109
6          14      晴   金    91
7          22      雨   土    99

# 削除したい行の任意の場所にNAを代入
> my.data[3, 1] <- NA

# NAを含む行を削除する関数na.omit()を使う
# 3行目"とされていた"データが削除されている
> (my.data2 <- na.omit(my.data))
  TEMPERATURE WEATHER WEEK SALES
1          20      曇   日    86
2          21      曇   月   107
4          16      晴   水    86
5          19      曇   木   109
6          14      晴   金    91
7          22      雨   土    99

# ラベルと行数が異なっていることに注意
> my.data2[3, ]
  TEMPERATURE WEATHER WEEK SALES
4          16      晴   水    86


行、列の追加

 これも列は簡単にできるのですが、新たな行を追加する場合はけっこうな手間がかかります。

 列は新たな変数をベクトルとして作り出し、それを既に作成されているデータフレームとcbind()を使って結合すればよいのです。

> new <- 1:7
> new
[1] 1 2 3 4 5 6 7
> cbind(my.data2, new)
  TEMPERATURE WEATHER WEEK SALES new
1          20      曇   日    86   1
2          21      曇   月   107   2
3          NA      曇   火   111   3
4          16      晴   水    86   4
5          19      曇   木   109   5
6          14      晴   金    91   6
7          22      雨   土    99   7

 行の場合も1行分のデータベクトルを作成して、それをrbind()で結合させればよいのですが、、、

> new.col <- c(10, "雨", "日", 80)
> (a <- rbind(my.data2, new.col))
  TEMPERATURE WEATHER WEEK SALES
1          20      曇   日    86
2          21      曇   月   107
3        <NA>      曇   火   111
4          16      晴   水    86
5          19      曇   木   109
6          14      晴   金    91
7          22      雨   土    99
8          10      雨   日    80

# 変数の中身を確認してみると
# 文字列になってしまっている
> a$TEMPERATURE
[1] "20" "21" NA   "16" "19" "14" "22" "10"

 基本的にベクトル内のデータ型は文字が含まれていれば、すべて文字列としてデータベクトルが作成されます。それなので、データフレームと結合した際に、全ての変数が文字型のデータになってしまったというわけです。

 この場合は、as.numeric()を使って数値データに変換してあげる必要があります。

> a$TEMPERATURE
[1] 20 21 NA 16 19 14 22 10

# 型の確認
> is.numeric(a$TEMPERATURE)
[1] TRUE

 ちなみに、型を検査するための関数、型を変換するための関数があります。numeric型であるかを判定するas.numeric()と変換するためのis.numeric()、文字型であるかを判定するas.character()とそれに変換するためのis.character()、そして因子型に対応するis.factorとas.factor()があります。通常はこの3つを覚えておけば、とくに問題はありません。