从特定列开始,然后根据R中的条件遍历到特定数目的列

时间:2019-03-12 08:53:29

标签: r dplyr tidyr

我以宽格式获得以下数据,其中每一行代表一个展示厅,“季度”是该展示厅从哪个季度开始销售的,“开始年份”是“开始财务年度”。

Code    Quarter StartingYear Quarter1_Num.FY16-17 Quarter2_Num.FY16-17 Quarter3_Num.FY16-17 Quarter4_Num.FY16-17 Quarter1_Num.FY17-18 Quarter2_Num.FY17-18 Quarter3_Num.FY17-18 Quarter4_Num.FY17-18 
S2249       2   FY16-17         0                       23                  0                   0                   2                       0                   6                   0
S463        3   FY17-18         0                       0                   4                   0                   0                       4                   90                  8                                                                               

对于每个代理,我必须从基于季度和起始年份的列开始(第1行为Quarter2_Num.FY16-17),并涵盖一年的时间,在这种情况下,这意味着为Quarter2_Num.FY17-18。 可以看出,列名称基于Quarter和StartingYear。

我想得到的输出:

Code    Quarter1_Starting_Num Quarter2_Starting_Num Quarter3_Starting_Num Quarter4_Starting_Num Quarter5_Starting_Num
S2249       23                  0                       0                   2                       0
S463        4                   0                       0                   4                       90  

这些列捕获陈列室启动后每个季度中一年的数据。

我知道使用gsub可以获得包含FY16-17或FY17-18的列。 但是我不确定如何为每行指定起始列,然后再对N行进行遍历。

有人可以帮我吗?

1 个答案:

答案 0 :(得分:1)

首先,我们将数据集从宽到长传输,然后进行计算和过滤,最后将其转换回宽格式。

library(dplyr)
library(tidyr)
gather(df, k,val,-c(Code,Quarter,StartingYear)) %>% 
mutate(Quar=gsub('Quarter(\\d)_.*','\\1',k),year=gsub('Quarter\\d_Num\\.(.*)\\.(.*)','\\1-\\2',k)) %>% 
arrange(Code) %>% group_by(Code) %>% 
mutate(flag=cumsum(cumsum(Quarter==Quar & StartingYear==year)), Quarter1=paste0('Quarter',flag,'_Starting_Num')) %>% 
filter(between(flag,1,5)) %>% select(Code,Quarter1,val) %>% spread(Quarter1,val)

# A tibble: 2 x 6
# Groups:   Code [2]
   Code  Quarter1_Starting_Num Quarter2_Starting_Num Quarter3_Starting_Num Quarter4_Starting_Num Quarter5_Starting_Num
  <fct>                 <int>                 <int>                 <int>                 <int>                 <int>
1 S2249                    23                     0                     0                     2                     0
2 S463                      4                     0                     0                     4                    90

数据

df <- structure(list(Code = structure(1:2, .Label = c("S2249", "S463"
), class = "factor"), Quarter = 2:3, StartingYear = structure(c(1L, 
1L), .Label = "FY16-17", class = "factor"), Quarter1_Num.FY16.17 = c(0L, 
0L), Quarter2_Num.FY16.17 = c(23L, 0L), Quarter3_Num.FY16.17 = c(0L, 
4L), Quarter4_Num.FY16.17 = c(0L, 0L), Quarter1_Num.FY17.18 = c(2L, 
0L), Quarter2_Num.FY17.18 = c(0L, 4L), Quarter3_Num.FY17.18 = c(6L, 
90L), Quarter4_Num.FY17.18 = c(0L, 8L)), class = "data.frame", row.names = c(NA, 
-2L))

PS:我将S463 3 FY17-18更改为S463 3 FY16-17以匹配预期的输出,您可以保留S463 3 FY17-18,但您会获得从Q3到Q5的NAs。

gsub('Quarter(\\d)_.*','\\1',c('Quarter1_Num.FY16.17','Quarter4_Num.FY17.18'))
[1] "1" "4"

  • 'Quarter(\\d)_.*'将一位数字分组,即在Quarter之后和_之前的1-9,并使用\\1

    返回该组
    gsub('Quarter\\d_Num\\.(.*)\\.(.*)','\\1-\\2',c('Quarter1_Num.FY16.17','Quarter4_Num.FY17.18'))
    [1] "FY16-17" "FY17-18"
    

  • \\.在“ Quarter”之后跳过原义的点,后跟digit_Num。在正则表达式中,我们使用.跳过诸如\\之类的特殊字符    
  • (.*)将点之后和下一个点之前的所有内容分组,即2016财年和2017财年。 gsub会将其视为第1组    
  • \\.跳过文字点    
  • (.*)将点后的任何内容归为一组,即17和18,gsub会将其视为组2    
  • \\1-\\2返回由-隔开的第1组和第2组,即2016-17财年