有效地将三次样条拟合到大型数据集

时间:2014-07-07 18:32:38

标签: sas

这是我的另一个问题的后续问题,Efficiently fitting cubic splines in SAS to specific grid of objects - 以前的解决方案有效,但效果不如我想象的那么高。

此代码的目的是按组对特定范围的对象变量IV插入图像MNES的值,并对结果值执行操作。

我的数据集如下:

MEMBID    DATE  MNES     IV
     1   13152  0.84   0.40
     1   13152  0.89   0.34
     1   13152  0.91   0.31
     1   13152  0.93   0.29
     1   13152  0.95   0.26
     1   13152  0.98   0.23
     1   13152  0.99   0.22
     1   13152  1.00   0.22
     1   13152  1.02   0.20
     1   13152  1.04   0.18
     1   13152  1.07   0.18
     ...
     4   13172  0.89   0.24
     4   13172  0.94   0.20
     4   13172  0.97   0.19
     4   13172  1.01   0.19
     4   13172  1.04   0.20
     4   13172  1.07   0.21
     4   13172  1.15   0.23
     4   13172  1.17   0.24
     ...

每个MEMBIDDATE组合都是按组的。从视角来看,我应该有大约两百万个小组。

通过将三次样条拟合到现有的IV - MNES对,应使用每个分组来估算100 IV网格的MNES 。这个网格从1/3变为3并且不是线性的,而是估计如下(这与我正在应用的方法有关 - graphically):

%let m = 500;
%let k = 2;
%let u = (1+&k) ** (1/&m);
data splined(keep=mnes);
    do grid=-500 to 500;
        mnes = (&u) ** grid;
    end;
run;

然后通过计算每行的选项价格并按组分别对该特定函数求和,将每个分组合成为单个数字。考虑到结果数据集的体积(即1001个网格对象×2百万个组= 20亿行),我不知道是否一次性完成所有这一切 - 但循环似乎并不聪明。

我一次又一次地研究过,从我收集的内容中,有几种内置工具可用于估算SAS中的三次样条:

  • BASE SAS通过MSPLINT功能实现了这一功能。虽然我实现了这个(请参阅上一篇文章,可选),但它要求我使用大量的宏循环,因为它要求我在宏中单独指定每个组的MNESIV变量,通过使用逗号分隔列表。在循环中进行200万次迭代远非一个好主意 - 在我当前的实现中花了太长时间;
  • SAS / IML允许通过splinec和splinev函数实现这一点,并且我已成功实现了这一点(参见上一篇文章,可选)但IML似乎并不适合处理200万个组;
  • SAS / ETS允许通过PROC EXPAND拟合三次样条曲线 - 但是,PROC EXPAND需要ID变量的时间序列和整数值。这与我的数据完全不兼容,因为MNES是十进制的并且需要具有特定数量的步骤(不能近似为整数);
  • 通过使用可用的样条转换,SAS / STAT允许通过PROC TRANSREG(这是我的最后手段,但它似乎也是最有希望的)拟合三次样条。它甚至通过组处理支持。它输出非常好看的图,但我无法理解如何获得我需要的特定网格的输出数据集。或者,我想获得样条曲线的参数并估算网格"手动" - 但这似乎不可能。如果我只适合三度polinoomial,那么我可以得到参数(通过out = coef选项),但如果我想要一个实际的样条曲线则不行。

如果你不知道三次样条曲线是如何工作的,那么paper就会用非常简单的术语来解释它。

我已经彻底研究过这个问题,但我没有答案。我很欣赏有关如何有效地自动化此过程的任何建议。谢谢。

在@Joe的评论之后,这里有5个小组的数据集。我已经简化了网格参数,只有m = 5,因此每组11个点。 (请注意,我在havewant中删除了一些小数位以改进演示。)

have

membid       date    days     iv    mnes
    -1  04JAN1996     365   0.15    0.91
    -1  04JAN1996     365   0.14    0.94
    -1  04JAN1996     365   0.14    0.96
    -1  04JAN1996     365   0.13    0.98
    -1  04JAN1996     365   0.13    1.00
    -1  04JAN1996     365   0.13    1.02
    -1  04JAN1996     365   0.12    1.04
    -1  04JAN1996     365   0.12    1.06
    -1  04JAN1996     365   0.12    1.08
    -1  04JAN1996     365   0.11    1.09
    -1  04JAN1996     365   0.11    1.11
    -1  04JAN1996     365   0.11    1.13
    -1  05JAN1996     365   0.15    0.91
    -1  05JAN1996     365   0.14    0.94
    -1  05JAN1996     365   0.14    0.96
    -1  05JAN1996     365   0.13    0.98
    -1  05JAN1996     365   0.13    1.00
    -1  05JAN1996     365   0.13    1.02
    -1  05JAN1996     365   0.12    1.04
    -1  05JAN1996     365   0.12    1.06
    -1  05JAN1996     365   0.12    1.08
    -1  05JAN1996     365   0.11    1.09
    -1  05JAN1996     365   0.11    1.11
    -1  05JAN1996     365   0.11    1.13
    -1  08JAN1996     365   0.14    0.91
    -1  08JAN1996     365   0.14    0.94
    -1  08JAN1996     365   0.13    0.96
    -1  08JAN1996     365   0.13    0.98
    -1  08JAN1996     365   0.12    1.00
    -1  08JAN1996     365   0.12    1.02
    -1  08JAN1996     365   0.13    1.04
    -1  08JAN1996     365   0.12    1.06
    -1  08JAN1996     365   0.12    1.08
    -1  08JAN1996     365   0.12    1.10
    -1  08JAN1996     365   0.11    1.11
    -1  08JAN1996     365   0.11    1.13
    -1  09JAN1996     365   0.15    0.91
    -1  09JAN1996     365   0.14    0.94
    -1  09JAN1996     365   0.14    0.96
    -1  09JAN1996     365   0.14    0.98
    -1  09JAN1996     365   0.13    1.00
    -1  09JAN1996     365   0.13    1.02
    -1  09JAN1996     365   0.12    1.04
    -1  09JAN1996     365   0.12    1.06
    -1  09JAN1996     365   0.12    1.08
    -1  09JAN1996     365   0.11    1.09
    -1  09JAN1996     365   0.11    1.11
    -1  09JAN1996     365   0.11    1.13
    -1  10JAN1996     365   0.15    0.91
    -1  10JAN1996     365   0.15    0.94
    -1  10JAN1996     365   0.14    0.96
    -1  10JAN1996     365   0.14    0.98
    -1  10JAN1996     365   0.13    1.00
    -1  10JAN1996     365   0.13    1.02
    -1  10JAN1996     365   0.13    1.05
    -1  10JAN1996     365   0.12    1.06
    -1  10JAN1996     365   0.12    1.08
    -1  10JAN1996     365   0.12    1.10
    -1  10JAN1996     365   0.12    1.12
    -1  10JAN1996     365   0.11    1.14

want

grid    membid     date    days      mnes         iv
  -5        -1    13152     365    0.3333    0.15207 
  -4        -1    13152     365    0.4152    0.15207 
  -3        -1    13152     365    0.5172    0.15207 
  -2        -1    13152     365    0.6443    0.15207 
  -1        -1    13152     365    0.8027    0.15207 
   0        -1    13152     365    1         0.13631 
   1        -1    13152     365    1.2457    0.11354 
   2        -1    13152     365    1.5518    0.11354 
   3        -1    13152     365    1.9331    0.11354 
   4        -1    13152     365    2.4082    0.11354 
   5        -1    13152     365    3         0.11354 
  -5        -1    13153     365    0.3333    0.15217 
  -4        -1    13153     365    0.4152    0.15217 
  -3        -1    13153     365    0.5172    0.15217 
  -2        -1    13153     365    0.6443    0.15217 
  -1        -1    13153     365    0.8027    0.15217 
   0        -1    13153     365    1         0.135057
   1        -1    13153     365    1.2457    0.115   
   2        -1    13153     365    1.5518    0.115   
   3        -1    13153     365    1.9331    0.115   
   4        -1    13153     365    2.4082    0.115   
   5        -1    13153     365    3         0.115   
  -5        -1    13156     365    0.3333    0.14731 
  -4        -1    13156     365    0.4152    0.14731 
  -3        -1    13156     365    0.5172    0.14731 
  -2        -1    13156     365    0.6443    0.14731 
  -1        -1    13156     365    0.8027    0.14731 
   0        -1    13156     365    1         0.131243
   1        -1    13156     365    1.2457    0.11656
   2        -1    13156     365    1.5518    0.11656
   3        -1    13156     365    1.9331    0.11656
   4        -1    13156     365    2.4082    0.11656
   5        -1    13156     365    3         0.11656
  -5        -1    13157     365    0.3333    0.15556
  -4        -1    13157     365    0.4152    0.15556
  -3        -1    13157     365    0.5172    0.15556
  -2        -1    13157     365    0.6443    0.15556
  -1        -1    13157     365    0.8027    0.15556
   0        -1    13157     365    1         0.13881
   1        -1    13157     365    1.2457    0.11447
   2        -1    13157     365    1.5518    0.11447
   3        -1    13157     365    1.9331    0.11447
   4        -1    13157     365    2.4082    0.11447
   5        -1    13157     365    3         0.11447
  -5        -1    13158     365    0.3333    0.15920
  -4        -1    13158     365    0.4152    0.15920
  -3        -1    13158     365    0.5172    0.15920
  -2        -1    13158     365    0.6443    0.15920
  -1        -1    13158     365    0.8027    0.15920
   0        -1    13158     365    1         0.14023
   1        -1    13158     365    1.2457    0.11923
   2        -1    13158     365    1.5518    0.11923
   3        -1    13158     365    1.9331    0.11923
   4        -1    13158     365    2.4082    0.11923
   5        -1    13158     365    3         0.11923

使用以下代码生成want数据集。 optday是一个只有have数据集的一个副组的数据集(我使用proc sql和宏循环到#34;到达那里")。 contributionoption price是我需要的其他字段。

data _null_;
    set optday end=last;
    if _n_ = 1 then do;
        call symput("first1",mnes);
        call symput("first1_v",iv);
    end;
    if last then do;
        call symput("last1",mnes);
        call symput("last1_v",iv);
    end;
run;

proc sql noprint;
    select mnes into:mneslist
    separated by ','
    from optday;
    select iv into:IVlist
    separated by ','
    from optday;
    select count(*) into:countlist
    from optday;
quit;

data want;
    do grid=-500 to 500;
        membid = &currmembid;
        date = "&currdate"d;
        days = &currdays;
        mnes = (&u) ** grid;
        if mnes < &first1 then IV = &first1_v;
        if mnes > &last1 then IV = &last1_v;
        if mnes >= &first1 and mnes <= &last1 then IV = msplint(mnes, &countlist, &mneslist, &IVlist);
        if mnes < 1 then optionprice = BLKSHPTPRC(mnes,&currdays/365,1,&currrate/100,iv);
        else optionprice = BLKSHCLPRC(mnes,&currdays/365,1,&currrate/100,iv);
        contrib = (1-(log(1+&k)/(&m))*grid)*optionprice/(&u)**grid;
        output;
    end;
run;

请注意,本文中使用的网格机制取自Buss和Vilkov在Vilkov网站上公开提供的MATLAB代码,其中包含选项数据的免模型隐含度量:http://www.vilkov.net/www/content/code-and-useful-stuff

1 个答案:

答案 0 :(得分:0)

我能够解决这个问题,因此我正在分享我的解决方案。我相信它非常有效 - 它可以在3到4个小时内运行我需要的所有过程。我以前的估计是10天。

我按照以下步骤操作:

  1. 按图片,日期和天数排序have;
  2. 创建mnes网格,为iv提供缺失值;
  3. 将观察结果附加到该网格(此步骤可能效率低下,但我不知道如何操作datastep只在一个步骤中执行此操作);
  4. 按组排序信息;
  5. 按组应用PROC TRANSREG - 它假定已知mnes范围之外的常量值,并为剩余的遗漏值进行插值。
  6. 取出观察到的值,以便只剩下网格。
  7. 缺点:我无法动态指定我想在每个观察值处有一个样条线结。因此,我必须给出一定数量的结,并且它将在观察值之间平均分配它们。这使得已知mnes范围之外的值不是网格中的最终iv,而是另一个值。

    以下是我使用的代码,包含示例信息:

    data have;
        input membid date days iv mnes;
        datalines;
        1 1 365 0.15 0.91
        1 1 365 0.14 0.94
        1 1 365 0.14 0.96
        1 1 365 0.13 0.98
        1 1 365 0.13 1.00
        1 1 365 0.13 1.02
        1 1 365 0.12 1.04
        1 1 365 0.12 1.06
        1 1 365 0.12 1.08
        1 1 365 0.11 1.09
        1 1 365 0.11 1.11
        1 1 365 0.11 1.13
        2 2 365 0.15 0.91
        2 2 365 0.14 0.94
        2 2 365 0.14 0.96
        2 2 365 0.13 0.98
        2 2 365 0.13 1.00
        2 2 365 0.13 1.02
        2 2 365 0.12 1.04
        2 2 365 0.12 1.06
        2 2 365 0.12 1.08
        2 2 365 0.11 1.09
        2 2 365 0.11 1.11
        2 2 365 0.11 1.13
         ;
    run;
    
    * Set model inputs;
    %let m = 500;
    %let k = 2;
    %let u = (1+&k) ** (1/&m);
    %let a = 2 * (&u-1);
    
    * Needed to sort data by groups;
    proc sort data=have;
        by membid date days mnes;
    run;
    
    * Create moneyness grid for each by group;
    data _splined;
        set have;
        by membid date days;
        if first.days then do grid=(-&m) to &m;
            mnes = (&u) ** grid;
            iv = .;
            output;
        end;
    run;
    
    * Append observations to generated moneyness grid;
    proc datasets nolist;
        append base=_splined
        data=have;
    quit;
    
    * Sort these, because first come the moneyness grids and then all the observations;
    proc sort data=_splined;
        by membid date days mnes;
    run;
    
    * Apply cubic splines with 10 equally spaced knots;
    proc transreg data=_splined short noprint;
        model identity(iv)=spline(mnes / nknots=10);
        output out=output1 p;
        by membid date days;
    run;
    
    * Delete initial observations - these are marked by proc transreg with _type_ = 'SCORE';
    data splined(keep=membid date days piv mnes);
        set output1(keep=membid date days _type_ piv mnes);
        if _type_ NE 'SCORE';
    run;
    

    如果您有任何疑问,请发表评论,我会尽力帮助您!

    请注意,本文中使用的网格机制取自Buss和Vilkov在Vilkov网站上公开提供的MATLAB代码,其中包含选项数据的免模型隐含度量:http://www.vilkov.net/www/content/code-and-useful-stuff