Je dois diviser/diviser une variable continue en 3 groupes de taille égale.
Exemple de bloc de données
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))
Après avoir été découpé (en fonction de la valeur de wt
), il me faudrait les 3 classes sous la nouvelle variable wt2
comme ceci:
> 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
Ceci serait appliqué à un grand ensemble de données
essaye ça:
split(das, cut(das$anim, 3))
si vous voulez diviser en fonction de la valeur de wt
, alors
library(Hmisc) # cut2
split(das, cut2(das$wt, g=3))
quoi qu'il en soit, vous pouvez le faire en combinant cut
, cut2
et split
.
MIS &AGRAVE; JOUR
si vous voulez un index de groupe comme une colonne supplémentaire, alors
das$group <- cut(das$anim, 3)
si la colonne doit être indexée comme 1, 2, ..., alors
das$group <- as.numeric(cut(das$anim, 3))
MISE À JOUR DE NOUVEAU
essaye ça:
> 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
Ou consultez cut_number
dans le package ggplot2
, par exemple.
das$wt_2 <- as.numeric(cut_number(das$wt,3))
Notez que cut(...,3)
divise la plage des données d'origine en trois plages de longueurs égales; cela ne donne pas nécessairement le même nombre de observations par groupe si les données sont distribuées de manière inégale (vous pouvez reproduire ce que cut_number
fait en utilisant quantile
de manière appropriée, mais c'est une fonction pratique de Nice). D'autre part, Hmisc::cut2()
utilisant l'argument g=
fait divisé par quantiles, est plus ou moins équivalent à ggplot2::cut_number
. J'aurais peut-être pensé que quelque chose comme cut_number
aurait été introduit dans dplyr
jusqu'à présent, mais autant que je sache, cela n'a pas été le cas .
ntile
de dplyr
le fait maintenant mais se comporte bizarrement avec les NA
.
J'ai utilisé un code similaire dans la fonction suivante qui fonctionne en base R et fait l'équivalent de la solution cut2
ci-dessus:
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)
}
Voici une autre solution utilisant la fonction bin_data()
de mltools package.
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)
Alternative sans en utilisant cut2.
das$wt2 <- as.factor( as.numeric( cut(das$wt,3)))
ou
das$wt2 <- as.factor( cut(das$wt,3, labels=F))
cut
, lorsque les points de rupture ne sont pas explicitement divisés en valeurs de même largeur, ils ne contiennent généralement pas le même nombre d'éléments:
x <- c(1:4,10)
lengths(split(x, cut(x, 2)))
# (0.991,5.5] (5.5,10]
# 4 1
Hmisc::cut2
et ggplot2::cut_number
utilisent des quantiles, qui créeront généralement des groupes de même taille (en termes de nombre d'éléments) si les données sont bien réparties et de taille correcte, ce n'est cependant pas toujours le cas. mltools::bin_data
peut donner des résultats différents mais est également basé sur des quantiles.
Ces fonctions ne donnent pas toujours des résultats précis lorsque les données contiennent un petit nombre de valeurs distinctes:
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
Ce n'est pas clair si la solution optimale a été trouvée ici.
Quelle est l'approche best de binning est une question subjective, mais une façon raisonnable de l'aborder est de rechercher les bacs minimisant la variance autour de la taille de bac prévue.
La fonction smart_cut
de (mon) package cutr
propose une telle fonctionnalité. Cependant, il est lourd en calcul et devrait être réservé aux cas où les points de coupe et les valeurs uniques sont peu nombreux (ce qui est généralement le cas où cela compte).
# 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
Nous constatons que les groupes sont beaucoup mieux équilibrés.
"balanced"
dans l'appel peut en fait être remplacé par une fonction personnalisée pour optimiser ou restreindre les bacs à volonté si la méthode basée sur la variance ne suffit pas.
Si vous souhaitez diviser en 3 groupes également répartis, la réponse est la même que La réponse de Ben Bolker ci-dessus - utilisez ggplot2::cut_number()
. Par souci d’achèvement, voici les 3 méthodes de conversion continue en catégorique (binning).
cut_number()
: Crée n groupes avec un nombre d'observation (approximativement) égalcut_interval()
: crée n groupes avec une plage égalecut_width()
: crée des groupes de largeur width Mon adresse préférée est cut_number () car elle utilise des quantiles régulièrement espacés pour les observations de tri. Voici un exemple avec des données asymétriques.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()
Créé le 2018-11-01 par le paquet reprex (v0.2.1)
Sans forfait supplémentaire, 3 étant le nombre de groupes:
> 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
Vous pouvez accélérer le calcul du quantile en utilisant un échantillon représentatif des valeurs d'intérêt. Vérifiez la documentation de la fonction FindInterval
.