<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>风险均摊 on 格物堂</title><link>https://gewutang.cn/tags/%E9%A3%8E%E9%99%A9%E5%9D%87%E6%91%8A/</link><description>Recent content in 风险均摊 on 格物堂</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Sat, 08 Mar 2014 00:00:00 +0000</lastBuildDate><atom:link href="https://gewutang.cn/tags/%E9%A3%8E%E9%99%A9%E5%9D%87%E6%91%8A/index.xml" rel="self" type="application/rss+xml"/><item><title>善用向量化提升R语言的计算性能</title><link>https://gewutang.cn/2014/03/08/use-vectorisation-to-improve-computational-performance/</link><pubDate>Sat, 08 Mar 2014 00:00:00 +0000</pubDate><guid>https://gewutang.cn/2014/03/08/use-vectorisation-to-improve-computational-performance/</guid><description>&lt;p&gt;用R 语言用的久了，渐渐发现 R 语言的世界里有很多黑魔法。其中一个黑魔法是向量化运算。向量化运算可以说是R语言区别于其它语言的特质之一，善用向量化运算不仅能有效降低代码的冗余度，还能显著提升代码的运算效率。遗憾的是，很多接触过其它编程语言的人未能掌握这一特性使得他们经常诟病R语言运算效率低下。这里给看官们举个例子来体会下。&lt;/p&gt;&#10;&lt;p&gt;想必大家都遇到过替换向量元素的情况。比如，我们有下面这样一个数据框，维度是1200000×2：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt;n = 1200000&#10;df = data.frame(values = rnorm(n), &#10; ID = rep(LETTERS[1:3], each = n/3),&#10; stringsAsFactors = FALSE)&#10;head(df)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;pre&gt;&lt;code&gt;## values ID&#10;## 1 1.8442348 A&#10;## 2 -0.5089413 A&#10;## 3 -0.8743655 A&#10;## 4 0.7824285 A&#10;## 5 -1.2115204 A&#10;## 6 -1.4914611 A&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt;tail(df)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;pre&gt;&lt;code&gt;## values ID&#10;## 1199995 1.753660616 C&#10;## 1199996 -0.007581797 C&#10;## 1199997 -0.635219385 C&#10;## 1199998 -1.437210958 C&#10;## 1199999 -0.101465502 C&#10;## 1200000 0.152135010 C&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;假设要把&lt;em&gt;df$ID&lt;/em&gt;中的A替换为“A公司”，B和C类似。怎么做呢？一个常用的解决方案是利用if&amp;hellip;for写循环。代码是这样的：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt;translator_if_for = function(input_vector) {&#10; output_vector = input_vector&#10; for(index in seq_along(input_vector)) {&#10; if(input_vector[index] == 'A') {&#10; output_vector[index] = 'A公司'&#10; } else if(input_vector[index] == 'B') {&#10; output_vector[index] = 'B公司'&#10; } else if(input_vector[index] == 'C') {&#10; output_vector[index] = 'C公司'&#10; } &#10; } &#10; return(output_vector)&#10;}&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt;dum_if_for = translator_if_for(df$ID)&#10;head(dum_if_for)&#10;tail(dum_if_for)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;用&lt;code&gt;rbenchmark&lt;/code&gt;包测试下上述操作需要的时间：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt;library(rbenchmark)&#10;res = benchmark(if_for_solution = translator_if_for(df$ID),&#10; columns= c(&amp;quot;test&amp;quot;,&amp;quot;replications&amp;quot;,&amp;quot;elapsed&amp;quot;,&amp;quot;relative&amp;quot;,&amp;quot;user.self&amp;quot;,&amp;quot;sys.self&amp;quot;),&#10; replications = 10)&#10; res&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;pre&gt;&lt;code&gt; test replications elapsed relative user.self sys.self&#10;1 if_for_solution 10 69.63 1 69.48 0&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;上面这段代码的缺点是时间久，而且看起来一点都不简洁。那么，是否有更好点的解决方案呢？Absolutely！而且不止一种。比较常用的替代方案是借助 &lt;code&gt;apply&lt;/code&gt;族函数（&lt;code&gt;apply&lt;/code&gt;族函数是R语言中避免编写显式循环的一个trick）。在用&lt;code&gt;apply&lt;/code&gt;族函数之前，得先构造一个辅助函数。构造函数之前不妨先想想我们的操作逻辑，我们想做的事情是这样的，对于&lt;code&gt;df$ID&lt;/code&gt;中的某个元素，如果元素是A其就变成A公司，B变成B公司，C变成C公司。这其实可以用&lt;code&gt;switch&lt;/code&gt;来实现。对所有元素进行依次进行判断就可以了，针对所有元素进行判断这个过程可以交给&lt;code&gt;sapply&lt;/code&gt;函数来完成，于是有下面的代码：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt; translator_function = function(element) {&#10; switch(element,&#10; A = 'A公司',&#10; B = 'B公司',&#10; C = 'C公司')&#10; }&#10; &#10; dum_switch_sapply = sapply(df$ID, translator_function)&#10; head(dum_switch_sapply)&#10; tail(dum_switch_sapply)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;代码看起来更简洁，看看操作结果是否一致：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt;all.equal(dum_if_for, dum_switch_sapply, check.attributes = FALSE)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;看看这段代码需要的时间：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt; res = benchmark(function_solution = sapply(df$ID, translator_function),&#10; columns= c(&amp;quot;test&amp;quot;,&amp;quot;replications&amp;quot;,&amp;quot;elapsed&amp;quot;,&amp;quot;relative&amp;quot;,&amp;quot;user.self&amp;quot;,&amp;quot;sys.self&amp;quot;),&#10; replications = 10)&#10; res&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;pre&gt;&lt;code&gt; test replications elapsed relative user.self sys.self&#10;1 function_solution 10 64.58 1 64.1 0.24&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;可以看到时间也有所减少。But..这就是结束吗？操作效率是有提升，但提升的一点都不明显啊！？别急，我们还有杀手锏——向量化运算！先上代码，再慢慢解释逻辑。&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt; translator_vector = c(A = 'A公司',&#10; B = 'B公司',&#10; C = 'C公司')&#10; dum_vectorized = translator_vector[df$ID]&#10; head(dum_vectorized)&#10; tail(dum_vectorized)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;看看结果是否一样：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt;all.equal(dum_vectorized, dum_switch_sapply, check.attributes = FALSE)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;完全一样。但是看起来无疑简洁了很多。那么，从耗时角度讲呢？我们看一看：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt; res = benchmark(vector_solution = translator_vector[df$ID],&#10; columns= c(&amp;quot;test&amp;quot;,&amp;quot;replications&amp;quot;,&amp;quot;elapsed&amp;quot;,&amp;quot;relative&amp;quot;,&amp;quot;user.self&amp;quot;,&amp;quot;sys.self&amp;quot;),&#10; replications = 10)&#10; res&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;pre&gt;&lt;code&gt; test replications elapsed relative user.self sys.self&#10;1 vector_solution 10 1.13 1 1.06 0.03&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;时间大大减少了。把三种方案的耗时放到一起看一看：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt; res = benchmark(if_for_solution = translator_if_for(df$ID),&#10; function_solution = sapply(df$ID, translator_function),&#10; vector_solution = translator_vector[df$ID],&#10; columns= c(&amp;quot;test&amp;quot;,&amp;quot;replications&amp;quot;,&amp;quot;elapsed&amp;quot;,&amp;quot;relative&amp;quot;,&amp;quot;user.self&amp;quot;,&amp;quot;sys.self&amp;quot;),&#10; replications = 10)&#10; res&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;pre&gt;&lt;code&gt; test replications elapsed relative user.self sys.self&#10;2 function_solution 10 71.51 87.207 70.95 0.42&#10;1 if_for_solution 10 69.89 85.232 69.34 0.25&#10;3 vector_solution 10 0.82 1.000 0.75 0.08&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;向量化运算无论在代码简洁度还是在效率上完爆前两种方案。缺点是操作逻辑十分巧妙，可能不是那么容易理解。这里简单解释一下：&lt;/p&gt;&#10;&lt;p&gt;上面的&lt;code&gt;translator_vector&lt;/code&gt;是个有名字的向量：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt; translator_vector = c(A = 'A公司',&#10; B = 'B公司',&#10; C = 'C公司')&#10; translator_vector&#10;&#10;names(translator_vector)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;因此，可以通过元素的名字对元素进行索引。例如：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt;translator_vector[&amp;quot;A&amp;quot;]&#10;translator_vector[&amp;quot;B&amp;quot;]&#10;translator_vector[c(&amp;quot;A&amp;quot;,&amp;quot;B&amp;quot;)]&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;而&lt;code&gt;df$ID&lt;/code&gt;刚好是一个由&lt;code&gt;translator_vector&lt;/code&gt;向量的元素名字组成的向量。因此,代码：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt;translator_vector[df$ID]&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;就相当于一个索引操作，其结果得到的恰好是&lt;code&gt;translator_vector&lt;/code&gt;中对应的元素，这也就相当于对向量元素进行了替换。&lt;/p&gt;&#10;</description></item><item><title>说说风险均摊投资组合的构建方法</title><link>https://gewutang.cn/2014/01/14/construct-pairty-risk-portfolio/</link><pubDate>Tue, 14 Jan 2014 00:00:00 +0000</pubDate><guid>https://gewutang.cn/2014/01/14/construct-pairty-risk-portfolio/</guid><description>&lt;h3 id="引子"&gt;&lt;a href="#%e5%bc%95%e5%ad%90" class="header-anchor"&gt;&lt;/a&gt;引子&#10;&lt;/h3&gt;&lt;p&gt;构建股票投资组合时，在筛选出备选股票之后，要解决的另外一个问题是确定备选股票在投资组合中的权重。我们可以用一个向量来表示：&lt;/p&gt;&#10;&lt;p&gt;$$&#10;w=\left(w_1,w_2,&amp;hellip;,w_n \right)&#10;$$&lt;/p&gt;&#10;&lt;p&gt;其中， &lt;code&gt;\(\sum_{i=1}^nw_{i}=1,i=1,2,...,n\)&lt;/code&gt; 。&lt;/p&gt;&#10;&lt;p&gt;显然，权重的可选集是个无限集合。如果想选取其中一个作为最优权重，那得先确定一个判断最优与否的方法。耳熟能详的方法自然是收益-风险法，即如果一个权重能够使投资组合的收益最大、风险最小，那么，它就是好的。如果用标准差来刻画风险的话，就有下面的评价函数:&lt;/p&gt;&#10;&lt;p&gt;$$&#10;U(R,\sigma)&#10;$$&lt;/p&gt;&#10;&lt;p&gt;其中， &lt;code&gt;\(\frac{\partial U\left(\cdot\right)}{\partial R}\gt 0\)&lt;/code&gt; ， &lt;code&gt;\(\frac{\partial U\left(\cdot\right)}{\partial\sigma}\lt 0\)&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;\(U\left(\cdot\right)\)&lt;/code&gt; 最简单的形式如下：&lt;/p&gt;&#10;&lt;p&gt;$$&#10;U_p = aR_{p} + b \sigma _{p}&#10;$$&lt;/p&gt;&#10;&lt;p&gt;其中， &lt;code&gt;\(a\gt 0\)&lt;/code&gt; ， &lt;code&gt;\(b\le 0\)&lt;/code&gt; ； &lt;code&gt;\(R_{p}\)&lt;/code&gt; 是组合的收益率， &lt;code&gt;\(\sigma_{p}\)&lt;/code&gt; 是组合的标准差。显然：&lt;/p&gt;&#10;&lt;p&gt;$$&#10;R_{p} = w&amp;rsquo;R&#10;$$&lt;/p&gt;&#10;&lt;p&gt;$$&#10;\sigma_p = w&amp;rsquo;Cw&#10;$$&lt;/p&gt;&#10;&lt;p&gt;其中， &lt;code&gt;\(R=(R_1,R_2,...,R_n)\)&lt;/code&gt; 是组合中各证券的收益率， &lt;code&gt;\(C\)&lt;/code&gt; 是组合中各证券的收益率的协方差矩阵。&lt;/p&gt;&#10;&lt;p&gt;把 &lt;code&gt;\(R_{p}\)&lt;/code&gt; 和 &lt;code&gt;\(\sigma_p\)&lt;/code&gt; 带入 &lt;code&gt;\(U_p\)&lt;/code&gt; ，解出令 &lt;code&gt;\(U_p\)&lt;/code&gt; 最小的 &lt;code&gt;\(w\)&lt;/code&gt; 即可。&lt;/p&gt;&#10;&lt;p&gt;当然，也有其它理念。比如下面要说的风险均摊。风险均摊是指选出来这样一个权重，使得其确定的投资组合中各个证券的风险占证券投资总的风险的比例是相同的。有些拗口，直接看下面的公式。&lt;/p&gt;&#10;&lt;h3 id="风险均摊的理论基础及公式"&gt;&lt;a href="#%e9%a3%8e%e9%99%a9%e5%9d%87%e6%91%8a%e7%9a%84%e7%90%86%e8%ae%ba%e5%9f%ba%e7%a1%80%e5%8f%8a%e5%85%ac%e5%bc%8f" class="header-anchor"&gt;&lt;/a&gt;风险均摊的理论基础及公式&#10;&lt;/h3&gt;&lt;p&gt;由前面的公式可知：&lt;/p&gt;&#10;&lt;p&gt;$$&#10;\sigma_p = wCw’=wC \times (w_1,w_2,&amp;hellip;,w_n)&amp;rsquo;=\sum_{i=1}^n wC_{\cdot i}w_i&#10;$$&lt;/p&gt;&#10;&lt;p&gt;上面可以看到证券组合的风险相当于是 &lt;code&gt;\(wC_{\cdot i}\)&lt;/code&gt; 的加权组合，权重是 &lt;code&gt;\(w=(w_1,w_2,...,w_n)\)&lt;/code&gt; 。所谓风险均摊，就是令 &lt;code&gt;\(wC_{\cdot i}w_i=wC_{\cdot j}w_j\)&lt;/code&gt; 。显然，确定一个权重 &lt;code&gt;\(w\)&lt;/code&gt; 使得证券组合的风险得以均摊等同于找到一个权重 &lt;code&gt;\(w\)&lt;/code&gt; 使得下式最小：&lt;/p&gt;&#10;&lt;p&gt;$$&#10;\sum_{j=1}^n \sum_{i=1}^n \left[ wC_{\cdot i}w_i-wC_{\cdot j}w_j \right]^2&#10;$$&lt;/p&gt;&#10;&lt;p&gt;这是一个比较简单的优化问题，在 R 软件里面很容易得到结果。&lt;/p&gt;&#10;&lt;h3 id="用-r-实现风险均摊优化器"&gt;&lt;a href="#%e7%94%a8-r-%e5%ae%9e%e7%8e%b0%e9%a3%8e%e9%99%a9%e5%9d%87%e6%91%8a%e4%bc%98%e5%8c%96%e5%99%a8" class="header-anchor"&gt;&lt;/a&gt;用 R 实现风险均摊优化器&#10;&lt;/h3&gt;&lt;pre&gt;&lt;code class="language-r"&gt;# 模拟获取数据&#10;require(quantmod);&#10;x=getSymbols(&amp;quot;000635.sz&amp;quot;,from=&amp;quot;2013-01-01&amp;quot;,auto.assign=FALSE)&#10;y=getSymbols(&amp;quot;000547.sz&amp;quot;,from=&amp;quot;2013-01-01&amp;quot;,auto.assign=FALSE)&#10;z=getSymbols(&amp;quot;600241.ss&amp;quot;,from=&amp;quot;2013-01-01&amp;quot;,auto.assign=FALSE)&#10;ret_mat &amp;lt;- cbind(dailyReturn(x),dailyReturn(y),dailyReturn(z))&#10;ret_mat &amp;lt;- na.omit(ret_mat)&#10;&#10;# 定义目标函数&#10;&#10;ff &amp;lt;- function(w,ret_mat){&#10; cov_mat &amp;lt;- cov(ret_mat);&#10; w=c(w,1-sum(w));&#10; len &amp;lt;- length(w);&#10; w_mat &amp;lt;- matrix(rep(w,time=len),nr=len,byrow=TRUE);&#10; diag_mat &amp;lt;- diag(w);&#10; res &amp;lt;- 2*len*as.vector(t(diag(w_mat%*%cov_mat%*%diag_mat))%*%diag(w_mat%*%cov_mat%*%diag_mat))-2*(sum (diag(w_mat%*%cov_mat%*%diag_mat)))^2;&#10; return(res);&#10; } &#10; &#10;# 优化目标函数&#10;&#10;w &amp;lt;- optim(c(0.3,0.3),ff,ret_mat=ret_mat)$par;&#10;&#10;# 查看权重&#10;&#10;w=c(w,1-sum(w));&#10;w = c(w,1-w[1]-w[2])&#10;&lt;/code&gt;&lt;/pre&gt;&#10;</description></item></channel></rss>