简化包含多个ifelse语句的重复性代码

时间:2016-11-21 20:36:36

标签: r loops if-statement

我正在考虑一项潜在的政策变更,允许组织(OrgID)在符合特定条件的情况下花费现有的补助金。数据是三列,这里是前六行:

 OrgID  Amount  Group
1     1 5782457 Group1
2     2 2280221 Group3
3     3 3260741 Group4
4     4 3869420 Group1
5     5 3950578 Group1
6     6 2058883 Group2

这将每年发生一次,条件取决于组织所在的组(Group)及其当前余额(Amount)。具体地,

  

Group = Group1
    - 如果Amount为500,000美元或更低,则所有资金都可用于支付     - 如果Amount超过500,000美元,则可以花费50%的资金。

     

Group = Group2
    - 如果Amount为$ 300,000或更低,则所有资金都可用于支付     - 如果Amount超过$ 300,000,则可以花费30%的资金。

     

Group = Group3
    - 如果Amount为100,000美元或更低,则所有资金都可用于支付     - 如果Amount大于$ 100,000,则可以花费10%的资金。

     

Group = Group4
    - 在任何条件下都不能花钱。

我想知道未来五年每年剩余的总金额,所以我转向dplyr软件包并写了以下内容:

mydata <-
    mydata %>%
    mutate(ReleaseOne =
               ifelse(Group == "Group1",
                      ifelse(Amount <= 500000, Amount,
                             round(Amount*0.50, 2)),
                      ifelse(Group == "Group2",
                             ifelse(Amount <= 300000, Amount,
                                    round(Amount*0.30, 2)),
                             ifelse(Group == "Group3",
                                    ifelse(Amount <= 100000, Amount,
                                           round(Amount*0.10, 2)), 0)))) %>%
    mutate(RemainOne =
               Amount - ReleaseOne)
...
mydata <-
    mydata %>%
    mutate(ReleaseFive =
               ifelse(Group == "Group1",
                      ifelse(RemainFour <= 500000, RemainFour,
                             round((RemainFour)*0.50, 2)),
                      ifelse(Group == "Group2",
                             ifelse(RemainFour <= 300000, RemainFour,
                                    round((RemainFour)*0.30, 2)),
                             ifelse(Group == "Group3",
                                    ifelse(RemainFour <= 100000, RemainFour,
                                           round((RemainFour)*0.10, 2)), 0)))) %>%
    mutate(RemainFive =
               RemainFour - ReleaseFive)

因此,我只重复了相同的代码块五次,但每次我更改以&#34; Release&#34;开头的变量的名称。和&#34;保持&#34; (即RemaimOneRemainTwoReleaseOneReleaseTwo等。)

这样做很好但是很乱。有没有办法使用自定义函数简化此操作,例如可能包括forwhile循环?

此外,知道在第1,2和3组中的所有组织达到Amount = 0之前将会有多少年是有价值的。但是,我知道如何做的唯一方法是不断重复上述内容,直到金额达到零。

数据名为mydata.txt,可以在this link的GitHub上找到。

2 个答案:

答案 0 :(得分:1)

您可以创建一个单独的数据框以与 -

进行比较
grp_data <- data.frame("Group" = c("Group1", "Group2", "Group3", "Group4"),
                       "threshold" = c(500000,300000,100000,0),
                       "percent" = c(0.5, 0.3, 0.1, 0))
mydata$allowed <- sapply(seq(nrow(mydata)), function(x)
                         {
                          ifelse(mydata[x, "Amount"] >= 
                                 grp_data[grp_data$Group == mydata[x, "Group"], "threshold"],
                                 grp_data[grp_data$Group == mydata[x, "Group"], "percent"] * mydata[x, "Amount"],
                                 mydata[x, "Amount"])
                         })

答案 1 :(得分:0)

这里有一个小功能应该可以解决问题 - 我也做了一些更通用的功能。它没有圆,但我确定你可以编辑它,如果你喜欢。

extrap = function(data,
                  threshhold = c(5e5, 3e5, 1e5, 0),
                  below = c(1, 1, 1, 1),
                  above = c(.5, .3, .1, 0),
                  n = 4) {
    res = list()
    x = data$Amount
    g = as.numeric(data$Group)
    for (i in 1:n) {
        x = x * above[g] ^ (x > threshhold[g]) * below[g] ^ (x <= threshhold[g])
        res[[i]] = x
    }
    names(res) = paste0("Release_", 1:n)
    return(bind_cols(data, res))
}

在您在问题中分享的数据的head上运行它:

extrap(dd)
#   OrgID  Amount  Group Release_1  Release_2 Release_3 Release_4
# 1     1 5782457 Group1 2891228.5 1445614.25 722807.12 361403.56
# 2     2 2280221 Group3  228022.1   22802.21  22802.21  22802.21
# 3     3 3260741 Group4       0.0       0.00      0.00      0.00
# 4     4 3869420 Group1 1934710.0  967355.00 483677.50 483677.50
# 5     5 3950578 Group1 1975289.0  987644.50 493822.25 493822.25
# 6     6 2058883 Group2  617664.9  185299.47 185299.47 185299.47

它依赖于数据框中的Groupfactor,并且threshholdbelowabove输入向量对应于级别Group因子。为了使它更通用,我添加了一个below向量,在你的情况下总是0?我对Group4感到有些困惑,可能above值应为1?我会把详细信息留给你。