我希望消除高于或低于2个标准差的异常值,对于许多具有相似名称的变量(代码中单独指定的变量太多)。
library(data.table)
irisdt <- data.table(iris)
myCols <- grep("Sepal", colnames(irisdt), value=TRUE)
# This works if I specify one column,
# but I have too many columns to specify, so need to use grep approach.
irisdt[, Sepal.Length.Outlier := (scale(Sepal.Length) < -2 | scale(Sepal.Length) > 2)]
# This does not work
irisdt[, (myCols) := lapply(myCols, function(x) {(scale(x) < -2 | scale(x) > 2)} )]
# This partially works, but changes in place
irisdt[, (myCols) := lapply(myCols, function(x) {(scale(irisdt[[x]]) < -2 | scale(irisdt[[x]]) > 2)} )]
# How do I make new variables, for example "Sepal.Length.Outlier"?
myOutlierCols <- grep(".Outlier", colnames(irisdt), value=TRUE)
# How do I select rows matching multiple columns (&)?
irisdt[myOutlierCols=="FALSE"] # does not work
irisdt[, hasOutlier := lapply(myCols, myCols==TRUE)] # does not work
irisdt[hasOutlier=="FALSE"] # relies on line above, which doesn't work
也许一个函数可以采用data.table列并将其除去高于或低于z得分截止值的值。这可以和lapply一起使用。
# This does not work
removeOutliers <- function(myColumn, cutoff = 3) {
lapply(myColumn, function (x) {
if (scale(myColumn[[x]]) < -cutoff | scale(myColumn[[x]]) > cutoff) {
x <- NA #specify individual value instead of column?
}
})
}
removeOutliers(irisdt[,Sepal.Length]) # for testing
trimmedIrisdt <- irisdt[,lapply(.SD, removeOutliers(.SD)), .SDcols = myCols] # could do by = grouping variable
# Once outliers are made NA, this would work:
trimmedIrisdt <- complete.cases(trimmedIrisdt)
答案 0 :(得分:2)
我想这实现了目标:
irisdt[, keep :=
as.logical(do.call(pmin, lapply(.SD, function(x) abs(scale(x)) <= 2)))
, .SDcols = myCols]
res = irisdt[(keep), !"keep"]
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1: 5.1 3.5 1.4 0.2 setosa
2: 4.9 3.0 1.4 0.2 setosa
3: 4.7 3.2 1.3 0.2 setosa
4: 4.6 3.1 1.5 0.2 setosa
5: 5.0 3.6 1.4 0.2 setosa
---
135: 6.7 3.0 5.2 2.3 virginica
136: 6.3 2.5 5.0 1.9 virginica
137: 6.5 3.0 5.2 2.0 virginica
138: 6.2 3.4 5.4 2.3 virginica
139: 5.9 3.0 5.1 1.8 virginica
如果存在分组变量,这也应该可以正常工作。我不知道它的统计稳健性。
工作原理:
abs(scale(x)) <= 2
。 要了解它是如何逐个细胞工作的......
library(data.table)
mynewCols = paste0(myCols,"_outly")
irisdt[, (mynewCols) :=
lapply(.SD, function(x) replace(x, abs(scale(x)) <= 2, NA))
, .SDcols = myCols]
然后浏览View(irisdt[rowSums(!is.na(irisdt[, ..mynewCols])) > 0])
。