2013-03-17 15 views
7

Zastanawiam się, czy istnieje bardziej straighforward sposób obliczyć pewien typ zmiennych niż podejście i zwykle trwa ....Oblicz „charakterystyka grupy” bez ddply i scalić

Poniższy przykład wyjaśnia to prawdopodobnie najlepszy. Mam ramkę danych z 2 kolumnami (owoce i czy owoc jest zgniły czy nie). Chciałbym, dla każdego rzędu, dodać np. procent owoców tej samej kategorii, która jest zepsuta. Na przykład są 4 wpisy dla jabłek, 2 z nich są zgniłe, więc każdy wiersz dla jabłka powinien mieć wartość 0,5. Wartości docelowe (wyłącznie jako ilustracja) są zawarte w kolumnie "pożądany wynik".

już wcześniej podszedł do tego problemu przez * przy użyciu „ddply” polecenia w zmiennej owocowe (z sumy/długość jako funkcja), tworząc nowy 3 * 2 dataframe * Używanie „scalić”, aby połączyć te powraca do starej ramki danych.

To wydaje się być okrężną drogą i zastanawiałem się, czy jest lepszy/szybszy sposób robienia tego! Idealne podejście ogólne, które można łatwo dostosować, jeśli jeden zamiast procentu musi określić, czy np. wszystkie owoce są zgniłe, wszelkie owoce są zgniłe, itd. itd. itd ....

Dziękujemy wcześniej,

W

Fruit Rotten Desired_Outcome_PercRotten 
1 Apple  1      0.5 
2 Apple  1      0.5 
3 Apple  0      0.5 
4 Apple  0      0.5 
5 Pear  1      0.75 
6 Pear  1      0.75 
7 Pear  1      0.75 
8 Pear  0      0.75 
9 Cherry  0       0 
10 Cherry  0       0 
11 Cherry  0       0 

#create example datagram; desired outcome columns are purely inserted as illustrative of target outcomes 
Fruit=c(rep("Apple",4),rep("Pear",4),rep("Cherry",3)) 
Rotten=c(1,1,0,0,1,1,1,0,0,0,0) 
Desired_Outcome_PercRotten=c(0.5,0.5,0.5,0.5,0.75,0.75,0.75,0.75,0,0,0) 
df=as.data.frame(cbind(Fruit,Rotten,Desired_Outcome_PercRotten))   
df 
+2

Pokrewne dyskusję na pierwszej części twoje pytanie: http://stackoverflow.com/q/11562656/636656. Odpowiedzi poniżej są przyjemniejsze, ponieważ łączą operację split-apply-merging z połączeniem w jednym kroku. –

+0

user1885116, użyj 'df <- data.frame (Fruit, Rotten, Desired_Outcome_PercRotten)', aby utworzyć 'data.frame' od początku zamiast' as.data.frame' z 'cbind'. Otrzymuje kolumnę "Rotten" jako czynnik, który jest niepożądany. – Arun

Odpowiedz

11

Można to zrobić tylko z ddply i mutate:

# changed summarise to transform on joran's suggestion 
# changed transform to mutate on mnel's suggestion :) 
ddply(df, .(Fruit), mutate, Perc = sum(Rotten)/length(Rotten)) 

#  Fruit Rotten Perc 
# 1 Apple  1 0.50 
# 2 Apple  1 0.50 
# 3 Apple  0 0.50 
# 4 Apple  0 0.50 
# 5 Cherry  0 0.00 
# 6 Cherry  0 0.00 
# 7 Cherry  0 0.00 
# 8 Pear  1 0.75 
# 9 Pear  1 0.75 
# 10 Pear  1 0.75 
# 11 Pear  0 0.75 
+4

Proponuję również 'mutate' (implementację' plyr' 'transform', która pozwala ci odwoływać się do utworzonych kolumn np.' Ddply (df,. (Fruit), mutate, percR = sum (Rotten)/length (Rotten) , pp = Rotten * percR) 'w porównaniu do' ddply (dd,. (Fruit), transform, percR = sum (Rotten)/length (Rotten), pp = Rotten * percR) ' – mnel

10

data.table jest super szybki, ponieważ aktualizuje przez odniesienie. A co z jego użyciem?

library(data.table) 

dt=data.table(Fruit,Rotten,Desired_Outcome_PercRotten) 

dt[,test:=sum(Rotten)/.N,by="Fruit"] 
#dt 
#  Fruit Rotten Desired_Outcome_PercRotten test 
# 1: Apple  1      0.50 0.50 
# 2: Apple  1      0.50 0.50 
# 3: Apple  0      0.50 0.50 
# 4: Apple  0      0.50 0.50 
# 5: Pear  1      0.75 0.75 
# 6: Pear  1      0.75 0.75 
# 7: Pear  1      0.75 0.75 
# 8: Pear  0      0.75 0.75 
# 9: Cherry  0      0.00 0.00 
#10: Cherry  0      0.00 0.00 
#11: Cherry  0      0.00 0.00 
5

Jednym rozwiązaniem w bazie R jest użycie ave.

within(df, { 
    ## Because of how you've created your data.frame 
    ## Rotten is actually a factor. So, we need to 
    ## convert it to numeric before we can use mean 
    Rotten <- as.numeric(as.character(Rotten)) 
    NewCol <- ave(Rotten, Fruit) 
}) 
    Fruit Rotten Desired_Outcome_PercRotten NewCol 
1 Apple  1      0.5 0.50 
2 Apple  1      0.5 0.50 
3 Apple  0      0.5 0.50 
4 Apple  0      0.5 0.50 
5 Pear  1      0.75 0.75 
6 Pear  1      0.75 0.75 
7 Pear  1      0.75 0.75 
8 Pear  0      0.75 0.75 
9 Cherry  0       0 0.00 
10 Cherry  0       0 0.00 

lub krócej:

transform(df, desired = ave(Rotten == 1, Fruit)) 

Funkcja domyślna stosowana z ave jest mean, stąd nie obejmowały go tutaj. Możesz jednak podać inną funkcję, dodając FUN = some-function-here, jeśli chcesz zrobić coś innego.

2

Jako że ave jest już dostępny, pozwól mi dodać jedno rozwiązanie za pomocą wybranej przeze mnie funkcji R: aggregate.

można uzyskać żądane dane po prostu z:

aggregate(as.numeric(as.character(Rotten)) ~ Fruit, df, mean) 

Jednak trzeba będzie jeszcze merge go później (lub w jednym kawałku):

merge(df, aggregate(as.numeric(as.character(Rotten)) ~ Fruit, df, mean))