Rでデータクリーニング
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
検索
|
最終更新
|
ヘルプ
]
開始行:
[[Rでデータクリーニング]]
まとまったページがない?じゃあ,作ろうじゃないですか。協...
こんなデータで,こんなデータクリーニングしたいなあという...
----
#contents
----
*データクリーニングとは [#q180a6cf]
データ入力が終わったら,次にやることはデータクリーニング...
データクリーニングとは,データのいろいろな誤りを修正する...
**一般的な手順 [#c407b240]
いろいろな入力ミスを検出し,その入力ミスのあるデータがど...
たとえば,性別を 1(男),2(女) で入力しているのに,NA...
> d <- data.frame(ID=1:10, sex=c(1, 2, NA, 1.2, 9, "male...
> 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]
変数ごとに欠損値の有無,実際に記録されているデータ値の種...
**クロス集計によるデータチェック [#n8cc808c]
身長が 108 センチの人のデータを 196 センチと誤入力したよ...
*2つのファイルの内容を比較する [#m9b24afb]
**ダブルチェック [#q264eea3]
同じデータを2つのファイルに2度入力し,内容を比較すること...
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,...
}
max.length <- max(nchar(c(a, b)))
ruler1 <- paste(sprintf("%10i", 1:(max.length%/%10+1...
ruler2 <- paste(rep("1234567890", (max.length%/%10+1...
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.char...
character.d <- ifelse(character.a[1:min.c] =...
character.d <- c(character.d, rep("v", max.l...
string.d <- paste(character.d, collapse="") ...
cat(sprintf(" %s\n %s\n %s\n%...
ruler1, ruler2, string.d, i, string.a, s...
}
}
}
使用例
> 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, ...
+ x=c(9, 1, 4, 5, 10, 3, 2, 12, 6, 11,...
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.n...
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[...
> x
[1] NA 1.0 2.0 4.0 3.0 4.0 5.0 7.0 8.5 10.0 ...
**独立データの欠損値 [#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 ...
[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つにする ...
**変数名の個数と順序が同じデータをまとめる -- rbind 関数 ...
**変数名も個数も違うデータを共通コードに基づいてまとめる ...
*外れ値の検索 [#h9b85c91]
**単変量の場合 [#zbb5e358]
平均値±k・標準偏差 の範囲以外にあるデータ値およびそのデー...
hazureti <- function(x, k=2) {
result <- NULL
result$caselist <- x >= mean(x)+k*sd(x) | x <= mean(x)-...
result$abnormal.values <- sort(x[result$caselist])
result
}
使用例
> hazureti(iris$Sepal.Width)
$caselist
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FA...
[17] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FA...
[33] TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FA...
[49] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FA...
[65] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FA...
[81] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FA...
[97] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FA...
[113] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FA...
[129] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FA...
[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 ...
15 5.8 4.0 1.2 0.2 0.0...
23 4.6 3.6 1.0 0.2 0.0...
25 4.8 3.4 1.9 0.2 0.0...
42 4.5 2.3 1.3 0.3 0.0...
44 5.0 3.5 1.6 0.6 0.0...
*factor にまつわる話 [#r30a6a40]
**factor が期待する順序にならない [#vf6d1ca2]
質問:性別を表す変数で,データファイルに "male", "female"...
回答:facot(d$sex, levels=c("male", "female")) のようにす...
> ( d <- data.frame(sex=c("male", "female", "male", "mal...
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 値を返します
クラスを調べてみて,あらびっくり。数値データなのに,facto...
> class(d$x)
[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 ... ...
よく見てみよう。1 を l(小文字のエル) と入力してしまって...
*1行あたりのデータの個数が異なる場合 [#q9b4981b]
**ある行のデータの個数がほかの行より少ないとき [#z718be2a]
以下のようなエラーメッセージが出る。
> d <- read.table("test.dat", header=TRUE)
以下にエラー scan(file, what, nmax, sep, dec, quote, sk...
'2' 行目には,2 個の要素がありません
そういうときには,fill=TRUE を指定して,読み込んでみよう。
> d <- read.table("test.dat", header=TRUE, fill=TRUE)
データを表示してみると,いろいろな風にオカシイことがある...
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, sk...
'1' 行目には,3 個の要素がありません
上と同じように,fill=TRUE を指定して,読み込んでみよう。
> d <- read.table("test.dat", header=TRUE, fill=TRUE)
表示してみたら,以下のようだった。本来の数値データが,row...
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 で使えるようにする例 [#d42...
[[信用残データ:http://hpcgi1.nifty.com/nk3news/d.cgi?down...
csv ファイルのようなので,以下のようにしてダウンロードし...
> d <- read.csv("s20080502.csv")
以下にエラー make.names(col.names, unique = TRUE) :
<8b>ɗmに不正なマルチバイト文字があります
つまり,このファイルのエンコーディングが合わないのだ。~
このファイルは WIndows で作られたようで,fileEncoding="cp...
d <- read.csv("s20080502.csv", header=FALSE, fileEncodin...
うむ。なんとか読み込めたようだ。~
以後の扱いに不便なので,変数(列)に名前を付けてやろう。
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...
7&iHD: 1 3 : 11 2 : 16 ...
7シーズH: 1 16 : 8 1 : 15 ...
A&AM : 1 2 : 8 8 : 12 ...
A&D : 1 5 : 8 11 : 10 ...
ABCマト: 1 9 : 8 3 : 10 ...
(Other) :2266 (Other):1699 (Other):2189 ...
むむ,前の方にも書いたけど,残高とか買残は数値データのは...
> mean(d$売残)
[1] NA
警告メッセージ:
In mean.default(d$売残) :
引数は数値でも論理値でもありません。NA 値を返します
"--" を NA に置き換えると同時に,元々数値だったものを数値...
> head( d$売残 <- as.numeric(as.character(d$売残)), 50)
[1] 499.000 2950.300 4062.000 323.400 195.900 1...
[10] 286.000 225.500 30.000 0.740 105.700 ...
[19] 191.400 19.500 17.400 3088.000 3480.000 ...
[28] 10367.000 4305.400 207.000 299.000 70.000 ...
[37] 1097.000 166.000 20.500 2181.000 NA ...
[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, fileEncod...
> colnames(d) <- c("名称", "売残", "買残", "日付", "市場...
これで,売残,買残の統計処理ができるようになった。na.rm=T...
> 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 ...
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...
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=FA...
ユーザ システム 経過
c g k # ファイルに書き出す秒数
> system.time(csv <- read.csv("datacleaning.csv"))
ユーザ システム 経過
d h l # ファイルから読み出す秒数
実際にあなたが扱うデータについて,「x=行数*列数/5e6」を計...
例えば,x = 行数*列数/5e6 = 100000*1000/5e6 = 20 であると...
ただし,私の環境では x > 60 位になると「ユーザ」時間はだ...
いきなり,大規模なデータを扱うのはチョットマッタ。
まず,みなさんご自分の環境で,どの程度のデータ量ならばど...
入出力というのは,数値計算などに比べると数桁違いの時間が...
----
&counter;
終了行:
[[Rでデータクリーニング]]
まとまったページがない?じゃあ,作ろうじゃないですか。協...
こんなデータで,こんなデータクリーニングしたいなあという...
----
#contents
----
*データクリーニングとは [#q180a6cf]
データ入力が終わったら,次にやることはデータクリーニング...
データクリーニングとは,データのいろいろな誤りを修正する...
**一般的な手順 [#c407b240]
いろいろな入力ミスを検出し,その入力ミスのあるデータがど...
たとえば,性別を 1(男),2(女) で入力しているのに,NA...
> d <- data.frame(ID=1:10, sex=c(1, 2, NA, 1.2, 9, "male...
> 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]
変数ごとに欠損値の有無,実際に記録されているデータ値の種...
**クロス集計によるデータチェック [#n8cc808c]
身長が 108 センチの人のデータを 196 センチと誤入力したよ...
*2つのファイルの内容を比較する [#m9b24afb]
**ダブルチェック [#q264eea3]
同じデータを2つのファイルに2度入力し,内容を比較すること...
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,...
}
max.length <- max(nchar(c(a, b)))
ruler1 <- paste(sprintf("%10i", 1:(max.length%/%10+1...
ruler2 <- paste(rep("1234567890", (max.length%/%10+1...
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.char...
character.d <- ifelse(character.a[1:min.c] =...
character.d <- c(character.d, rep("v", max.l...
string.d <- paste(character.d, collapse="") ...
cat(sprintf(" %s\n %s\n %s\n%...
ruler1, ruler2, string.d, i, string.a, s...
}
}
}
使用例
> 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, ...
+ x=c(9, 1, 4, 5, 10, 3, 2, 12, 6, 11,...
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.n...
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[...
> x
[1] NA 1.0 2.0 4.0 3.0 4.0 5.0 7.0 8.5 10.0 ...
**独立データの欠損値 [#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 ...
[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つにする ...
**変数名の個数と順序が同じデータをまとめる -- rbind 関数 ...
**変数名も個数も違うデータを共通コードに基づいてまとめる ...
*外れ値の検索 [#h9b85c91]
**単変量の場合 [#zbb5e358]
平均値±k・標準偏差 の範囲以外にあるデータ値およびそのデー...
hazureti <- function(x, k=2) {
result <- NULL
result$caselist <- x >= mean(x)+k*sd(x) | x <= mean(x)-...
result$abnormal.values <- sort(x[result$caselist])
result
}
使用例
> hazureti(iris$Sepal.Width)
$caselist
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FA...
[17] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FA...
[33] TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FA...
[49] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FA...
[65] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FA...
[81] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FA...
[97] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FA...
[113] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FA...
[129] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FA...
[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 ...
15 5.8 4.0 1.2 0.2 0.0...
23 4.6 3.6 1.0 0.2 0.0...
25 4.8 3.4 1.9 0.2 0.0...
42 4.5 2.3 1.3 0.3 0.0...
44 5.0 3.5 1.6 0.6 0.0...
*factor にまつわる話 [#r30a6a40]
**factor が期待する順序にならない [#vf6d1ca2]
質問:性別を表す変数で,データファイルに "male", "female"...
回答:facot(d$sex, levels=c("male", "female")) のようにす...
> ( d <- data.frame(sex=c("male", "female", "male", "mal...
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 値を返します
クラスを調べてみて,あらびっくり。数値データなのに,facto...
> class(d$x)
[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 ... ...
よく見てみよう。1 を l(小文字のエル) と入力してしまって...
*1行あたりのデータの個数が異なる場合 [#q9b4981b]
**ある行のデータの個数がほかの行より少ないとき [#z718be2a]
以下のようなエラーメッセージが出る。
> d <- read.table("test.dat", header=TRUE)
以下にエラー scan(file, what, nmax, sep, dec, quote, sk...
'2' 行目には,2 個の要素がありません
そういうときには,fill=TRUE を指定して,読み込んでみよう。
> d <- read.table("test.dat", header=TRUE, fill=TRUE)
データを表示してみると,いろいろな風にオカシイことがある...
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, sk...
'1' 行目には,3 個の要素がありません
上と同じように,fill=TRUE を指定して,読み込んでみよう。
> d <- read.table("test.dat", header=TRUE, fill=TRUE)
表示してみたら,以下のようだった。本来の数値データが,row...
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 で使えるようにする例 [#d42...
[[信用残データ:http://hpcgi1.nifty.com/nk3news/d.cgi?down...
csv ファイルのようなので,以下のようにしてダウンロードし...
> d <- read.csv("s20080502.csv")
以下にエラー make.names(col.names, unique = TRUE) :
<8b>ɗmに不正なマルチバイト文字があります
つまり,このファイルのエンコーディングが合わないのだ。~
このファイルは WIndows で作られたようで,fileEncoding="cp...
d <- read.csv("s20080502.csv", header=FALSE, fileEncodin...
うむ。なんとか読み込めたようだ。~
以後の扱いに不便なので,変数(列)に名前を付けてやろう。
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...
7&iHD: 1 3 : 11 2 : 16 ...
7シーズH: 1 16 : 8 1 : 15 ...
A&AM : 1 2 : 8 8 : 12 ...
A&D : 1 5 : 8 11 : 10 ...
ABCマト: 1 9 : 8 3 : 10 ...
(Other) :2266 (Other):1699 (Other):2189 ...
むむ,前の方にも書いたけど,残高とか買残は数値データのは...
> mean(d$売残)
[1] NA
警告メッセージ:
In mean.default(d$売残) :
引数は数値でも論理値でもありません。NA 値を返します
"--" を NA に置き換えると同時に,元々数値だったものを数値...
> head( d$売残 <- as.numeric(as.character(d$売残)), 50)
[1] 499.000 2950.300 4062.000 323.400 195.900 1...
[10] 286.000 225.500 30.000 0.740 105.700 ...
[19] 191.400 19.500 17.400 3088.000 3480.000 ...
[28] 10367.000 4305.400 207.000 299.000 70.000 ...
[37] 1097.000 166.000 20.500 2181.000 NA ...
[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, fileEncod...
> colnames(d) <- c("名称", "売残", "買残", "日付", "市場...
これで,売残,買残の統計処理ができるようになった。na.rm=T...
> 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 ...
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...
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=FA...
ユーザ システム 経過
c g k # ファイルに書き出す秒数
> system.time(csv <- read.csv("datacleaning.csv"))
ユーザ システム 経過
d h l # ファイルから読み出す秒数
実際にあなたが扱うデータについて,「x=行数*列数/5e6」を計...
例えば,x = 行数*列数/5e6 = 100000*1000/5e6 = 20 であると...
ただし,私の環境では x > 60 位になると「ユーザ」時間はだ...
いきなり,大規模なデータを扱うのはチョットマッタ。
まず,みなさんご自分の環境で,どの程度のデータ量ならばど...
入出力というのは,数値計算などに比べると数桁違いの時間が...
----
&counter;
ページ名: