[[Rでデータクリーニング]]

まとまったページがない?じゃあ,作ろうじゃないですか。協力宜しく。早いもの勝ち。

こんなデータで,こんなデータクリーニングしたいなあというのがあれば,具体的に書けば,それを実現する関数なりが書き込まれるだろう(かな???)というページ。
----
#contents
----
*データクリーニングとは [#q180a6cf]

データ入力が終わったら,次にやることはデータクリーニングである。いきなりデータ解析を始めてはいけない。そもそも,入力されたデータがちゃんとしたものである保証はない。コーディングミスやタイプミスがある可能性が高いし,アンケート調査の場合には調査票のデータ自体が間違っていたり矛盾したデータであったりする。

データクリーニングとは,データのいろいろな誤りを修正することである。そのためには,誤入力の可能性があるデータを拾い出すことが必要である。これをデータチェックという。データの種類や誤りの種類によって,誤りを検出する方法もさまざまである。既存の関数を単独で使う場合もあるし,組み合わせて使えばさらに効果的なデータチェックをすることができることもある。場合によっては,専用の関数を書かなければならないこともある。

**一般的な手順 [#c407b240]

いろいろな入力ミスを検出し,その入力ミスのあるデータがどれであるかを出力し,正しいデータに置き換える。

たとえば,性別を 1(男),2(女) で入力しているのに,NA のほかに 9 とか 1.2 とか "male"という入力がある。以下の用にすれば,そういう変なデータを含む行が出力される。その中の ID No. に基づいて,元のデータがどうなっていたかを確認するのである。
 > d <- data.frame(ID=1:10, sex=c(1, 2, NA, 1.2, 9, "male", 2, 1, 2, 2))
 > summary(d)
        ID          sex   
  Min.   : 1.00   1   :2  
  1st Qu.: 3.25   1.2 :1  
  Median : 5.50   2   :4  
  Mean   : 5.50   9   :1  
  3rd Qu.: 7.75   male:1  
  Max.   :10.00   NA's:1  
 > table(d$sex, useNA="ifany")
    1  1.2    2    9 male <NA> 
    2    1    4    1    1    1 
 >  d <- na.omit(d)
 >  d[d$sex == 9,]
   ID sex
 5  5   9
 >  d[d$sex == 1.2,]
   ID sex
 4  4 1.2
 >  d[d$sex == "male", ]
   ID  sex
 6  6 male

**単純集計によるデータチェック [#d49b6291]

変数ごとに欠損値の有無,実際に記録されているデータ値の種類をみる。カテゴリー変数だと table 関数を使うとよい。連続変数だといきなり table 関数を使うは不適切なので,cut 関数でカテゴリー化してから table 関数を使うとよい。summary 関数によれば,NA の個数,最小値,最大値(カテゴリー変数の場合には主な値の個数)などが得られる。このような関数を使うことにより,たとえば身長として235(センチ)などと誤入力されたものを見つけることができる。ただし,身長が 168 センチの人のデータを 186 センチと誤入力したようなものは見つけることはできない。

**クロス集計によるデータチェック [#n8cc808c]

身長が 108 センチの人のデータを 196 センチと誤入力したようなものでも,別の変数たとえば年齢とクロス集計する,または散布図を描けば誤入力を発見できる場合もある。たとえば,その人の年齢が 10 歳であった場合,そんなに大きな子供は滅多にいないので,年齢の方が間違えているのかもわからないが,とにかくデータを確かめるきっかけにはなるだろう。

*2つのファイルの内容を比較する [#m9b24afb]

**ダブルチェック [#q264eea3]

同じデータを2つのファイルに2度入力し,内容を比較することにより入力ミスをチェックする。 [#y26ce2ed]
 compare <- function(file.a, file.b)
 {
     a <- readLines(file.a)
     b <- readLines(file.b)
     length.a <- length(a)    
     length.b <- length(b)
     if (length.a != length.b) {
         stop(paste("ファイルの行数が違います", length.a, "行と", length.b, "行"))
     }
     max.length <- max(nchar(c(a, b)))
     ruler1 <- paste(sprintf("%10i", 1:(max.length%/%10+1)), collapse="")
     ruler2 <- paste(rep("1234567890", (max.length%/%10+1)), collapse="")
     for (i in 1:length.a) {
         string.a <- a[i]
         string.b <- b[i]
         if (string.a != string.b) {
             character.a <- unlist(strsplit(string.a, ""))
             length.character.a <- length(character.a)
             character.b <- unlist(strsplit(string.b, ""))
             length.character.b <- length(character.b)
             min.c <- min(length.character.a, length.character.b)
             character.d <- ifelse(character.a[1:min.c] == character.b[1:min.c], " ", "v")
             character.d <- c(character.d, rep("v", max.length-min.c))
             string.d <- paste(character.d, collapse="")    
             cat(sprintf("      %s\n      %s\n      %s\n%4i: %s\n      %s\n\n",
                 ruler1, ruler2, string.d, i, string.a, string.b))    
         }
     }
 }
使用例
 > set.seed(12) # テストデータを作る
 > file.a <- "testdata1.dat"
 > file.b <- "testdata2.dat"
 > d <- matrix(sample(0:9, 250, replace=TRUE), 10)
 > write(apply(d, 1, paste, collapse=""), file=file.a)
 > d[sample(250, 5)] <- sample(0:9, 5)
 > write(apply(d, 1, paste, collapse=""), file=file.b)
 > compare(file.a, file.b) # ファイルの比較
                1         2         3
       123456789012345678901234567890
                  v             
    3: 9308949611478951141654247
       9308949611488951141654247
 
                1         2         3
       123456789012345678901234567890
                             v v
    6: 0429091924756856515266137
       0429091924756856515266933
 
                1         2         3
       123456789012345678901234567890
         v                      
    8: 6518057783166680942903649
       6558057783166680942903649
 
                1         2         3
       123456789012345678901234567890
       v                        
    9: 0643163133167844418159180
       1643163133167844418159180
 
 > unlink(c(file.a, file.b))

** 外部コマンドを使った例 [#f66c0bc9]

diffコマンドを使う。オプションなし
 > system(paste("diff", file.a, file.b))
 3c3
 < 9308949611478951141654247
 ---
 > 9308949611488951141654247
 6c6
 < 0429091924756856515266137
 ---
 > 0429091924756856515266933
 8,9c8,9
 < 6518057783166680942903649
 < 0643163133167844418159180
 ---
 > 6558057783166680942903649
 > 1643163133167844418159180

左右に並べるyオプションをつける
 > system(paste("diff -y -W60", file.a, file.b))
 0322537356476822586397504	0322537356476822586397504
 8878534781828287522820110	8878534781828287522820110
 9308949611478951141654247    |	9308949611488951141654247
 2378135323809170372086533	2378135323809170372086533
 1226852375608033488296246	1226852375608033488296246
 0429091924756856515266137    |	0429091924756856515266933
 1456351707945846825421760	1456351707945846825421760
 6518057783166680942903649    |	6558057783166680942903649
 0643163133167844418159180    |	1643163133167844418159180
 0163787813495542673221586	0163787813495542673221586

単純に同一かどうかだけを判定したいときはcmpコマンドを使う
 > system(paste("cmp", file.a, file.b))
 testdata1.dat testdata2.dat 異なります: バイト 64、行 3

*重複データを取り除く [#a4cc5347]

**全く同じ重複データを取り除く-- unique関数 [#z1c2a90c]
 > ( d <- data.frame(a=c(2, 2, 5, 4, 1, 2, 2),
 +                   b=c("f", "r", "o", "u", "p", "r", "z"),
 +                   c=c(2, 4, 3, 5, 2, 4, 4)) )
   a b c
 1 2 f 2
 2 2 r 4
 3 5 o 3
 4 4 u 5
 5 1 p 2
 6 2 r 4
 7 2 z 4
 > ( u <- unique(d) )
   a b c
 1 2 f 2
 2 2 r 4
 3 5 o 3
 4 4 u 5
 5 1 p 2
 7 2 z 4

**ある変数の値が同じ重複データを除く [#yba2d99f]
 unique2 <- function(d,    # データフレーム
                     ID)   # 基準となるデータのある列番号
 { # ID が同じデータは,最後のものが残る
   nrow <- nrow(d)
   ok <- rep(TRUE, nrow)
   for (i in 1 : (nrow-1)) {
     if (sum(d[(i+1) : nrow, ID] %in% d[i, ID])) {
       ok[i] <- FALSE
     }
   }
   d[ok,]
 }
実行例
 > ( d <- data.frame(ID=c(8, 9, 8, 9, 5, 2, 4, 6, 8, 10, 1, 2),
 +                   x=c(9, 1, 4, 5, 10, 3, 2, 12, 6, 11, 8, 7)) )
    ID  x
 1   8  9
 2   9  1
 3   8  4
 4   9  5
 5   5 10
 6   2  3
 7   4  2
 8   6 12
 9   8  6
 10 10 11
 11  1  8
 12  2  7
 > ( d2 <- unique2(d, 1) )
    ID  x
 4   9  5
 5   5 10
 7   4  2
 8   6 12
 9   8  6
 10 10 11
 11  1  8
 12  2  7

~
質問 重複データを見てから、個別に削除したりするのが、この場合によく行われると思うのですが、どうするといいのでしょう。~
**重複データを確認してから削除する [#z3bd165e]

質問 重複データを見てから個別に削除するということもよく行われると思うのですが、どうすればよいでしょうか。~

重複するデータを表示し,どれを削除するか確認する。
 unique3 <- function(d,    # データフレーム
                     ID)   # 基準となるデータのある列番号
 {
    tbl <- table(d[ID])
    tbl <- tbl[tbl > 1]
    suf <- as.integer(names(tbl))
    print(lapply(suf, function(s) d[d[,ID] == s,]))
 }
実行例
 > unique3(d, 1)
 [[1]]
    ID x
 6   2 3
 12  2 7
 
 [[2]]
   ID x
 1  8 9
 3  8 4
 9  8 6
 
 [[3]]
   ID x
 2  9 1
 4  9 5
左端に示されているのが行番号である。6, 1, 9, 2 行目を削除したいなら。
 d2 <- d[-c(6, 1, 9, 2), ]
などとすればよい。
 > ( d2 <- d[-c(6, 1, 9, 2),] )
    ID  x
 3   8  4
 4   9  5
 5   5 10
 7   4  2
 8   6 12
 10 10 11
 11  1  8
 12  2  7

*欠損値の補完(補間) [#ac3e0f8e]

[[zooパッケージを使って欠損値を補間する:http://d.hatena.ne.jp/teramonagi/20111201]]~
Hmiscパッケージのimpute, fit.mult.impute関数:

**時系列データの欠損値 [#d37b212d]

欠損値の前後のデータの平均値で補完する

 > x <- c(NA, 1, 2, 4, 3, NA, 5, 7, NA, 10, NA)
 > invisible(sapply(which(is.na(x)),
 +           function(p) if (p != 1 && p != length(x)) x[p] <<- mean(x[p+c(-1,1)])))
 > x
  [1]   NA  1.0  2.0  4.0  3.0  4.0  5.0  7.0  8.5 10.0   NA

**独立データの欠損値 [#y178dd0f]

***欠損値データを除く平均値で補完する [#fbf544e9]

 > x <- c(NA, 1, 2, 4, 3, NA, 5, 7, NA, 10, NA)
 > x[is.na(x)] <- mean(x, na.rm=TRUE)
 > x
  [1]  4.571429  1.000000  2.000000  4.000000  3.000000  4.571429  5.000000  7.000000  4.571429
 [10] 10.000000  4.571429

***特定の値で補完する [#tce061cd]

 > x <- c(NA, 1, 2, 4, 3, NA, 5, 7, NA, 10, NA)
 > x[is.na(x)] <- 0
 > x
  [1]  0  1  2  4  3  0  5  7  0 10  0

*複数のファイルに分割して保存されているデータを1つにする [#p7a9a70b]

**変数名の個数と順序が同じデータをまとめる -- rbind 関数 [#eb9208b3]

**変数名も個数も違うデータを共通コードに基づいてまとめる -- merge 関数 [#g889f495]

*外れ値の検索 [#h9b85c91]

**単変量の場合 [#zbb5e358]

平均値±k・標準偏差 の範囲以外にあるデータ値およびそのデータを持つのはどのデータかを返す関数。
 hazureti <- function(x, k=2) {
 	result <- NULL
 	result$caselist <- x >= mean(x)+k*sd(x) | x <= mean(x)-k*sd(x)
 	result$abnormal.values <- sort(x[result$caselist])
 	result
 }
使用例
 > hazureti(iris$Sepal.Width)
 $caselist
   [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE
  [17] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
  [33]  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
  [49] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE
  [65] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
  [81] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
  [97] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [113] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [129] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [145] FALSE FALSE FALSE FALSE FALSE FALSE
 
 $abnormal.values
 [1] 2.0 4.0 4.1 4.2 4.4

**多変量の場合(マハラノビスの汎距離) [#a4473cb4]

 Mahalanobis <- function(dat, threshold) {
     dat <- na.omit(dat)
     n <- nrow(dat)
     d2 <- apply(t(t(dat)-colMeans(dat)), 1,
         function(z) z %*% solve(var(dat)*(n-1)/n) %*% z)
     dat$P <- pchisq(d2, ncol(dat), lower.tail=FALSE)
     dat[dat$P < threshold, ]
 }
使用例
 > Mahalanobis(iris[1:50, 1:4], 0.05)
    Sepal.Length Sepal.Width Petal.Length Petal.Width          P
 15          5.8         4.0          1.2         0.2 0.03376522
 23          4.6         3.6          1.0         0.2 0.02369321
 25          4.8         3.4          1.9         0.2 0.04133150
 42          4.5         2.3          1.3         0.3 0.01352573
 44          5.0         3.5          1.6         0.6 0.01363081

*factor にまつわる話 [#r30a6a40]

**factor が期待する順序にならない [#vf6d1ca2]

質問:性別を表す変数で,データファイルに "male", "female" と書いてある。普通,male=1, female=2 になると思ったのに,male=2, female=1 になってしまい,理解できない。~
回答:facot(d$sex, levels=c("male", "female")) のようにするとよいでしょう。~
 > ( d <- data.frame(sex=c("male", "female", "male", "male", "female")) )
      sex
 1   male
 2 female
 3   male
 4   male
 5 female
 > as.integer(d$sex)
 [1] 2 1 2 2 1
 > d$sex <- factor(d$sex, levels=c("male", "female"))
 > d
      sex
 1   male
 2 female
 3   male
 4   male
 5 female
 > as.integer(d$sex)
 [1] 1 2 1 1 2

**数値データが factor になってしまった [#rc49ee3c]

こんなデータファイルを作ったとする。
         x   y
 1   42.47 Apr
 2  47.428 Aug
 3  52.969 Dec
 4  59.304 Jan
 5  57.534 Jun
 6  50.29l Mar
 7  65.535 May
 8  33.175 Nov
 9  45.198 Oct
 10 57.151 Sep
読み込んでみる。
 > d <- read.table("test.dat", header=TRUE)
平均値を取ろうとして,怒られる。
 > mean(d$x)
 [1] NA
  警告メッセージ: 
 In mean.default(d$x) :
    引数は数値でも論理値でもありません。NA 値を返します 
クラスを調べてみて,あらびっくり。数値データなのに,factor だといわれてしまった。
 > class(d$x)
 [1] "factor"
こういうとき,原因は「データの中に数を表す文字以外の文字が入っている」。1文字でも紛れ込んでいると全部が factor になる。当然,平均値なんか計算できないというわけ。~
たくさんあるデータのどこがイケナイのか,以下のようにして調べる。
 > z <- sapply(d$x, function(y) as.numeric(as.character(y)))
  警告メッセージ: 
 In FUN(X[[10L]], ...) :  強制変換により NA が生成されました 
 > which(is.na(z))
 [1] 6
 > d$x[6]
 [1] 50.29l
 10 Levels: 33.175 42.47 45.198 47.428 50.29l 52.969 ... 65.535
よく見てみよう。1 を l(小文字のエル) と入力してしまっている。1 と l は打ち間違えないとは思うが,0 と o は近くにあるし間違えやすいかも。

*1行あたりのデータの個数が異なる場合 [#q9b4981b]

**ある行のデータの個数がほかの行より少ないとき [#z718be2a]

以下のようなエラーメッセージが出る。
 > d <- read.table("test.dat", header=TRUE)
  以下にエラー scan(file, what, nmax, sep, dec, quote, skip, nlines, na.strings,  : 
    '2' 行目には,2 個の要素がありません 
そういうときには,fill=TRUE を指定して,読み込んでみよう。
 > d <- read.table("test.dat", header=TRUE, fill=TRUE)
データを表示してみると,いろいろな風にオカシイことがある。以下の例では,2行目のデータの区切りが「全角空白」なのが原因。
              x   y
 1        42.47 Apr
 2  47.428 Aug    
 3       52.969 Dec

**ある行のデータの個数がほかの行より多いとき [#lf2f9bc3]

以下のようなエラーメッセージが出る。
 > d <- read.table("test.dat", header=TRUE)
  以下にエラー scan(file, what, nmax, sep, dec, quote, skip, nlines, na.strings,  : 
    '1' 行目には,3 個の要素がありません 
上と同じように,fill=TRUE を指定して,読み込んでみよう。
 > d <- read.table("test.dat", header=TRUE, fill=TRUE)
表示してみたら,以下のようだった。本来の数値データが,rownames になってしまった。
          x    y
 42.47  Apr     
 47.428 Aug test
 52.969 Dec

**各行に何個のデータがあるかを見るには [#x0e003a5]

以下のようにすればよい。
 >  x <- readLines("test.dat")
 >  y <- sapply(x, function(y) length(unlist(strsplit(y, " "))))
 >  ( z <- unname(y) )
  [1] 2 2 3 2 2 2 2 2 2 2 2
個数の違うのが何行目なのかは以下のようにすれば分かる。
 >  which(z == 3)
 [1] 3

*データクリーニングの例 [#da34f259]

**ネット上にある既存データを R で使えるようにする例 [#d4276988]

[[信用残データ:http://hpcgi1.nifty.com/nk3news/d.cgi?down=homepage1.nifty.com/nk3news/20080503/s20080502.csv&name=s20080502.csv]]というのがある。~
csv ファイルのようなので,以下のようにしてダウンロードしてファイルとして保存してから,いざ解析のために読み込もうとしたときに,OS によってはエラーメッセージが出ることがある。
 > d <- read.csv("s20080502.csv")
  以下にエラー make.names(col.names, unique = TRUE) : 
    <8b>&#599;mに不正なマルチバイト文字があります 
つまり,このファイルのエンコーディングが合わないのだ。~
このファイルは WIndows で作られたようで,fileEncoding="cp932" を指定しないと Mac では読めない。読み込むためには,以下のようにする。ヘッダーがあると思ったけど,ないので,header=FALSE とする。
 d <- read.csv("s20080502.csv", header=FALSE, fileEncoding="cp932")
うむ。なんとか読み込めたようだ。~
以後の扱いに不便なので,変数(列)に名前を付けてやろう。
 colnames(d) <- c("名称", "売残", "買残", "日付", "市場", "コード")
先頭のデータを見てみる。
 > head(d)
         名称    売残   買残       日付 市場 コード
 1       極洋     499   1506 2008/05/02    1   1301
 2       日水  2950.3 1086.8 2008/05/02    1   1332
 3 マルニチH    4062   5067 2008/05/02    1   1334
 4 サカタタネ   323.4   72.2 2008/05/02    1   1377
 5     ホクト   195.9   26.8 2008/05/02    1   1379
 6     住友炭 17481.5  37852 2008/05/02    1   1503
一番最初にすることは,サンプルサイズがいくつかを確認すること。
 > nrow(d)
 [1] 2272
2272件のデータが入っている。~
名称とコードによってデータ識別ができるようだが,重複データがあるかどうか調べておく。
 > length(table(d$名称))
 [1] 2272
 > length(table(d$コード))
 [1] 2272
となり,行数と等しいので重複データはないようだ。~
次に,どんなデータが入っているのか,まずは,summary 関数で確認する。
 > summary(d)
          名称           売残           買残              日付           市場           コード    
  300投信:   1   --     : 530   --     :  20   2008/05/02:2272   Min.   :1.000   Min.   :1301  
  7&iHD:   1   3      :  11   2      :  16                     1st Qu.:1.000   1st Qu.:4280  
  7シーズH:   1   16     :   8   1      :  15                     Median :1.000   Median :6677  
  A&AM  :   1   2      :   8   8      :  12                     Mean   :1.208   Mean   :6222  
  A&D    :   1   5      :   8   11     :  10                     3rd Qu.:1.000   3rd Qu.:8238  
  ABCマト:   1   9      :   8   3      :  10                     Max.   :2.000   Max.   :9997  
  (Other)   :2266   (Other):1699   (Other):2189                                                   
むむ,前の方にも書いたけど,残高とか買残は数値データのはずだけど,"--" というデータが入力されているのが分かる。これが,欠損値なんだなあ。これがあるから,売残,買残は数値データではなく factor になってしまっている。だから,平均値なんかがとれなくなっている。
 > mean(d$売残)
 [1] NA
  警告メッセージ: 
 In mean.default(d$売残) :
    引数は数値でも論理値でもありません。NA 値を返します 
"--" を NA に置き換えると同時に,元々数値だったものを数値に戻さないといけない。以下のような,簡便法では,警告メッセージがでるが,無視して良い(数値にできないものが NA になるということだから)。
 > head( d$売残 <- as.numeric(as.character(d$売残)), 50)
  [1]   499.000  2950.300  4062.000   323.400   195.900 17481.500    74.000  6846.000     4.312
 [10]   286.000   225.500    30.000     0.740   105.700  2010.540   444.000  1178.500    88.500
 [19]   191.400    19.500    17.400  3088.000  3480.000  1981.000 12676.000 13932.000    13.000 
 [28] 10367.000  4305.400   207.000   299.000    70.000   253.000  1610.000  1369.800    47.000
 [37]  1097.000   166.000    20.500  2181.000        NA    35.000   872.000    34.000   204.000
 [46]   285.100  2473.000  1044.000    27.500   644.000
  警告メッセージ: 
 In head(d$売残 <- as.numeric(as.character(d$売残)), 50) :
    強制変換により NA が生成されました 
 > d$買残 <- as.numeric(as.character(d$買残))
気持ちが悪いという場合には,na.string="--" を指定してもう一度読み直すとよい(ラベル付けなども再度)。
 > d <- read.csv("s20080502.csv", header=FALSE, fileEncoding="cp932", na.string="--")
 > colnames(d) <- c("名称", "売残", "買残", "日付", "市場", "コード")
これで,売残,買残の統計処理ができるようになった。na.rm=TRUE を忘れないように。
 > mean(d$売残, na.rm=TRUE)
 [1] 793.7595
 > mean(d$買残, na.rm=TRUE)
 [1] 1092.553
日付は "2008/05/02" 一種だけのようだ。
市場は 1, 2 の二種のようだ。
 > table(d$市場)
    1    2 
 1799  473 
市場により,売残の平均値に差があるかどうか(意味がないかも知れないが)検定することもできる。
 > t.test(d$売残~d$市場)
 
 	Welch Two Sample t-test
 
 data:  d$売残 by d$市場 
 t = 4.4822, df = 145.155, p-value = 1.488e-05
 alternative hypothesis: true difference in means is not equal to 0 
 95 percent confidence interval:
  362.5556 934.4865 
 sample estimates:
 mean in group 1 mean in group 2 
        830.6157        182.0947

*大規模データは R は不得手では? [#v6c47028]

まず,あなたの使っているマシンで,以下のようなテストプログラムを走らせてみよう。
 n <- 10000
 p <- 500
 gc(); gc()
 system.time(m <- round(matrix(rnorm(n*p), n, p)*10+50))
 system.time(d <- as.data.frame(m))
 system.time(write.csv(d, "datacleaning.csv", quote=FALSE, row.names=FALSE))
 system.time(csv <- read.csv("datacleaning.csv"))
実行例
 >  n <- 10000
 >  p <- 500
 >  gc(); gc()
   略
 >  system.time(m <- round(matrix(rnorm(n*p), n, p)*10+50))
    ユーザ   システム    経過  
      a        e           i # n×p 行列の作成にかかる秒数
 >  system.time(d <- as.data.frame(m))
    ユーザ   システム    経過  
      b        f           j # データフレームに変換する秒数
 >  system.time(write.csv(d, "datacleaning.csv", quote=FALSE, row.names=FALSE))
    ユーザ   システム    経過  
      c        g           k # ファイルに書き出す秒数
 >  system.time(csv <- read.csv("datacleaning.csv"))
    ユーザ   システム    経過  
      d        h           l # ファイルから読み出す秒数
実際にあなたが扱うデータについて,「x=行数*列数/5e6」を計算する。上で得られた秒数 a 〜 l に x を掛ければ,それぞれに必要なおよその秒数がわかる。

例えば,x = 行数*列数/5e6 = 100000*1000/5e6 = 20 であるとする。d = 2.776 であるなら,実際には約 20*2.776 = 55.52 秒かかる(実際やってみると 58 秒かかった)。

ただし,私の環境では x > 60 位になると「ユーザ」時間はだいたいそれくらいですむが,「経過」時間は予測より遙かに長くなるので注意。私の環境では,x=30のときの予測「ユーザ」時間は167程度で実測が174秒であるが,「経過」時間の予測は169であるが,実際には倍以上の378秒であった)。

いきなり,大規模なデータを扱うのはチョットマッタ。

まず,みなさんご自分の環境で,どの程度のデータ量ならばどれくらいの時間が必要かを把握しておく方がよいだろう。

入出力というのは,数値計算などに比べると数桁違いの時間が必要なのだから。

----
&counter;

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS