1) En utilisant les données définies dans la note à l'utilisation finale rollapply
comme indiqué ci-dessous. nms
est le nom des colonnes pour effectuer le calcul de la fenêtre glissante ou il peut être spécifié uniquement comme index de colonne (c'est-à-dire nms <- 4:5
). Sum
est comme somme, sauf qu'il renverra NA, au lieu de 0, si donné une série qui est entièrement NA et sinon il effectue sum(X, na.rm = TRUE)
. Notez que les valeurs NA ajoutées au roll
sont telles que la série n'est pas plus courte que la largeur de la fenêtre.
library(data.table)
library(zoo)
k <- 2 # prior two months
Sum <- function(x) if (all(is.na(x))) NA else sum(x, na.rm = TRUE)
roll <- function(x) rollapply(c(x, rep(NA, k)), list(1:k), Sum)
nms <- names(mytable)[4:5]
mytable[, (nms) := lapply(.SD, roll), .SDcols = nms, by = "Company"]
donnant:
> mytable
Month Year Company ProducedCereals CommercialsShown
1: 6 2016 Kellog 15 19
2: 5 2016 Kellog 12 4
3: 4 2016 Kellog NA NA
4: 6 2016 General Mills 7 19
5: 5 2016 General Mills NA NA
1a) Dans un commentaire, la situation est mentiond où avant la ligne actuelle il y a manque de lignes et que les derniers deux mois civils doivent être utilisés de manière moins de 2 lignes peuvent être utilisées dans n'importe quelle somme.
Dans ce cas, il convient de trier d'abord la trame de données dans l'ordre de Société, puis de la trier par ordre croissant, ce qui implique que nous souhaitons que l'alignement soit aligné sur rollapply
.
Nous passons un objet zoo avec l'index yearmon à rollapply
afin que nous ayons un index temporel que Sum
peut vérifier pour sous-totaliser l'entrée à la fenêtre désirée. Nous utilisons une taille de fenêtre de 3 et ne faisons que sommer les valeurs dans la fenêtre dont les heures se situent dans les limites spécifiées. Nous préciserons coredata = FALSE
-rollapply
afin que les données et l'index sont transmis à la fonction rollapply
et pas seulement les données.
k <- 2 # prior 2 months
# inputs zoo object x, subsets it to specified window and sums
Sum2 <- function(x) {
w <- window(x, start = end(x) - k/12, end = end(x) - 1/12)
if (length(w) == 0 || all(is.na(w))) NA_real_ else sum(w, na.rm = TRUE)
}
nms <- names(mytable)[4:5]
setkey(mytable, Company, Year, Month) # sort
# create zoo object from arguments and run rollapplyr using Sum2
roll2 <- function(x, year, month) {
z <- zoo(x, as.yearmon(year + (month - 1)/12))
coredata(rollapplyr(z, k+1, Sum2, coredata = FALSE, partial = TRUE))
}
mytable[, (nms) := lapply(.SD, roll2, Year, Month), .SDcols = nms, by = "Company"]
donnant:
> mytable
Month Year Company ProducedCereals CommercialsShown
1: 5 2016 General Mills NA NA
2: 6 2016 General Mills 7 19
3: 4 2016 Kellog NA NA
4: 5 2016 Kellog 12 4
5: 6 2016 Kellog 15
1b) Une autre approche pour lignes manquantes est de conver les données à forme longue et à un remplissage de forme rectangulaire dans des cellules manquant de NA. Cela fonctionnera tant que le même mois et l'année ne manquent pas dans chaque entreprise.
k <- 2 # sum over k prior months
m <- melt(mytable, id = 1:3)
dd <- as.data.frame.table(tapply(m$value, m[, 1:4, with = FALSE], c),
responseName = "value")
Sum1 <- function(x) {
x <- head(x, -1)
if (length(x) == 0 || all(is.na(x))) NA_real_ else sum(x, na.rm = TRUE)
}
setDT(dd)[, value := rollapplyr(value, k+1, Sum1, partial = TRUE),
by = .(Company, variable)]
dc <- as.data.table(dcast(... ~ variable, data = dd, value = "value"))
setkey(dc, Company, Year, Month)
dc
donne:
Month Year Company ProducedCereals CommercialsShown
1: 4 2016 General Mills NA NA
2: 5 2016 General Mills NA NA
3: 6 2016 General Mills 7 19
4: 4 2016 Kellog NA NA
5: 5 2016 Kellog 12 4
6: 6 2016 Kellog 15 19
2) Une autre possibilité est de convertir mytable
à l'objet zoo z
de division mytable
par la Société et ensuite utiliser rollapply
à ce sujet. mytable
est de nouveau comme indiqué dans la note à la fin. Sum
provient de (1).
k <- 2 # prior 2 months
ym <- function(m, y) as.yearmon(paste(m, y), format = "%m %Y")
z <- read.zoo(mytable, index = 1:2, split = k+1, FUN = ym)
Sum <- function(x) if (all(is.na(x))) NA else sum(x, na.rm = TRUE)
rollapply(z, list(-1:-k), Sum, partial = TRUE, fill = NA)
donnant:
ProducedCereals.General Mills CommercialsShown.General Mills
Apr 2016 NA NA
May 2016 NA NA
Jun 2016 7 19
ProducedCereals.Kellog CommercialsShown.Kellog
Apr 2016 NA NA
May 2016 12 4
Jun 2016 15 19
Note: Le code dans la question ne génère pas les données affichées dans la question si nous avons utilisé ce lieu pour le data.table mytable
:
library(data.table)
mytable <-
structure(list(Month = c(6, 5, 4, 6, 5), Year = c(2016, 2016,
2016, 2016, 2016), Company = c("Kellog", "Kellog", "Kellog",
"General Mills", "General Mills"), ProducedCereals = c(6, 3,
12, 5, 7), CommercialsShown = c(12, 15, 4, 20, 19)), .Names = c("Month",
"Year", "Company", "ProducedCereals", "CommercialsShown"), row.names = c(NA,
-5L), class = "data.frame")
mytable <- as.data.table(mytable)
Voir https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example/28481250#28481250 re comment faire un bon exemple reproductible (qui peut être copier-coller dans une nouvelle session R et exécuter). – Frank
Eh bien, j'ai prévu une sortie et ce que je ressens est une explication relativement succincte du problème, alors vous voulez que j'ajoute des données d'entrée dans R? Tu l'as eu. Édité – shiggity
Ok merci. Dunno avec quelle rapidité quelqu'un publiera une réponse, mais en attendant: je suppose qu'une jointure non equi devrait fonctionner https://stackoverflow.com/questions/44406040/sum-over-past-window-size-dates-per-group/ 44407291 # 44407291 en supposant que vous utilisiez une variable yearmon au lieu de deux colonnes séparées. – Frank