我需要将连续变量拆分/分成3个相等大小的组。
示例数据框
das <- data.frame(anim=1:15,
wt=c(181,179,180.5,201,201.5,245,246.4,
189.3,301,354,369,205,199,394,231.3))
在被切断之后(根据wt
的值),我需要在新变量wt2
下设置3个类:
> das
anim wt wt2
1 1 181.0 1
2 2 179.0 1
3 3 180.5 1
4 4 201.0 2
5 5 201.5 2
6 6 245.0 2
7 7 246.4 3
8 8 189.3 1
9 9 301.0 3
10 10 354.0 3
11 11 369.0 3
12 12 205.0 2
13 13 199.0 1
14 14 394.0 3
15 15 231.3 2
这适用于大型数据集
答案 0 :(得分:56)
试试这个:
split(das, cut(das$anim, 3))
如果您想根据wt
的值进行拆分,那么
library(Hmisc) # cut2
split(das, cut2(das$wt, g=3))
无论如何,您可以通过合并cut
,cut2
和split
来实现这一目标。
<强>已更新强>
如果您想将组索引作为附加列,那么
das$group <- cut(das$anim, 3)
如果列应该像1,2,...那样索引,那么
das$group <- as.numeric(cut(das$anim, 3))
再次更新
试试这个:
> das$wt2 <- as.numeric(cut2(das$wt, g=3))
> das
anim wt wt2
1 1 181.0 1
2 2 179.0 1
3 3 180.5 1
4 4 201.0 2
5 5 201.5 2
6 6 245.0 2
7 7 246.4 3
8 8 189.3 1
9 9 301.0 3
10 10 354.0 3
11 11 369.0 3
12 12 205.0 2
13 13 199.0 1
14 14 394.0 3
15 15 231.3 2
答案 1 :(得分:31)
或者查看cut_number
包中的ggplot2
,例如
das$wt_2 <- as.numeric(cut_number(das$wt,3))
请注意cut(...,3)
将原始数据的范围划分为三个相等长度的范围;如果数据分布不均匀,则不一定会为每个组生成相同数量的观察(您可以通过适当地使用cut_number
来复制quantile
所做的事情,但它是一个很方便的功能)。另一方面,使用Hmisc::cut2()
参数的g=
按分位数进行分割,因此或多或少等同于ggplot2::cut_number
。到目前为止,我可能认为像cut_number
这样的内容会进入dplyr
,但as far as I can tell it hasn't。
答案 2 :(得分:3)
替代不使用使用cut2。
das$wt2 <- as.factor( as.numeric( cut(das$wt,3)))
或
das$wt2 <- as.factor( cut(das$wt,3, labels=F))
答案 3 :(得分:3)
ntile
的 dplyr
现在可以做到这一点,但与NA
的行为很奇怪。
我在以下函数中使用了类似的代码,该代码在基本R中有效,并且与上面的cut2
解决方案相同:
ntile_ <- function(x, n) {
b <- x[!is.na(x)]
q <- floor((n * (rank(b, ties.method = "first") - 1)/length(b)) + 1)
d <- rep(NA, length(x))
d[!is.na(x)] <- q
return(d)
}
答案 4 :(得分:3)
这是使用mltools包中的bin_data()
函数的另一种解决方案。
library(mltools)
# Resulting bins have an equal number of observations in each group
das[, "wt2"] <- bin_data(das$wt, bins=3, binType = "quantile")
# Resulting bins are equally spaced from min to max
das[, "wt3"] <- bin_data(das$wt, bins=3, binType = "explicit")
# Or if you'd rather define the bins yourself
das[, "wt4"] <- bin_data(das$wt, bins=c(-Inf, 250, 322, Inf), binType = "explicit")
das
anim wt wt2 wt3 wt4
1 1 181.0 [179, 200.333333333333) [179, 250.666666666667) [-Inf, 250)
2 2 179.0 [179, 200.333333333333) [179, 250.666666666667) [-Inf, 250)
3 3 180.5 [179, 200.333333333333) [179, 250.666666666667) [-Inf, 250)
4 4 201.0 [200.333333333333, 245.466666666667) [179, 250.666666666667) [-Inf, 250)
5 5 201.5 [200.333333333333, 245.466666666667) [179, 250.666666666667) [-Inf, 250)
6 6 245.0 [200.333333333333, 245.466666666667) [179, 250.666666666667) [-Inf, 250)
7 7 246.4 [245.466666666667, 394] [179, 250.666666666667) [-Inf, 250)
8 8 189.3 [179, 200.333333333333) [179, 250.666666666667) [-Inf, 250)
9 9 301.0 [245.466666666667, 394] [250.666666666667, 322.333333333333) [250, 322)
10 10 354.0 [245.466666666667, 394] [322.333333333333, 394] [322, Inf]
11 11 369.0 [245.466666666667, 394] [322.333333333333, 394] [322, Inf]
12 12 205.0 [200.333333333333, 245.466666666667) [179, 250.666666666667) [-Inf, 250)
13 13 199.0 [179, 200.333333333333) [179, 250.666666666667) [-Inf, 250)
14 14 394.0 [245.466666666667, 394] [322.333333333333, 394] [322, Inf]
15 15 231.3 [200.333333333333, 245.466666666667) [179, 250.666666666667) [-Inf, 250)
答案 5 :(得分:2)
cut
,如果未给定明确的断点将值分成相同宽度的bin,则它们通常不会包含相同数量的项目:
x <- c(1:4,10)
lengths(split(x, cut(x, 2)))
# (0.991,5.5] (5.5,10]
# 4 1
Hmisc::cut2
和ggplot2::cut_number
使用分位数,如果数据分布良好且大小合适,通常将创建相同大小的组(就元素数量而言),但是并非总是如此。 mltools::bin_data
可以给出不同的结果,但也基于分位数。
当数据包含少量不同值时,这些函数并不总是给出整洁的结果:
x <- rep(c(1:20),c(15, 7, 10, 3, 9, 3, 4, 9, 3, 2,
23, 2, 4, 1, 1, 7, 18, 37, 6, 2))
table(x)
# x
# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
# 15 7 10 3 9 3 4 9 3 2 23 2 4 1 1 7 18 37 6 2
table(Hmisc::cut2(x, g=4))
# [ 1, 6) [ 6,12) [12,19) [19,20]
# 44 44 70 8
table(ggplot2::cut_number(x, 4))
# [1,5] (5,11] (11,18] (18,20]
# 44 44 70 8
table(mltools::bin_data(x, bins=4, binType = "quantile"))
# [1, 5) [5, 11) [11, 18) [18, 20]
# 35 30 56 45
目前尚不清楚是否找到最佳解决方案。
什么是 best 最佳分箱方法是一个主观问题,但是一种合理的解决方法是寻找使预期分箱大小周围的方差最小的分箱。
(我)软件包cutr
中的函数smart_cut
提出了这样的功能。但是,它的计算量很大,应该保留给切点和唯一值很少的情况(通常在这种情况下很重要)。
# devtools::install_github("moodymudskipper/cutr")
table(cutr::smart_cut(x, list(4, "balanced"), "g"))
# [1,6) [6,12) [12,18) [18,20]
# 44 44 33 45
我们看到小组之间的平衡要好得多。
实际上,如果基于差异的方法不够用,调用中的 "balanced"
可以被自定义函数替换,以根据需要优化或限制垃圾箱。
答案 6 :(得分:1)
您还可以将bin
软件包中的method = "content"
函数与OneR
一起使用:
library(OneR)
das$wt_2 <- as.numeric(bin(das$wt, nbins = 3, method = "content"))
das
## anim wt wt_2
## 1 1 181.0 1
## 2 2 179.0 1
## 3 3 180.5 1
## 4 4 201.0 2
## 5 5 201.5 2
## 6 6 245.0 2
## 7 7 246.4 3
## 8 8 189.3 1
## 9 9 301.0 3
## 10 10 354.0 3
## 11 11 369.0 3
## 12 12 205.0 2
## 13 13 199.0 1
## 14 14 394.0 3
## 15 15 231.3 2
答案 7 :(得分:0)
没有任何额外的包,3是组的数量:
> findInterval(das$wt, unique(quantile(das$wt, seq(0, 1, length.out = 3 + 1))), rightmost.closed = TRUE)
[1] 1 1 1 2 2 2 3 1 3 3 3 2 1 3 2
您可以使用感兴趣的值的代表性样本来加速分位数计算。仔细检查FindInterval
功能的文档。
答案 8 :(得分:0)
如果要分成3组,则答案与Ben Bolker's answer above相同-使用ggplot2::cut_number()
。为了完整起见,这里介绍了将连续转换为分类(合并)的三种方法。
cut_number()
:使n个组具有(大约)相等的观察次数cut_interval()
:使n个群组的距离相等cut_width()
:创建宽度为width的组
我要去的地方是cut_number(),因为它使用间隔均匀的分位数对观察值进行分箱。这是数据偏斜的示例。library(tidyverse)
skewed_tbl <- tibble(
counts = c(1:100, 1:50, 1:20, rep(1:10, 3),
rep(1:5, 5), rep(1:2, 10), rep(1, 20))
) %>%
mutate(
counts_cut_number = cut_number(counts, n = 4),
counts_cut_interval = cut_interval(counts, n = 4),
counts_cut_width = cut_width(counts, width = 25)
)
# Data
skewed_tbl
#> # A tibble: 265 x 4
#> counts counts_cut_number counts_cut_interval counts_cut_width
#> <dbl> <fct> <fct> <fct>
#> 1 1 [1,3] [1,25.8] [-12.5,12.5]
#> 2 2 [1,3] [1,25.8] [-12.5,12.5]
#> 3 3 [1,3] [1,25.8] [-12.5,12.5]
#> 4 4 (3,13] [1,25.8] [-12.5,12.5]
#> 5 5 (3,13] [1,25.8] [-12.5,12.5]
#> 6 6 (3,13] [1,25.8] [-12.5,12.5]
#> 7 7 (3,13] [1,25.8] [-12.5,12.5]
#> 8 8 (3,13] [1,25.8] [-12.5,12.5]
#> 9 9 (3,13] [1,25.8] [-12.5,12.5]
#> 10 10 (3,13] [1,25.8] [-12.5,12.5]
#> # ... with 255 more rows
summary(skewed_tbl$counts)
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> 1.00 3.00 13.00 25.75 42.00 100.00
# Histogram showing skew
skewed_tbl %>%
ggplot(aes(counts)) +
geom_histogram(bins = 30)
# cut_number() evenly distributes observations into bins by quantile
skewed_tbl %>%
ggplot(aes(counts_cut_number)) +
geom_bar()
# cut_interval() evenly splits the interval across the range
skewed_tbl %>%
ggplot(aes(counts_cut_interval)) +
geom_bar()
# cut_width() uses the width = 25 to create bins that are 25 in width
skewed_tbl %>%
ggplot(aes(counts_cut_width)) +
geom_bar()
由reprex package(v0.2.1)于2018-11-01创建
答案 9 :(得分:0)
equal_freq
中的 funModeling
取一个矢量和箱数(基于相等的频率):
das <- data.frame(anim=1:15,
wt=c(181,179,180.5,201,201.5,245,246.4,
189.3,301,354,369,205,199,394,231.3))
das$wt_bin=funModeling::equal_freq(das$wt, 3)
table(das$wt_bin)
#[179,201) [201,246) [246,394]
# 5 5 5