2010-12-05 4 views
2

Je me bats avec quelque chose de très simple, mais je tourne en rond, et je ne vois pas où je fais une erreur. J'espère vraiment que quelqu'un pourrait me prêter une suggestion pratique, pour que je ne sois plus coincé!Calcul des pourcentages dans une instruction apply (R)

Mon objectif: Je veux calculer le pourcentage d'instances dans un data.frame qui ont un résultat supérieur à 0. J'ai essayé cela avec la boucle for, mais en vain. Donc, après quelques recherches, j'ai utilisé la fonction apply pour calculer diverses métriques comme moyenne, sd et min/max. Cela fonctionne très bien, mais pour calculer le pourcentage, la fonction d'application ne fonctionne pas, même lorsque je crée une fonction personnalisée, et l'insère dans la fonction d'application.

Ceci est la version abrégée de mon data.frame:

 tradesList[c(1:5,10:15),c(1,7)] 
    Instrument TradeResult.Currency. 
1   JPM     -3 
2   JPM     264 
3   JPM     284 
4   JPM     69 
5   JPM     283 
10  JPM     -294 
11  KFT     -8 
12  KFT     -48 
13  KFT     125 
14  KFT     -150 
15  KFT     -206 

Je veux résumer ce data.frame, par exemple en affichant la TradeResult moyenne pour chaque instrument:

> tapply(tradesList$TradeResult.Currency., tradesList$Instrument, mean) 
JPM KFT 
42.3 14.6 

Cependant , Je voudrais aussi calculer le pourcentage de lignes qui ont un TradeResult> 0 par instrument. Avec la fonction 'which' vérifiant que les instances qui sont> 0 fonctionne, cependant, apply n'acceptera pas cette fonction comme un argument.

> length(which(tradesList$TradeResult.Currency. > 0))/length(tradesList$TradeResult.Currency.) * 100 
[1] 50 
> tapply(tradesList$TradeResult.Currency., tradesList$Instrument, (length(which(tradesList$TradeResult.Currency. > 0))/length(tradesList$TradeResult.Currency.) * 100)) 
Error in match.fun(FUN) : 
    c("'(length(which(tradesList$TradeResult.Currency. > 0))/length(tradesList$TradeResult.Currency.) * ' is not a function, character or symbol", "' 100)' is not a function, character or symbol") 
> 

J'ai cherché dans la fonction d'aide pour plus d'informations sur cette erreur, et ont essayé différentes manières de formuler la fonction (par exemple avec des crochets ou des guillemets), mais chaque chemin conduit au même résultat. Est-ce que quelqu'un connaît un whay pour calculer le pourcentage d'instances qui sont supérieures à zéro? Peut-être qu'il me manque quelque chose?

Merci beaucoup à l'avance,

Cordialement,

Edit: Merci beaucoup pour vos commentaires rapides G. Grothendieck, Gavin Simpson et dwin. Très apprécié et très utile!

Résolu: Voici ce que j'ai maintenant:

> tmpData <- tradesList[c(1:5,10:15),c(1,7)] 
> tmpData 
    Instrument TradeResult.Currency. 
1   JPM     -3 
2   JPM     264 
3   JPM     284 
4   JPM     69 
5   JPM     283 
10  JPM     -294 
11  KFT     -8 
12  KFT     -48 
13  KFT     125 
14  KFT     -150 
15  KFT     -206 
> 100* # to get percentages 
+ with(tmpData, 
+ tapply((TradeResult.Currency. > 0) , Instrument, sum)/ # number GT 0 
+  tapply(TradeResult.Currency., Instrument, length)) # total number 
    JPM  KFT 
66.66667 20.00000 
> 100 * tapply(tmpData$TradeResult.Currency. > 0, tmpData$Instrument, mean) 
    JPM  KFT 
66.66667 20.00000 
> pcentFun <- function(x) { 
+  res <- x > 0 
+  100 * (sum(res)/length(res)) 
+ } 
> 
> with(tmpData, tapply(TradeResult.Currency., Instrument, pcentFun)) 
    JPM  KFT 
66.66667 20.00000 

Merci encore!

Cordialement,

Répondre

2

Ecrire une fonction simple calcul:

pcentFun <- function(x) { 
    res <- x > 0 
    100 * (sum(res)/length(res)) 
} 

Ensuite, nous pouvons l'appliquer à des groupes d'instruments, via tapply()

> with(tradeList, tapply(TradeResult.Currency, Instrument, pcentFun)) 
    JPM  KFT 
66.66667 20.00000 

mais aggregate() serait plus utile si vous voulez que le résumé avec les noms d'instruments:

> with(tradesList, aggregate(TradeResult.Currency, 
+       by = list(Instrument = Instrument), pcentFun)) 
    Instrument  x 
1  JPM 66.66667 
2  KFT 20.00000 
+0

Merci Gavin, c'est vraiment utile. La suggestion globale est aussi quelque chose que je peux utiliser pour le reste de mon analyse R. Génial! – Jura25

+1

Indice: la somme divisée par la longueur est la définition de la moyenne. – hadley

+0

@ Hadley; merci, vous faites un bon point - je pensais que @ Jura25 reconnaîtrait la formulation que j'ai utilisée plus facilement que le fait de dire que c'était la moyenne. En outre, @ Jura25, en lisant entre les lignes, cherchait à savoir comment aller un peu plus loin avec l'application des fonctions. Le simple fait d'utiliser 'mean' n'aurait pas fait beaucoup de progrès. –

1

Vous pouvez travailler avec des résultats logiques en utilisant la somme ou la moyenne pour obtenir un résumé des résultats significatifs:

100* # to get percentages 
with(tradesList, 
tapply((TradeResult.Currency. > 0) , Instrument, sum)/ # number GT 0 
     tapply(TradeResult.Currency., Instrument, length)) # total number 

Edit: J'ai remarqué que Gavin vous a donné une réponse qui a rendu un dataframe, un général classe bien comprise. La classe des valeurs de Gabor et de mes réponses étaient des tableaux d'une dimension. Ils pourraient être transformés en vecteurs nommés en entourant l'objet par c() qui se double d'une concaténation et d'une coercition à la fonction vectorielle. Et en l'état, ils sont parfaitement acceptables pour relier ou accéder avec "[" de la manière attendue et retrou- ver les résultats attendus de names(). La fonction tapply retourne des tableaux avec le nombre de dimensions dans le (s) argument (s) INDEX et peut être très efficacement combinée pour des opérations matricielles avec des objets table.Je fais beaucoup de divisons par sommes, ou compte par sommes pour obtenir des statistiques de catégories significatives en 2, 3 ou 4 dimensions.

+0

Merci DWin, belle propreté suggèrent ion, même compréhensible pour un débutant comme moi. Je suppose que la déclaration avec() est quelque chose que je vais plus souvent. Merci d'avoir répondu! – Jura25

2

Essayez ceci:

100 * tapply(tradesList$TradeResult.Currency. > 0, tradesList$Instrument, mean) 

Avec les données de l'échantillon dans le poste qu'il donne:

JPM KFT 
66.67 20.00 

et ici qu'il utilise sqldf (notez que le pilote RSQLite se traduit par des points de soulignement puisque les points sont aussi un opérateur SQL donc nous utilisons des underscores où les points étaient):

> library(sqldf) 
> sqldf("select Instrument, 
+  100 * avg(TradeResult_Currency_ > 0) as '%>0', 
+  avg(TradeResult_Currency_) as 'Avg Currency' 
+  from tradesList group by Instrument") 
    Instrument %>0 Avg Currency 
1  JPM 66.67  100.5 
2  KFT 20.00  -57.4 

Ces deux pourraient aussi o être traduit en aggregate par une modification appropriée de la solution aggregate déjà publiée.

+0

Merci G. Grothendieck, simple et élégant mais assez efficace. Merci d'avoir répondu! – Jura25

Questions connexes