J'ai les données suivantes:
Name <- c("Sam", "Sarah", "Jim", "Fred", "James", "Sally", "Andrew", "John", "Mairin", "Kate", "Sasha", "Ray", "Ed")
Age <- c(22,12,31,35,58,82,17,34,12,24,44,67,43)
Group <- c("A", "B", "B", "B", "B", "C", "C", "D", "D", "D", "D", "D", "D")
data <- data.frame(Name, Age, Group)
Et j'aimerais utiliser dplyr pour
(1) regrouper les données par "Groupe" (2) afficher l'âge min et max au sein de chaque groupe (3) afficher le nom de la personne avec les âges min et max
Le code suivant le fait:
data %>% group_by(Group) %>%
summarize(minAge = min(Age), minAgeName = Name[which(Age == min(Age))],
maxAge = max(Age), maxAgeName = Name[which(Age == max(Age))])
Ce qui fonctionne bien:
Group minAge minAgeName maxAge maxAgeName
1 A 22 Sam 22 Sam
2 B 12 Sarah 58 James
3 C 17 Andrew 82 Sally
4 D 12 Mairin 67 Ray
Cependant, j'ai un problème s'il y a plusieurs valeurs min ou max:
Name <- c("Sam", "Sarah", "Jim", "Fred", "James", "Sally", "Andrew", "John", "Mairin", "Kate", "Sasha", "Ray", "Ed")
Age <- c(22,31,31,35,58,82,17,34,12,24,44,67,43)
Group <- c("A", "B", "B", "B", "B", "C", "C", "D", "D", "D", "D", "D", "D")
data <- data.frame(Name, Age, Group)
> data %>% group_by(Group) %>%
+ summarize(minAge = min(Age), minAgeName = Name[which(Age == min(Age))],
+ maxAge = max(Age), maxAgeName = Name[which(Age == max(Age))])
Error: expecting a single value
Je recherche deux solutions:
(1) où peu importe le nom min ou max affiché, juste celui-là (c'est-à-dire la première valeur trouvée) (2) où s'il y a des "liens" toutes les valeurs minimales et maximales sont affichées
Veuillez me faire savoir si ce n'est pas clair et merci d'avance!
Je recommanderais en fait de conserver vos données dans un format "long". Voici comment j'aborderais ceci:
library(dplyr)
Garder toutes les valeurs quand il y a des liens:
data %>%
group_by(Group) %>%
arrange(Age) %>% ## optional
filter(Age %in% range(Age))
# Source: local data frame [8 x 3]
# Groups: Group
#
# Name Age Group
# 1 Sam 22 A
# 2 Sarah 31 B
# 3 Jim 31 B
# 4 James 58 B
# 5 Andrew 17 C
# 6 Sally 82 C
# 7 Mairin 12 D
# 8 Ray 67 D
Garder une seule valeur quand il y a des liens:
data %>%
group_by(Group) %>%
arrange(Age) %>%
slice(if (length(Age) == 1) 1 else c(1, n())) ## maybe overkill?
# Source: local data frame [7 x 3]
# Groups: Group
#
# Name Age Group
# 1 Sam 22 A
# 2 Sarah 31 B
# 3 James 58 B
# 4 Andrew 17 C
# 5 Sally 82 C
# 6 Mairin 12 D
# 7 Ray 67 D
Si vous voulez vraiment un ensemble de données "large", le concept de base serait de gather
et spread
les données, en utilisant "tidyr":
library(dplyr)
library(tidyr)
data %>%
group_by(Group) %>%
arrange(Age) %>%
slice(c(1, n())) %>%
mutate(minmax = c("min", "max")) %>%
gather(var, val, Name:Age) %>%
unite(key, minmax, var) %>%
spread(key, val)
# Source: local data frame [4 x 5]
#
# Group max_Age max_Name min_Age min_Name
# 1 A 22 Sam 22 Sam
# 2 B 58 James 31 Sarah
# 3 C 82 Sally 17 Andrew
# 4 D 67 Ray 12 Mairin
Mais quelle forme large vous voudriez avec des liens n'est pas claire.
Vous pouvez utiliser which.min
et which.max
pour obtenir la première valeur.
data %>% group_by(Group) %>%
summarize(minAge = min(Age), minAgeName = Name[which.min(Age)],
maxAge = max(Age), maxAgeName = Name[which.max(Age)])
Pour obtenir toutes les valeurs, utilisez par exemple coller avec un argument collapse
approprié.
data %>% group_by(Group) %>%
summarize(minAge = min(Age), minAgeName = paste(Name[which(Age == min(Age))], collapse = ", "),
maxAge = max(Age), maxAgeName = paste(Name[which(Age == max(Age))], collapse = ", "))
Voilà quelque data.table
approche, la première empruntée à @akrun:
setDT(data)
# show one, wide format
data[,c(min=.SD[which.min(Age)],max=.SD[which.max(Age)]),by=Group]
# Group min.Name min.Age max.Name max.Age
# 1: A Sam 22 Sam 22
# 2: B Sarah 31 James 58
# 3: C Andrew 17 Sally 82
# 4: D Mairin 12 Ray 67
# show all, long format
data[,{
mina=min(Age)
maxa=max(Age)
rbind(
data.table(minmax="min",Age=mina,Name=Name[which(Age==mina)]),
data.table(minmax="max",Age=maxa,Name=Name[which(Age==maxa)])
)},by=Group]
# Group minmax Age Name
# 1: A min 22 Sam
# 2: A max 22 Sam
# 3: B min 31 Sarah
# 4: B min 31 Jim
# 5: B max 58 James
# 6: C min 17 Andrew
# 7: C max 82 Sally
# 8: D min 12 Mairin
# 9: D max 67 Ray
Je pense que le format long est le meilleur, car il vous permet de filtrer avec minmax
, mais le code est torturé et inefficace.
Voici quelques moyens sans doute moins bons:
# show all, wide format (with a list column)
data[,{
mina=min(Age)
maxa=max(Age)
list(
minAge=mina,
maxAge=maxa,
minNames=list(Name[Age==mina]),
maxNames=list(Name[Age==maxa]))
},by=Group]
# Group minAge maxAge minNames maxNames
# 1: A 22 22 Sam Sam
# 2: B 31 58 Sarah,Jim James
# 3: C 17 82 Andrew Sally
# 4: D 12 67 Mairin Ray
# show all, wide format (with a string column)
# (just look at @shadow's answer)