簡體   English   中英

在SAS中匯總實際年份

[英]Aggregating Over Actual Year in SAS

假設我們有下表(“購買”):

Date                 Units_Sold             Brand       Year
18/03/2010                5                   A         2010
12/04/2010                2                   A         2010
22/05/2010                1                   A         2010
25/05/2010                7                   A         2010
11/08/2011                5                   A         2011
12/07/2010                2                   B         2010
22/10/2010                1                   B         2010
05/05/2011                7                   B         2011

對於不同品牌,同樣的邏輯一直持續到2014年底。

我想做的是計算每年每個品牌的Units_Sold數量。 但是,我不想在日歷年中執行此操作,而是在實際年份中執行此操作。

所以我想要的一個例子:

proc sql;
create table Dont_Want as
select Year, Brand, sum(Units_Sold) as Unit_per_Year
from Purchases
group by Year, Brand;
quit;

如果我們知道例如品牌“ A”在整個2010年都存在,則上述邏輯是可以的。但是,如果品牌“ A”第一次出現在18/03/2010並一直存在到現在,則可以比較2010年和2011年將不夠好,因為2010年我們將“短缺” 3個月。

所以我想做的是計算:

對於A:從18/03/2010到17/03/2011,然后從18/03/2011到17/03/2012的總和,依此類推。

B:從2010年12月7日至2011年7月11日的總和,依此類推。

以此類推。

有這樣做的聰明方法嗎?

第1步:確保按品牌和日期對數據集進行排序或編制索引

proc sort data=want;
     by brand date;
run;

步驟2:計算每種產品的開始/結束日期

下面的代碼背后的想法:

  1. 我們知道品牌在分類數據集中的首次出現是品牌被引入的日期。 我們將其稱為Product_Year_Start

  2. intnx函數可用於將該日期增加365天,然后從中減去1。 我們將此日期稱為Product_Year_End

  3. 由於我們現在知道產品的年末日期,因此我們知道,如果任何給定行上的日期都超過產品的年末日期,那么我們就開始下一個產品年。 我們只計算該品牌的Product_Year_EndProduct_Year_Start ,並將它們提高一年。

所有這些都是通過按組處理和retain語句來實現的。

data Comparison_Dates;
    set have;
    by brand date;

    retain Product_Year_Start Product_Year_End;

    if(first.brand) then do;
        Product_Year_Start = date;
        Product_Year_End = intnx('year', date, 1, 'S') - 1;
    end;

    if(Date > Product_Year_End) then do;
        Product_Year_Start = intnx('year', Product_Year_Start, 1, 'S');
        Product_Year_End = intnx('year', Product_Year_End, 1, 'S');
    end;

    format Product_Year_Start Product_Year_End date9.;
run;

步驟3:使用原始的SQL代碼,按新產品的開始/結束日期分組

proc sql;
    create table want as
    select catt(year(Product_Year_Start), '-', year(Product_Year_End) ) as Product_Year
         , Brand
         , sum(Units_Sold) as Unit_per_Year
    from Comparison_Dates
    group by Brand, calculated Product_Year
    order by Brand, calculated Product_Year;
quit;

下面的代碼按照字面意義進行操作,對於每個“品牌”的最早“日期”,它開始聚合“單位銷售”,當達到365天標記時,它將重置計數,並開始另一個周期。

data have;
    informat date ddmmyy10.;
    input date units_sold brand $ year;
    format date date9.;
    cards;
18/03/2010                5                   A         2010
12/04/2010                2                   A         2010
22/05/2010                1                   A         2010
25/05/2010                7                   A         2010
11/08/2011                5                   A         2011
12/07/2010                2                   B         2010
22/10/2010                1                   B         2010
05/05/2011                7                   B         2011
;

proc sort data=have;
    by brand date;
run;

data want;
    do until (last.brand);
        set have;
        by brand date;

        if first.brand then
            do;
                Sales_Over_365=0;
                _end=intnx('day',date,365);
            end;

        if date <= _end then
            Sales_Over_365+units_sold;
        else
            do;
                output;
                Sales_Over_365=units_sold;
                _end=intnx('day',date,365);
            end;
    end;

    output;
    drop _end;
run;

您需要每個品牌的開始日期。 目前,我們可以使用第一個銷售日期,但這可能不是您想要的。 然后,您可以將每個銷售日期分類為該品牌的年份。

讓我們從樣本數據創建數據集開始。 不需要YEAR變量。

data have ;
  input Date Units_Sold Brand $ Year ;
  informat date ddmmyy10.;
  format date yymmdd10.;
cards;
18/03/2010 5 A 2010
12/04/2010 2 A 2010
22/05/2010 1 A 2010
25/05/2010 7 A 2010
11/08/2011 5 A 2011
12/07/2010 2 B 2010
22/10/2010 1 B 2010
05/05/2011 7 B 2011
;;;;

現在,我們可以通過SQL查詢獲得所需的答案。

proc sql ;
  create table want as
   select brand
        , start_date
        , 1+floor((date - start_date)/365) as sales_year
        , intnx('year',start_date,calculated sales_year -1,'same')
            as start_sales_year format=yymmdd10.
        , sum(units_sold) as total_units_sold
  from
  ( select brand
        , min(date) as start_date format=yymmdd10.
        , date
        , units_sold
    from have
    group by 1
   )
  group by 1,2,3,4
  ;
quit;

這將產生以下結果:

                                               total_
                       sales_      start_      units_
Brand    start_date     year     sales_year     sold
  A      2010-03-18       1      2010-03-18      15
  A      2010-03-18       2      2011-03-18       5
  B      2010-07-12       1      2010-07-12      10

沒有直接的方法可以做到這一點。 你可以做這樣的事情。

為了測試代碼,我將您的表保存到一個文本文件中。

然后,我創建了一個名為Sale的類。

public class Sale
{
    public DateTime Date { get; set; }
    public int UnitsSold { get; set; }
    public string Brand { get; set; }
    public int Year { get; set; }
}

然后,使用保存的文本文件填充List<Sale>

var lines = File.ReadAllLines(@"C:\Users\kosala\Documents\data.text");
var validLines = lines.Where(l => !l.Contains("Date")).ToList();//remove the first line.

List<Sale> sales = validLines.Select(l => new Sale()
        {
            Date = DateTime.Parse(l.Substring(0,10)),
            UnitsSold = int.Parse(l.Substring(26,5)),
            Brand = l.Substring(46,1),
            Year = int.Parse(l.Substring(56,4)),
        }).ToList();

//All the above code is for testing purposes. The actual code starts from here.
var totalUnitsSold = sales.OrderBy(s => s.Date).GroupBy(s => s.Brand);

        foreach (var soldUnit in totalUnitsSold)
        {
            DateTime? minDate = null;
            DateTime? maxDate = null;
            int total = 0;
            string brand = "";

            foreach (var sale in soldUnit)
            {
                brand = sale.Brand;
                if (minDate == null)
                {
                    minDate = sale.Date;
                }
                if ((sale.Date - minDate).Value.Days <= 365)
                {
                    maxDate = sale.Date;
                    total += sale.UnitsSold;
                }
                else
                {
                    break;
                }
            }
            Console.WriteLine("Brand : {0} UnitsSold Between {1} - {2} is {3}",brand, minDate.Value, maxDate.Value, total);
   }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM