Поскольку вы тренируете группу, это хороший пример by
(база R), dplyr::group_by
или data.table
* x[,,by=]
.
Уравнение эффективното же самое во всех трех, используя тот факт, что (Group[1] == "a")
будет приведен от logical
до numeric
при умножении на число;поскольку FALSE
переводит в 0, то фактически отключается, добавляя Spread
.
Base
Я использую within
здесь, чтобы сделать внутреннюю часть немного более читабельной, но это нетребование (в этом случае вам нужно будет добавить x$
перед всеми именами переменных).
Отставание может быть сделано с помощью dplyr::lag
(даже если вы не используете остальныепакет для этого) или многие другие методы.Я не считаю stats::lag
наиболее интуитивным в подобных приложениях, но я уверен, что кто-нибудь предложит способ включить его в ответ.Использование c(NA, ...)
гарантирует, что мы не будем вводить данные другой группы или вменять данные, которых у нас нет, поскольку у нас нет никакой ценности вводить в первый ряд группы.Наконец, head(..., n = 1)
возвращает первый элемент вектора / списка, а head(..., n = -1)
(отрицательный) возвращает все, кроме последнего .
newx <- by(x, x$Group, function(y) {
within(y, {
NewVal = Factor2 * Factor1 / c(NA, head(Factor1, n=-1)) + (Group[1] == "a") * Spread
})
})
newx
# x$Group: a
# Date Group Factor1 Factor2 Spread NewVal
# 1 2019-04-01 a 1.01 1.011 0.01 NA
# 2 2019-04-02 a 1.02 1.012 0.02 1.042020
# 3 2019-04-03 a 1.03 1.013 0.03 1.052931
# -------------------------------------------------------
# x$Group: b
# Date Group Factor1 Factor2 Spread NewVal
# 4 2019-04-01 b 1.0050 1.0040 0.01 NA
# 5 2019-04-02 b 1.0051 1.0041 0.02 1.0042
# 6 2019-04-03 b 1.0052 1.0042 0.03 1.0043
Это действительно просто list
с каким-то необычным by
-специфическим форматированием, так что вы можете рассматривать его как таковое или комбинировать их эффективным способом base-R:
do.call("rbind.data.frame", c(newx, stringsAsFactors = FALSE))
# Date Group Factor1 Factor2 Spread NewVal
# a.1 2019-04-01 a 1.0100 1.0110 0.01 NA
# a.2 2019-04-02 a 1.0200 1.0120 0.02 1.042020
# a.3 2019-04-03 a 1.0300 1.0130 0.03 1.052931
# b.4 2019-04-01 b 1.0050 1.0040 0.01 NA
# b.5 2019-04-02 b 1.0051 1.0041 0.02 1.004200
# b.6 2019-04-03 b 1.0052 1.0042 0.03 1.004300
dplyr
Многие находятtidyverse
Линия пакетов для интуитивного чтения.
library(dplyr)
x %>%
group_by(Group) %>%
mutate(NewVal = Factor2 * Factor1 / lag(Factor1) + (Group[1] == "a") * Spread) %>%
ungroup()
# # A tibble: 6 x 6
# Date Group Factor1 Factor2 Spread NewVal
# <chr> <chr> <dbl> <dbl> <dbl> <dbl>
# 1 2019-04-01 a 1.01 1.01 0.01 NA
# 2 2019-04-02 a 1.02 1.01 0.02 1.04
# 3 2019-04-03 a 1.03 1.01 0.03 1.05
# 4 2019-04-01 b 1.00 1.00 0.01 NA
# 5 2019-04-02 b 1.01 1.00 0.02 1.00
# 6 2019-04-03 b 1.01 1.00 0.03 1.00
data.table
С другой стороны, многие находят data.table
лучше из-за эффективности, получаемой от модификации на месте (большинствоиз операций R являются копированием при записи, что означает, что некоторые операции повторно копируют объект или его часть при каждом изменении).
library(data.table)
X <- as.data.table(x)
X[, NewVal := Factor2 * Factor1 / shift(Factor1) + (Group[1] == "a") * Spread, by = "Group"]
X
# Date Group Factor1 Factor2 Spread NewVal
# 1: 2019-04-01 a 1.0100 1.0110 0.01 NA
# 2: 2019-04-02 a 1.0200 1.0120 0.02 1.042020
# 3: 2019-04-03 a 1.0300 1.0130 0.03 1.052931
# 4: 2019-04-01 b 1.0050 1.0040 0.01 NA
# 5: 2019-04-02 b 1.0051 1.0041 0.02 1.004200
# 6: 2019-04-03 b 1.0052 1.0042 0.03 1.004300
Часть «на месте» видна во второй строкездесь, где это выглядит так, как будто операция [
должна просто возвращать подмножество или что-то из данных ... но в этом случае использование :=
вызывает создание (или изменение) столбцов на месте.