Je voudrais renvoyer le nombre de valeurs uniques pour chaque colonne d'un tableau. Par exemple, si j'ai la table:
Testdata <- data.frame(var_1 = c("a","a","a"), var_2 = c("b","b","b"), var_3 = c("c","d","e"))
var_1 | var_2 | var_3
a | b | c
a | b | d
a | b | e
Je voudrais que la sortie soit:
Variable | Unique_Values
var_1 | 1
var_2 | 1
var_3 | 3
J'ai essayé de jouer avec des boucles en utilisant la fonction unique, par exemple.
for(i in names(Testdata)){
# Code using unique function
}
Cependant, je soupçonne qu'il existe un moyen plus simple.
Vous pouvez utiliser apply
:
apply(Testdata, 2, function(x) length(unique(x)))
# var_1 var_2 var_3
# 1 1 3
Dans dplyr
:
Testdata %>% summarise_all(funs(n_distinct(.)))
C'est en fait une amélioration par rapport au commentaire de @Ananda Mahto. Cela ne cadrait pas dans le commentaire, j'ai donc décidé d'ajouter une réponse.
sapply
est en fait légèrement plus rapide que lapply
et donne la sortie sous une forme plus compacte, tout comme la sortie de apply
.
Un résultat d'exécution de test sur les données réelles:
> start <- Sys.time()
> apply(datafile, 2, function(x)length(unique(x)))
symbol. date volume
1371 261 53647
> Sys.time() - start
Time difference of 1.619567 secs
>
> start <- Sys.time()
> lapply(datafile, function(x)length(unique(x)))
$symbol.
[1] 1371
$date
[1] 261
$volume
[1] 53647
> Sys.time() - start
Time difference of 0.07129478 secs
>
> start <- Sys.time()
> sapply(datafile, function(x)length(unique(x)))
symbol. date volume
1371 261 53647
> Sys.time() - start
Time difference of 0.06939292 secs
La datafile
compte environ 3,5 millions de lignes.
Citation du texte d'aide:
sapply est une version conviviale et un wrapper de lapply par défaut renvoyer un vecteur, une matrice ou, si simplify = "array", un tableau si approprié, en appliquant simplify2array (). sapply (x, f, simplify = FALSE, USE.NAMES = FALSE) est identique à lapply (x, f).
Utilisation de la fonction lengths
-:
lengths(lapply(Testdata, unique))
# var_1 var_2 var_3
# 1 1 3
Voici une alternative:
aggregate(values ~ ind, unique(stack(Testdata)), length)
# ind values
# 1 var_1 1
# 2 var_2 1
# 3 var_3 3
Cela nécessite que les colonnes soient character
.
Ici, j'ai utilisé dplyr
et tidyr
pour compter (en utilisant votre bloc de données Testdata
):
Testdata %>%
gather(var, value) %>%
distinct() %>%
count(var)
# # A tibble: 3 × 2
# var n
# <chr> <int>
# 1 var_1 1
# 2 var_2 1
# 3 var_3 3
J'ai juste essayé toutes les solutions et deux des solutions ci-dessus ne fonctionnaient pas, l'une avec l'agrégat et l'autre avec tidyr, mais deux d'entre elles utilisant ne fonctionnaient pas. Je pense que l’utilisation d’une table de données est un bon choix,
setDT(Testdata)[, lapply(.SD, uniqueN), .SDcols=c("var_1","var_2","var_3")]
# var_1 var_2 var_3
# 1: 1 1 3
J'ai essayé de les comparer les uns aux autres
library(microbenchmark)
Mycomp = microbenchmark(
apply = apply(Testdata, 2, function(x)length(unique(x))),
lapply = lapply(Testdata, function(x)length(unique(x))),
sapply = sapply(Testdata, function(x)length(unique(x))),
#base = aggregate(values ~ ind, unique(stack(Testdata)), length),
datatable = setDT(Testdata)[, lapply(.SD, uniqueN), .SDcols=c("var_1","var_2","var_3")],
times=50
)
#Unit: microseconds
# expr min lq mean median uq max neval cld
# apply 163.315 176.678 192.0435 181.7915 192.047 608.859 50 b
# lapply 138.217 147.339 157.9684 153.0640 165.829 254.145 50 a
# sapply 160.338 169.124 178.1486 174.3965 185.548 203.419 50 b
# datatable 667.937 684.650 698.1306 696.0160 703.390 874.073 50 c
library(purrr)
Testdata %>% map_dbl(n_distinct)
var_1 var_2 var_3
1 1 3
# in your format
Testdata %>% map_dbl(n_distinct)%>%melt(value.name = "unique_counts")
unique_counts
var_1 1
var_2 1
var_3 3