我编写了一个函数,它根据name列的值来获取数据的子集。它计算列的异常值" mark"并取代所有异常值。 但是,当我尝试组合这些不同的子集时,我的元素的顺序会发生变化。有什么方法可以维持我的元素在列中的顺序"标记"
我的数据集是:
name mark
A 100.0
B 0.5
C 100.0
A 50.0
B 90.0
B 1000.0
C 1200.0
C 5000.0
A 210.0
我写的功能是:
data.frame(do.call("rbind", as.list(by(data, data$name,
function(x){apply(x[, .(mark)],2,
function(y) {y[y > (quantile(x$mark, na.rm=TRUE)[[3]][[1]] + 1.5 * IQR(x$mark))]
<- (quantile(x$mark, na.rm=TRUE)[[3]][[1]] + 1.5 * IQR(x$mark));y})}))))
上述功能的结果是下面的第一列(为了说明目的,我手动添加了name
):
mark NAME
100.000 ----- A
50.000 ----- A
210.000 ----- A
0.500 ----- B
90.000 ----- B
839.625 ----- B
100.000 ----- C
1200.000 ----- C
4875.000 ----- C
在上面的结果中,标记列的值的顺序被改变。有什么方法可以维持元素的顺序吗?
答案 0 :(得分:1)
您确定代码正在按照您的想法行事吗?
看起来你正在用中位数+ 1.5 * IQR替换大于中位数(第三个返回值quantile
)的任何值。也许这就是你想要的,我不知道。更大的问题是您在apply
函数中执行此操作,因此它将重新计算每次迭代的中位数和IQR,并使用之前已更改的行进行更新。我打赌这不是你想要的,但我想我已经看到了陌生人。
更好的选择可能是创建一个外部函数来完成工作,它接收所有数据,进行计算,然后输出所有数据。我之所以喜欢dplyr
,只是因为它很干净。
读取您的数据(为什么&#34; ----&#34;?)
scores <- read.table(text="
name mark
A 100.0
B 0.5
C 100.0
A 50.0
B 90.0
B 1000.0
C 1200.0
C 5000.0
A 210.0", header=TRUE)
并创建一个更有意义的功能;替换任何大于75%分位数的值(由名称引用,因此您知道它是什么)或小于具有该限制值的25%分位数
scale_outliers <- function(data) {
lim <- quantile(data, na.rm = TRUE)
data[data > lim["75%"]] <- lim["75%"]
data[data < lim["25%"]] <- lim["25%"]
return(data)
}
将此处理链接到dplyr::mutate
很简洁,然后可以传递给ggplot
。这是原始数据
gg1 <- scores %>% ggplot(aes(x=name, y=mark))
gg1 <- gg1 + geom_point() + geom_boxplot() + coord_cartesian(ylim=range(scores$mark))
gg1
如果我们使用新函数对其进行更改,我们将返回数据,而不会在
周围更改行scores %>% mutate(new_mark = scale_outliers(mark))
#> name mark new_mark
#> 1 A 100.0 100
#> 2 B 0.5 90
#> 3 C 100.0 100
#> 4 A 50.0 90
#> 5 B 90.0 90
#> 6 B 1000.0 1000
#> 7 C 1200.0 1000
#> 8 C 5000.0 1000
#> 9 A 210.0 210
我们可以绘制,
gg2 <- scores %>% mutate(new_mark = scale_outliers(mark)) %>% ggplot(aes(x=name, y=new_mark))
gg2 <- gg2 + geom_point() + geom_boxplot() + coord_cartesian(ylim=range(scores$mark))
gg2
最重要的是,如果你现在想要按分组进行分位数比较(比如name
列,那就像使用dplyr::group_by(name)
一样简单,
gg3 <- scores %>% group_by(name) %>% mutate(new_mark = scale_outliers(mark)) %>% ggplot(aes(x=name, y=new_mark))
gg3 <- gg3 + geom_point() + geom_boxplot() + coord_cartesian(ylim=range(scores$mark))
gg3
答案 1 :(得分:0)
Hack-R答案的略微重构版本 - 您可以为data.table
添加索引:
data <- data.table(name = c("A", "B","C", "A","B","B","C","C","A"),mark = c(100,0.5,100,50,90,1000,1200,5000,210))
data[,i:=.I]
然后执行计算,但保留name
和i
:
df <- data.frame(do.call("rbind", as.list(
by(data, data$name,
function(x) cbind(i=x$i,
name=x$name,
apply(x[, .(mark)], 2,function(y) {y[y > (quantile(x$mark, na.rm=TRUE)[[3]][[1]] + 1.5 * IQR(x$mark))] <- (quantile(x$mark, na.rm=TRUE)[[3]][[1]] + 1.5 * IQR(x$mark));y})
)))))
最后你使用索引订购:
df[order(df$i),]
i name mark
1 1 A 100
4 2 B 0.5
7 3 C 100
2 4 A 50
5 5 B 90
6 6 B 839.625
8 7 C 1200
9 8 C 4875
3 9 A 210