2010-05-06 7 views
1

En R, j'ai un cadre de données avec des colonnes pour Seat (facteur), Party (facteur) et Votes (numérique). Je souhaite créer un cadre de données récapitulatif avec des colonnes pour le partage Seat, Winning et Vote. Par exemple, à partir de la trame de donnéesUtilisation de reshape + cast pour agréger sur plusieurs colonnes

df <- data.frame(party=rep(c('Lab','C','LD'),times=4), 
       votes=c(1,12,2,11,3,10,4,9,5,8,6,15), 
       seat=rep(c('A','B','C','D'),each=3)) 

Je veux obtenir la sortie

seat winner voteshare 
1 A  C 0.8000000 
2 B Lab 0.4583333 
3 C  C 0.5000000 
4 D  LD 0.5172414 

Je peux comprendre comment y parvenir. Mais je suis sûr qu'il doit y avoir un meilleur moyen, probablement un interligne rusé utilisant le paquet reshape de Hadley Wickham. Aucune suggestion?

Pour ce que cela vaut, ma solution utilise une fonction de mon package djwutils_2.10.zip et est appelée comme suit. Mais il y a toutes sortes de cas spéciaux qui ne sont pas traités, alors je préfère me fier au code de quelqu'un d'autre.

aggregateList(df, by=list(seat=seat), 
       FUN=list(winner=function(x) x$party[which.max(x$votes)], 
         voteshare=function(x) max(x$votes)/sum(x$votes))) 
+0

Très topique ensemble de données! –

+0

En effet! J'ai généré des graphiques qui affichent les résultats de la dernière élection, et les dernières cotes de betfair.com, et je veux être prêt pour ce soir. Les parcelles sont à http://www.cs.ucl.ac.uk/staff/d.wischik/Interests/Stats/Election/uk2010.html – DamonJW

Répondre

11

paquet de plyr Hadley peut vous aider:

ddply(df, .(seat), function(x) data.frame(winner=x[which.max(x$votes),]$party, voteshare=max(x$votes)/sum(x$votes))) 
+0

Merci. C'est exactement ce que je voulais. – DamonJW

+2

Ou, plus succinctement (et bientôt plus rapide): 'ddply (df,. (Siège), résumer, gagnant = parti [which.max (votes)], voteshare = max (votes)/somme (votes)) – hadley

3

Vous pouvez avoir raison qu'il ya une seule ligne rusé. J'ai tendance à favoriser l'approche qui est compréhensible est mieux que malin, surtout quand vous regardez d'abord quelque chose. Voici l'alternative plus verbeuse.

votes_by_seat_and_party <- as.matrix(cast(df, seat ~ party, value="votes")) 

    C Lab LD 
A 12 1 2 
B 3 11 10 
C 9 4 5 
D 6 8 15 

seats <- rownames(votes_by_seat_and_party) 
parties <- colnames(votes_by_seat_and_party) 

winner_col <- apply(votes_by_seat_and_party, 1, which.max) 
winners <- parties[winner_col] 
voteshare_of_winner_by_seat <- apply(votes_by_seat_and_party, 1, function(x) max(x)/sum(x)) 

results <- data.frame(seat = seats, winner = winners, voteshare = voteshare_of_winner_by_seat) 

    seat winner voteshare 
1 A  C 0.8000000 
2 B Lab 0.4583333 
3 C  C 0.5000000 
4 D  LD 0.5172414 

# Full voteshare matrix, if you're interested 
total_votes_by_seat <- rowSums(votes_by_seat_and_party) 
voteshare_by_seat_and_party <- votes_by_seat_and_party/total_votes_by_seat 
+0

Vous pouvez traiter les valeurs manquantes (où il n'y avait pas de candidat pour une partie en particulier à un siège donné) comme «0» ou «NA». –

2

OK, donc 3 solutions ... voici une autre solution plus compacte en utilisant R. brut, il est 4 lignes de code clairsemés. Je suppose que les valeurs manquantes sont 0, ou juste manquant, parce que cela n'aura pas d'importance. Je suppose que ce serait votre code le plus rapide pour un grand nombre de données.

#get a sum for dividing 
s <- aggregate(df$votes, list(seat = df$seat), sum) 
#extract the winner and seat 
temp <- aggregate(df$votes, list(seat = df$seat), max) 
res <- df[df$seat %in% temp$seat & df$votes %in% temp$x,] 
res$votes <- res$votes/s$x 

Renommez les colonnes si vous le souhaitez ...

res noms $ < - c ('partie', 'voteshare', 'gagnant')

(cela renvoie une erreur l'événement d'une cravate ... vous serez en mesure de le voir dans le cadre de données temp)