#r #dataframe #dplyr #data.table #tidyverse
#r #фрейм данных #dplyr #данные.таблица #tidyverse
Вопрос:
Я искал аналогичный вопрос, но все, кого я нашел, хотели выполнить скользящее вычитание по строкам.
То, что я хочу сделать, — это скользящее вычитание по столбцам моего фрейма данных. В частности, я хотел бы вычесть каждый столбец последовательно (слева направо), сохраняя при этом текущий вычитаемый совокупный, как «общий» столбец для вычитания в следующей последовательности.
Я нашел способ жестко закодировать это, но, очевидно, это выглядит некрасиво, и код сломается, если количество столбцов будет каким-либо образом отличаться от количества созданных dfs.
Допустим, у нас есть рамка данных о населении для каждого возраста за каждый год, а общая сумма-это суммы строк за каждый год:
df lt;- data.frame(Age lt;- c(1:40), Total lt;- rep(500,40), Y1990 lt;- rep(100,40), Y1991 lt;- rep(100,40), Y1992 lt;- rep(100,40))
Желаемый результат был достигнут с помощью следующего кода:
df1 lt;- df$Total #or df[2] df2 lt;- df1 - df[3] df3 lt;- df2 - df[4] ... dfx lt;- df(x-1) - df[x 1] #and then we join them together like so: final_df lt;- 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.)
Я возился с циклами, но не мог заставить работать первую/последнюю итерацию (часть x 1/x-1 продолжала выдавать мне ошибку, что индекс был вне диапазона). Я даже попытался использовать «перерыв» или «следующий» в цикле, но я не мог до конца понять это. У меня есть около 70 лет данных, и, возможно, в будущем их будет больше, поэтому мне нужно обновить свой код, чтобы он был устойчив к будущему, чтобы не иметь сотен строк кода «dfx».
Мне интересно, может ли кто-нибудь предоставить супер простой цикл или функцию для этого. Возможно, решение data.table проще всего, хотя мне трудно работать с синтаксисом data.table. Бонусные баллы, если вы сможете сохранить имя переменной на протяжении всей итерации (хотя это и не обязательно). Я просто хочу, чтобы мой код был красивым и надежным! Ваше здоровье и спасибо вам.
Ответ №1:
Я думаю, это то, чего ты хочешь. Нет необходимости в 40 одинаковых строках, 5 должно быть достаточно:
df lt;- data.frame(Age = c(1:5), Total = rep(500, 5), Y1990 = rep(100, 5), Y1991 = rep(100, 5), Y1992 = rep(100, 5)) final_df lt;- data.frame(df[, 1:2], df$Total - t(apply(df[, 3:5], 1, cumsum))) colnames(final_df)[-(1:2)] lt;- 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. Потрясающий, простой, интерпретируемый, использует базу R и обобщается для x столбцов. Большое вам спасибо!
2. Просто немного отредактировал свой код
final_df lt;- data.frame(df[, 1:2], df$Total - t(apply(df[, 3:ncol(df)], 1, cumsum)))
, заменив 3:5 на 3:ncol(df), так что теперь он должен работать бесконечное количество лет! Очень легко понять, спасибо!!3. Спасибо за редактирование.
Ответ №2:
Вот решение с данными.таблица:
library(data.table) df lt;- 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 lt;- 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
Комментарии:
1. Это выглядит великолепно! Спасибо. Мне это нравится. Функция SDcols. Я начал чаще использовать Reduce, и это отличный инструмент. Работает как по волшебству. Просто теперь нужно лучше разбираться в синтаксисе data.table. Ура!
Ответ №3:
Различные способы сделать это:
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
Комментарии:
1. Спасибо Оньямбу, очень элегантно. Ваше решение похоже на решение Брайана. Просто любопытно, что это за функция list2DF ()? Работает ли это аналогично cbind()? Требуется ли для этого список в качестве входных данных? Меня это интересует. Ура!