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

Était-ce utile?

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: Masse volumique (en noir) et la version interpolée (en rouge)

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 1s 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 .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top