次のダーティデータ(仮想確率データ)に 含まれる異常値を可視化しながら見つける。

1 ダーティデータ

1.1 データの作成(参考)

set.seed(1) # 乱数シード
n <- 100000 # データサイズ

# 正常値
rv <- runif(n = n, min = 0, max = 1) # 一様乱数

# 異常値1(負の値)
size <- 3   # ランダムサンプルサイズ
ii <- sample(n, size) # インデックスランダムサンプル
rv[ii] <- runif(n = size, min = -1, max = 0)

# 異常値2(とても大きな/小さな値)
rv[39] <- 22
rv[52] <- -21
rv[91] <- 11

# 小数点第2位に丸め行列(列数:100)に変換
m <- matrix(round(rv, 2), ncol = 100)

write.csv(as.data.frame(m), 
       file = 'data_cleansing2_dirty_data.csv',
       row.names = F, quote = F) 

1.2 データの読み込み

# CSVデータを行列オブジェクトに変換
d <- read.csv(file = 'https://stats.dip.jp/01_ds/data/data_cleansing2_dirty_data.csv')

# Rのboxplot関数は行列(matrix)を引数とするのでデータフレームを行列に変換する。
m <- as.matrix(d) 

1.3 箱ひげ図で全体の確認

boxplot(m)

any(m < 0)            # 負のデータが存在
## [1] TRUE
any(abs(m) > 3*sd(m)) # 3シグマ(標準偏差の3倍)を超えるデータが存在
## [1] TRUE

1.4 カラム(列)範囲を絞る

jj <- 36:46
boxplot(m[, jj])

# 異常値が入っているカラム(列)の棒グラフを作成 
j <- 37
y <- m[, j]

barplot(height    = y,         # 棒グラフの高さ
        names.arg = 1:nrow(m)) # 横軸名

1.5 レコード(行)の範囲を絞り特定する。

ii <- 140:231
y <- m[ii, j]

barplot(height    = y,                        # 棒グラフの高さ
        cex.names = 0.4,                      # 横軸ラベルの大きさ
        names.arg = paste(ii, '\n(', y, ')')) # 横軸名 \nで改行して値も()内に表示

# さらにレコード(行)の範囲を絞り特定する。
ii <- 194:206
y <- m[ii, j]

barplot(height    = y,                        # 棒グラフの高さ
        cex.names = 0.4,                      # 横軸ラベルの大きさ
        names.arg = paste(ii, '\n(', y, ')')) # 横軸名 \nで改行して値も表示

# 異常値を特定
m[200, j]
##   V37 
## -0.78

2 可視化しないで直接的に求める場合

# 負の値
m[m < 0]
## [1] -21.00  -0.78  -0.99  -0.68
# 3シグマ(標準偏差の3倍)を超える値
sigma <- sd(m) # 標準偏差

#m[abs(m) > 3*sigma] # 数が多いためコメントアウトした。

# 4シグマ(標準偏差の4倍)を超える値
m[abs(m) > 4*sigma]
## [1]  22 -21  11
# 行と列のインデックス(Row, Col)と値(Value)のデータを作成
m.a <- NULL # 結果格納用の空のオブジェクトを作成

for (j in 1:ncol(m))
{
  for (i in 1:nrow(m))
  { # 負値または4シグマを超える異常値を検出しレコードを追加していく。
    if ( m[i, j] < 0 | m[i, j] > 4 * sigma )
    {
      cat('Row:', i, ', Col:', j, ', Value: ', m[i, j], fill = T) 
      m.a <- rbind(m.a, t(c(i, j, m[i, j]))) # rbind:行ベクトルを追加
    }
  }
}
## Row: 39 , Col: 1 , Value:  22
## Row: 52 , Col: 1 , Value:  -21
## Row: 91 , Col: 1 , Value:  11
## Row: 200 , Col: 37 , Value:  -0.78
## Row: 521 , Col: 59 , Value:  -0.99
## Row: 242 , Col: 100 , Value:  -0.68
# 結果表示
colnames(m.a) <- c('Row', 'Col', 'Value')
m.a
##      Row Col  Value
## [1,]  39   1  22.00
## [2,]  52   1 -21.00
## [3,]  91   1  11.00
## [4,] 200  37  -0.78
## [5,] 521  59  -0.99
## [6,] 242 100  -0.68

3 演習課題

次のダーティデータ(仮想確率データ)から, 可視化する方法とそうでない方法で異常値を発見せよ。

4 ダーティデータ

d <- read.csv(file = 'https://stats.dip.jp/01_ds/data/data_cleansing2_dirty_data_exercise.csv')

library(DT)
## Warning: パッケージ 'DT' はバージョン 4.3.3 の R の下で造られました
datatable(d)