根据其他列的条件创建新列

时间:2016-11-14 07:04:44

标签: r breakpoints

原始数据如下所示,

Year   Price    Volume   P1    P2    P3   V1    V2    V3
2009    46       125     25    50    75   200   400   600
2009    65       800     25    50    75   200   400   600
2010    20       560     30    55    90   250   500   800
2010    15       990     30    55    90   250   500   800
2011    89       350     35    70    120  250   500   800
2012    23       100     35    70    120  250   500   800
...     ...      ...     ...   ...   ...  ...   ...   ...

我尝试创建一个名为" Portfolio"的新列。如果Price和Volume分别小于P1和V1,则Portfolio等于11.然后,如果除了Price小于P1但Volume小于V2,则Portfolio等于12,依此类推。 Price和Volume共有3个断点。因此,创建了16个投资组合,分别命名为11,12,13,14,21,22,23,24,...,44。 结果如下表所示

Year   Price    Volume   P1    P2    P3   V1    V2    V3   Portfolio
2009    46       125     25    50    75   200   400   600    21
2009    65       800     25    50    75   200   400   600    34
2010    20       560     30    55    90   250   500   800    13
2010    15       990     30    55    90   250   500   800    14
2011    89       350     35    70    120  250   500   800    32
2012    23       100     35    70    120  250   500   800    11
...     ...      ...     ...   ...   ...  ...   ...   ...    ...
你可以帮我解决这个问题。我试过if(){}和if if(){}函数。但是,我没有得到第二个表的结果。这就是我在这里发布原始数据的原因。非常感谢。

我尝试的代码如下,

if ((Price<P1)&&(Volume<V1)){data$Portfolio=11}
else if ((Price<P1)&&(Volume<V2)){data$Portfolio=12}
else if((Price<P1)&&(Volume<V3)){data$Portfolio=13}
else if(Price<P1){data$Portfolio=14}
else if((Price<P2)&&(Volume<V1)){Fin_Ret$port=21}
...
else if(Price>P3){data$Portfolio=44}

输出是,

> if ((Price<P1)&&(Volume<V1)){data$Portfolio=11}
> else if ((Price<P1)&&(Volume<V2)){data$Portfolio=12}
Error: unexpected 'else' in "else"
...

当我尝试&#34;&amp;&#34;而不是&amp;&amp;&#34;,结果显示,

> if ((mkvalt<MV20)&(BM<BM20)){Fin_Ret$port=11}
Warning message:
In if ((mkvalt < MV20) & (BM < BM20)) { :
the condition has length > 1 and only the first element will be used

我很困惑也许我不理解R中的基本事物。

3 个答案:

答案 0 :(得分:0)

您可以使用:

df$Portfolio[(df$Price<df$P1)&(df$Volume<df$V1)] <- 11
df$Portfolio[(df$Price<df$P1)&(df$Volume<df$V2) & is.na(df$Portfolio)] <- 12

或使用dplyr :: mutate

library(dplyr)
df <- df %>% 
        mutate(Portfolio=ifelse((Price<P1)&(Volume<V1),11,NA)) %>% 
        mutate(Portfolio=ifelse((Price<P1)&(Volume<V2)& is.na(Portfolio),12,Portfolio))

答案 1 :(得分:0)

在您提供的代码中,

else if(Price<P1){data$Portfolio=14}
else if((Price<P2)&&(Volume<V1)){Fin_Ret$port=21}
...
else if(Price>P3){data$Portfolio=44}

在最后一行if后删除else。你应该能够得到预期的结果。

答案 2 :(得分:0)

以下是使用findIntervaldata.table的不同简洁方法。它基于以下观察:Portfolio id由两个数字组成,其中第一个数字仅由价格类别决定,第二个数字仅由数量类别决定。

library(data.table)
dt[, Portfolio := paste0(findInterval(Price, c(-Inf, P1, P2, P3)), 
                         findInterval(Volume, c(-Inf, V1, V2, V3))),
   by = .(P1, P2, P3, V1, V2, V3)]

print(dt)
#   Year Price Volume P1 P2  P3  V1  V2  V3 Portfolio
#1: 2009    46    125 25 50  75 200 400 600        21
#2: 2009    65    800 25 50  75 200 400 600        34
#3: 2010    20    560 30 55  90 250 500 800        13
#4: 2010    15    990 30 55  90 250 500 800        14
#5: 2011    89    350 35 70 120 250 500 800        32
#6: 2012    23    100 35 70 120 250 500 800        11
默认情况下,

findInterval使用正确的开放时间间隔,这与OP的代码中的条件(Price<P1)等一致。

数据

使其成为可重现的例子

dt <- fread("Year   Price    Volume   P1    P2    P3   V1    V2    V3
            2009    46       125     25    50    75   200   400   600
            2009    65       800     25    50    75   200   400   600
            2010    20       560     30    55    90   250   500   800
            2010    15       990     30    55    90   250   500   800
            2011    89       350     35    70    120  250   500   800
            2012    23       100     35    70    120  250   500   800")