6
votes

R: Calculez une somme roulante sur la série chronologique irrégulière regroupée par des variables d'identification avec une fenêtre à temps basse

J'aime r mais certains problèmes sont tout simplement difficiles.

Le défi consiste à trouver la première instance d'une somme de roulement inférieure à 30 dans une série de temps irrégulière ayant une fenêtre à base de temps supérieure ou égale à 6 heures. J'ai un échantillon de la série p> xxx pré>

nerveux n observations, il y a des intervalles N * (N-1) / 2 qui doivent être comparés. Par exemple, avec n = 2, il y a juste 1 intervalle pour évaluer. Pour n = 3, il y a 3 intervalles. Et ainsi de suite. P>

Je suppose qu'il s'agit d'une variante du problème de somme sous-ensemble ( http : //fr.wikipedia.org/wiki/subset_sum_problem ) p>

Bien que les données puissent être triées, je suppose que cela nécessite une solution de force brute testant chaque intervalle. P>

L'aide serait appréciée. p>


Edit: Voici les données avec la colonne DateTime formatée comme POSIXCT: P>

df <- structure(list(Person = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 
2L, 3L, 3L, 3L, 4L, 4L, 4L), .Label = c("A", "B", "C", "D"), class = "factor"), 
DateTime = structure(c(1388560500, 1388564100, 1388566800, 
1388571300, 1388582100, 1388560500, 1388567700, 1388600100, 
1388559600, 1388563200, 1388580300, 1388556000, 1388560500, 
1388582100), class = c("POSIXct", "POSIXt"), tzone = ""), 
Value = c(5L, 5L, 5L, 5L, 5L, 25L, 25L, 2L, 20L, 5L, 1L, 
1L, 13L, 15L)), .Names = c("Person", "DateTime", "Value"), row.names = c("1", 
"2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", 
"14"), class = "data.frame")


0 commentaires

3 Réponses :


4
votes

J'ai trouvé que ceci soit un problème difficile dans R aussi. Donc j'ai fait un paquet pour cela!

require(data.table)
setDT(df)
df[ , roll := rollingByCalcs(df,dates="DateTime",target="Value",
                    by="Person",stat=sum,lower=0,upper=6*60*60)]

    Person            DateTime Value roll
 1:      A 2014-01-01 01:15:00     5    5
 2:      A 2014-01-01 02:15:00     5   10
 3:      A 2014-01-01 03:00:00     5   15
 4:      A 2014-01-01 04:15:00     5   20
 5:      A 2014-01-01 07:15:00     5   25
 6:      B 2014-01-01 01:15:00    25   25
 7:      B 2014-01-01 03:15:00    25   50
 8:      B 2014-01-01 12:15:00     2    2
 9:      C 2014-01-01 01:00:00    20   20
10:      C 2014-01-01 02:00:00     5   25
11:      C 2014-01-01 06:45:00     1   26
12:      D 2014-01-01 00:00:00     1    1
13:      D 2014-01-01 01:15:00    13   14
14:      D 2014-01-01 07:15:00    15   28


5 commentaires

+1, sympa! Pouvez-vous démontrer comment la sortie de votre fonction à l'aide des données d'échantillons de l'OP ressemblerait?


Chose sûre! @Dave M, pourriez-vous utiliser dput sur vos données? Ou pouvez-vous rendre vos données reproductibles en quelque sorte?


J'avais déjà créé les données, alors j'ai ajouté un dput à la question


Remarquable. Et très apprécié. Je ne suis pas au travail pour le moment, mais j'ai passé le week-end à rêver d'une solution - en vain. Les séquences ne sont pas aussi longues dans le jeu de données réel, mais il y a probablement 30 000 personnes à traiter. Je vais donc vous garder posté. Et merci beaucoup.


Chose sûre! Et si vous avez besoin d'une vitesse (et que vous exécutez Mac OSX ou Linux), vous pouvez modifier les noyaux de 1 à autant que vous le souhaitez.



1
votes

Nous supposons qu'un intervalle est défini par deux rangées pour la même personne. Pour chaque personne, nous voulons le premier intervalle de ce type (sagesse) d'au moins 6 heures pour lesquels la somme de de la valeur code> de ces deux rangées et de toutes les lignes intermédiaires est inférieure à 30. S'il y a plus de que l'un de ce premier intervalle pour une personne choisissez une arbitraire.

Ceci peut être représenté par une triple jointure dans SQL. La sélection interne choisit toutes les lignes constituées du début de l'intervalle ( a.datetime code>), la fin de l'intervalle ( b.datetime code>) et des lignes entre eux ( C.DateTime code>) Regroupement par Personne CODE> et intervalle et sommation sur la valeur Code> à condition qu'il s'étend sur au moins 6 heures code>. La sélection externe ne conserve que ces lignes dont total code> est personne code> ne conserve que celui dont celui dont DateTime code> est le moins. S'il y a plus d'une première ligne (temps sage) pour une personne code> il choisit un arbitrairement. P> xxx pré>

donnant: p> xxx pré>

Remarque: strong> Nous avons utilisé ces données: p>

DF <- data.frame( Row = 1:14,
  Person = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 4L, 
             4L, 4L), .Label = c("A", "B", "C", "D"), class = "factor"),
  DateTime = structure(c(1388582100, 1388585700, 1388588400, 1388592900, 
             1388603700, 1388582100, 1388589300, 1388621700, 1388581200, 
             1388584800, 1388601900, 1388577600, 1388582100, 1388603700), 
             class = c("POSIXct", "POSIXt"), tzone = ""),
  Value = c(5L, 5L, 5L, 5L, 5L, 25L, 25L, 2L, 20L, 5L, 1L, 1L, 13L, 15L) ) 


0 commentaires

1
votes

à partir de la version 1.9.8 (sur Cran 25 nov. 2016), le data.Table package a gagné la capacité de agrégée dans une jointure non équité em>.

   Person               start                 end       hours
1:      A 2014-01-01 08:15:00 2014-01-01 14:15:00  6.00 hours
2:      B 2014-01-01 08:15:00 2014-01-01 19:15:00 11.00 hours
3:      B 2014-01-01 10:15:00 2014-01-01 19:15:00  9.00 hours
4:      D 2014-01-01 07:00:00 2014-01-01 14:15:00  7.25 hours
5:      D 2014-01-01 08:15:00 2014-01-01 14:15:00  6.00 hours


0 commentaires