在数据帧的每一行中应用条件函数

时间:2019-04-22 20:18:24

标签: r

我是R语言的新手,并且正在为此看起来像这样的df挣扎:

Date      Group       Factor 1 Factor 2 Spread
2019-04-01  a   1.01    1.011   0.01
2019-04-02  a   1.02    1.012   0.02
2019-04-03  a   1.03    1.013   0.03
2019-04-01  b   1.005   1.004   0.01
2019-04-02  b   1.0051  1.0041  0.02
2019-04-03  b   1.0052  1.0042  0.03

我想验证每行中的每个组,如果结果是“ a”组,则执行Factor1 / Factor1(1天滞后)* Factor2 +价差,如果不是“ a”组,则不添加价差

1 个答案:

答案 0 :(得分:0)

由于您以小组为条件,所以这是by(以R为底),dplyr::group_bydata.table的{​​{1}}的一个很好的例子。

等式实际上在所有三个等式中都是相同的,这是利用x[,,by=]乘以一个数字时将从(Group[1] == "a")强制到logical的事实。因为numeric转换为0,所以实际上禁止添加FALSE

基本

我在这里使用Spread来使内部结构更具可读性,但这不是必须的(在这种情况下,您需要在所有变量名之前加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特定的格式,因此您可以将其视为以有效的base-R方式将它们组合在一起的方式:

by

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更好,因为就地修改可提高效率(R的大多数操作都是写时复制,这意味着某些操作会重新复制对象或对象的一部分每次更改)。

data.table

“就地”部分在第二行很明显,似乎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 操作应该只返回一个子集或某些数据……但在这种情况下使用{{ 1}}导致就地创建(或更改)列。