web-dev-qa-db-fra.com

Compter des valeurs uniques pour chaque colonne

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.

14
Zfunk

Vous pouvez utiliser apply:

apply(Testdata, 2, function(x) length(unique(x)))
# var_1 var_2 var_3 
#     1     1     3
25
sgibb

Dans dplyr:

Testdata %>% summarise_all(funs(n_distinct(.)))
6
leerssej

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).

5
Tapajit Dey

Utilisation de la fonction lengths-:

lengths(lapply(Testdata, unique))

# var_1 var_2 var_3 
#     1     1     3 
2
zx8754

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.

1
Matthew Plourde

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
1
Megatron

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
0
user6376316
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
0
Vinay