web-dev-qa-db-fra.com

Sous-section roulante sur colonnes (pas des lignes!) Dans r

J'ai regardé autour de vous pour une question similaire, mais tous ceux que j'ai trouvés voulaient faire une soustraction roulante par des lignes .

Ce que je veux faire, c'est une Sous-section roulante sur mon Dataframe colonnes. Plus précisément, je souhaiterais soustraire chaque colonne séquentiellement (de gauche à droite), tout en conservant le cumulatif soustrait actuel, comme la colonne "totale" pour soustraire dans la séquence suivante.

J'ai trouvé un moyen de coder cela, mais évidemment, il a l'air moche et que le code briserait si le nombre de colonnes diffère de quelque manière que ce soit du nombre de DFS créé.

Disons que nous avons un Dataframe d'une population pour chaque âge pour chaque année, le total étant les rangements de chaque année:

df <- data.frame(Age <- c(1:40), 
                 Total <- rep(500,40), 
                 Y1990 <- rep(100,40), 
                 Y1991 <- rep(100,40),
                 Y1992 <- rep(100,40))

Le résultat que je veux a été atteint par le code suivant:

df1 <- df$Total  #or df[2]
df2 <- df1 - df[3]
df3 <- df2 - df[4]
...
dfx <- df(x-1) - df[x+1]

#and then we join them together like so:
final_df <- cbind(df$Age, df1, df2, df3,..., dfx)

#final_df should be the Age column, the Total column (500), df2 should be 400 (500-100 = 400), df3 should be 300, etc. etc.)

Je me suis traité avec des boucles mais je ne pouvais pas vraiment obtenir la première/la dernière itération au travail (la partie x + 1/x-1 conservée me donnant une erreur que l'indice était hors limites). J'ai même essayé d'utiliser "Break" ou "Suivant" dans la boucle mais je ne pouvais pas la saisir tout à fait. J'ai environ 70 ans de données, et éventuellement plus à l'avenir, j'ai donc besoin de mettre à jour mon code pour le rendre futur de manière à ne pas avoir de centaines de lignes de code "DFX".

Je me demande si quelqu'un pouvait fournir une boucle ou une fonction super simple pour y aller. Peut-être une solution de données.Table est-elle plus facile, même si j'ai du mal à la syntaxe de données. Points bonus Si vous pouvez garder le nom de la variable tout au long de l'itération (non nécessaire). Je veux juste que mon code soit joli et robuste! Bravo et merci.

1
GabeMath

Je pense que c'est ce que tu veux. Il n'y a pas besoin de 40 lignes identiques, 5 devraient suffire:

df <- data.frame(Age = c(1:5), Total = rep(500, 5), Y1990 = rep(100, 5), Y1991 = rep(100, 5), Y1992 = rep(100, 5))

final_df <- data.frame(df[, 1:2], df$Total - t(apply(df[, 3:5], 1, cumsum)))
colnames(final_df)[-(1:2)] <- c("df2", "df3", "df4")
final_df
#   Age Total df2 df3 df4
# 1   1   500 400 300 200
# 2   2   500 400 300 200
# 3   3   500 400 300 200
# 4   4   500 400 300 200
# 5   5   500 400 300 200
1
dcarlson

Voici une solution avec données.Table:

library(data.table)
df <- data.frame(Age = c(1:5), Total = rep(500, 5), Y1990 = rep(100, 5), Y1991 = rep(100, 5), Y1992 = rep(100, 5))
setDT(df)
final_df <- cbind(df[, .(Age = Age)], 
                  df[, Reduce(`-`, .SD, init = Total, accumulate = TRUE), 
                     .SDcols = Y1990:Y1992])
final_df
  Age  V1  V2  V3  V4
1:   1 500 400 300 200
2:   2 500 400 300 200
3:   3 500 400 300 200
4:   4 500 400 300 200
5:   5 500 400 300 200
0
Brian Montgomery

Diverses façons d'y aller:

cbind(df[1], matrixStats::rowCumsums(as.matrix(df[-1])))
  Age   1   2   3   4
1   1 500 600 700 800
2   2 500 600 700 800
3   3 500 600 700 800
4   4 500 600 700 800
5   5 500 600 700 800


cbind(df[1], list2DF(Reduce('-', df[-1], accumulate = TRUE)))

  Age Var.2 Var.3 Var.4 Var.5
1   1   500   400   300   200
2   2   500   400   300   200
3   3   500   400   300   200
4   4   500   400   300   200
5   5   500   400   300   200
0
Onyambu