Valeur de densité pour chaque retour
-
11-10-2019 - |
Question
J'ai un dataframe "foo" qui ressemble à ceci
Date Return
1998-01-01 0.02
1998-01-02 0.04
1998-01-03 -0.02
1998-01-04 -0.01
1998-01-05 0.02
...
1998-02-01 0.1
1998-02-02 -0.2
1998-02-03 -0.1
etc.
Je voudrais ajouter à cette dataframe une nouvelle colonne me montrant la valeur de densité du rendement correspondant. J'ai essayé:
foo$density <- for(i in 1:length(foo$Return)) density(foo$Return,
from = foo$Return[i], to = foo$Return[i], n = 1)$y
Mais il ne fonctionne pas. J'ai vraiment des difficultés à appliquer une « fonction » à chaque ligne. Mais peut-être il y a aussi une autre façon de le faire, ne pas utiliser la densité ()?
Ce que je voudrais essentiellement faire est d'extraire les valeurs de densité ajustées de densité () aux rendements dans foo. Si je fais juste parcelle (densité ($ foo retour)) il me donne la courbe, mais je voudrais avoir les valeurs de densité attachées aux rendements.
@Joris:
foo$density <- density(foo$Return, n=nrow(foo$Return))$y
calcule quelque chose, semble toutefois renvoyer des valeurs de densité erronées.
Je vous remercie de me aider! Dani
La solution
À la réflexion, oublier la fonction de densité, je me suis soudain rendu compte ce que vous vouliez faire. La plupart des fonctions de densité renvoient une grille, donc ne vous donne pas l'évaluation des points précis. Si vous voulez, vous pouvez par exemple utiliser le package sm
:
require(sm)
foo <- data.frame(Return=rpois(100,5))
foo$density <- sm.density(foo$Return,eval.points=foo$Return)$estimate
# the plot
id <- order(foo$Return)
hist(foo$Return,freq=F)
lines(foo$Return[id],foo$density[id],col="red")
Si le nombre de valeurs différentes est pas grande, vous pouvez utiliser ave ():
foo$counts <- ave(foo$Return,foo$Return,FUN=length)
Si le but est de parcelle une fonction de densité, il n'y a pas besoin de le calculer comme vous l'avez fait. Il suffit d'utiliser
plot(density(foo$Return))
Ou, pour ajouter un histogramme en dessous (l'esprit l'option freq=F
)
hist(foo$Return,freq=F)
lines(density(foo$Return),col="red")
Autres conseils
Une alternative à sm.density
est d'évaluer la densité sur une grille plus fine que par défaut, et l'utilisation approx
ou approxfun
pour donner les valeurs interpolées de la densité au Returns
vous voulez. Voici un exemple avec des données factices:
set.seed(1)
foo <- data.frame(Date = seq(as.Date("2010-01-01"), as.Date("2010-12-31"),
by = "days"),
Returns = rnorm(365))
head(foo)
## compute the density, on fin grid (512*8 points)
dens <- with(foo, density(Returns, n = 512 * 8))
À ce stade, nous pourrions utiliser approx()
pour interpoler les composants x
et y
de la densité de retour, mais je préfère approxfun()
qui fait la même chose, mais retourne une fonction que l'on peut ensuite utiliser pour faire l'interpolation. Tout d'abord, générer la fonction d'interpolation:
## x and y are components of dens, see str(dens)
BAR <- with(dens, approxfun(x = x, y = y))
Maintenant, vous pouvez utiliser BAR()
pour retourner la densité interpolée à tout moment que vous souhaitez, par exemple pour la première Returns
:
> with(foo, BAR(Returns[1]))
[1] 0.3268715
Pour terminer l'exemple, ajouter la densité pour chaque donnée dans Returns
:
> foo <- within(foo, Density <- BAR(Returns))
> head(foo)
Date Returns Density
1 2010-01-01 -0.6264538 0.3268715
2 2010-01-02 0.1836433 0.3707068
3 2010-01-03 -0.8356286 0.2437966
4 2010-01-04 1.5952808 0.1228251
5 2010-01-05 0.3295078 0.3585224
6 2010-01-06 -0.8204684 0.2490127
Pour voir comment l'interpolation fait, nous pouvons tracer la densité et la version interpolée et comparer. Notez que nous devons trier Returns
car pour obtenir l'effet que nous voulons, les besoins de lines
pour voir les données dans augmentation pour:
plot(dens)
with(foo, lines(sort(Returns), BAR(sort(Returns)), col = "red"))
Ce qui donne quelque chose comme ceci:
Tant que la densité est évaluée à suffisamment fine un ensemble de points (512 * 8 dans l'exemple ci-dessus) vous ne devriez pas avoir de problèmes et sera difficile poussé à faire la différence entre la version interpolée et la chose réelle . Si vous avez des « lacunes » dans les valeurs de votre Returns
alors vous trouverez peut-être que, comme lines()
rejoint juste les points que vous demanderez à tracer, que les segments de ligne droite risquent de ne pas suivre la densité de noir à l'emplacement des lacunes. Ceci est juste un artefact des lacunes et comment fonctionne lines()
, pas un problème avec l'interpolation.
Si l'on ignore la question de density
, qui @Joris experte réponses, vous ne semblent pas avoir compris comment mettre en place une boucle. Ce que vous revenez de la boucle est la valeur NULL
. Ceci est la valeur qui est insérée dans foo$density
et qui ne sera pas non travail, car il est le NULL
, ce qui signifie qu'il est un composant vide, à savoir qu'il n'existe pas dans la mesure où R est concerné. Voir ?'for'
pour plus de détails.
> bar <- for(i in 1:10) {
+ i + 1
+ }
> bar
NULL
> foo <- data.frame(A = 1:10, B = LETTERS[1:10])
> foo$density <- for(i in seq_len(nrow(foo))) {
+ i + 1
+ }
> head(foo) ## No `density`
A B
1 1 A
2 2 B
3 3 C
4 4 D
5 5 E
6 6 F
Si vous souhaitez insérer la valeur de retour pour chaque itération de la boucle, vous devez faire l'affectation dans la boucle, et cela signifie que vous devez pré-allouer l'espace de stockage avant d'entrer dans la boucle , par exemple la boucle ci-dessus si nous voulions avoir i + 1
pour i
en 1, ..., 10, nous pourrions faire ceci:
> bar <- numeric(length = 10)
> for(i in seq_along(bar)) {
+ bar[i] <- i + 1
+ }
> bar
[1] 2 3 4 5 6 7 8 9 10 11
Bien sûr, vous ne feriez pas un tel calcul car cela via une boucle, parce que R est vectorisé et travaillera avec des vecteurs de nombres plutôt que de vous avoir à coder chaque élément de calcul par élément que vous pourriez en C ou autres langages de programmation .
> bar <- 1:10 + 1
> bar
[1] 2 3 4 5 6 7 8 9 10 11
Notez que R est devenu 1
dans un vecteur de 1
s de longueur suffisante pour permettre le calcul de procéder, quelque chose appelé recyclage R-parler.
Parfois, vous pourriez avoir besoin d'itérer sur un objet avec une boucle ou en utilisant l'une de la famille de s|l|t|apply()
, mais le plus souvent, vous trouverez une fonction qui fonctionne pour tout un pan de données en une seule fois. Ceci est l'un des avantages de R sur d'autres langages de programmation, mais ne vous oblige à obtenir votre tête dans vectorisé mode .