Categories
日常应用

从R里面底层操纵Excel/xlsx(自动化报告福音)

好吧,我在eBay折腾的最多的就是生成自动化报告时候各种软件之间的相互调用,什么R啊,SAS啊,Teradata啊,Excel啊,Python啊,反正基本都有机会相互调用一下。每到此时我就深深感慨选择一个library丰富的工具是多么的重要!You could hardly expect what you colleagues are handy with!(P.s. 不要跟我提VBA这种逆天存在的东西。有哪个时间研究它你学点啥别的不好...)

今天忍无可忍+心情大好的折腾了一下R和excel。这个不是简单的从R里面读写excel数据,而是真心用R去操纵excel里面的单元格(cell),除了读写数据之外还要定义样式什么的。excel作为一个奇葩的软件,you may never expect where people would paste data to! 然后他们再自定义一堆样式(我恨这种点点鼠标就能改的东西,你丫又不是Photoshop...)。

但是没办法,人家定义好的“高端洋气”的报表姿态你不能轻易动啊。只能乖乖的往里面paste数据。这件事虽说一次两次手动也就罢了,三五次真的是要疯掉的。anyway,万事总有解决的途径...

很久以前从Yixuan 的博客上得知有xlsx这么个包,当时只记得这东西可以读写xlsx...直到后面折腾了一下才知道这货底层居然调用的是java的xlsx API,也就是说不用写Java也可以操作xlsx了,yeah!

为了生成excel格式的自动化报告(不要问我为啥不用knitr,不用***,说起来都是泪呀!),我主要需要解决的就是:

  • 读取原有xlsx文件,保持格式、附加新格式。
  • 在相应的位置粘进去新的数据。(当然如果只有这么一个需求可以通过ODBC来做...)

第一个倒是满简单的,就是较之yixuan代码里面的createWorkbook(),改成loadWorkbook()就可以了。然后就是找到相应的sheet,这个也满简单的,一行getSheets搞定。

然后第二步建议不要去操作cell(太没效率了),直接操作cellblock。CellBlock()可以用来定义一个新的CellBlock,然后灵活运用CB.setBorder()和CB.setColData()就可以先增加边框、然后一列列填充数据。这里使用按列填充数据主要是因为R里面的Data Frame是一列一个数据格式的,一下子把一块儿都paste到excel的cellblock里面的话,会报错...BTW为了定义边框的样式,需要用到Border()。类似的还可以定义Fill和Font这些。

同上,最好不要直接用addDataFrame()来直接贴数据...格式不能覆盖。如果是要在一个新的sheet上贴数据,那么就write.xlsx(sheetName="newsheet",append=T)好了。不需要通过上述底层的API折腾了。

最后还有一个比较有用的函数,autoSizeColumn()可以用来自动调整列宽。全鼓捣完之后saveWorkbook()保存就可以啦。

最后的最后,一个珍贵的建议——都在R里面把数据整理好再去想输出到excel里面(什么reshape2啊,data.table啊,plyr啊,该上的一起上啊!),千万别手贱在excel里面改一点点小东西...每一次都手动改一下下你的时间就被白白浪费了好几分钟!珍爱生命,远离excel...

附上一段我最后搞定自动化报告的代码:

library("xlsx")
test_template <- loadWorkbook("template.xlsx") #读入template.xlsx文件。定义好各种乱七八糟的格式的。
design_tab <- getSheets(test_template)[["design"]] #转到design这个sheet。
data_block <- CellBlock(design_tab, 5,5,nrow(mydata),ncol(mydata)) #准备贴数据的方块,我这里从第5行第5列开始贴。
border <-  Border(color="black", position=c("LEFT", "RIGHT"),
pen=c("BORDER_THIN", "BORDER_THIN")) #定义边框样式——左右黑色细直线。
for (i in 1:ncol(mydata))
{
CB.setBorder(data_block, border,colIndex = i,rowIndex=1:nrow(onetime_design_tab)) #给每一列都贴上边框
CB.setColData(data_block, mydata[,i], i, rowOffset=0, showNA=F, colStyle=NULL)#给每一列贴数据
}
border_bottom <-  Border(color="black", position=c("LEFT", "RIGHT","BOTTOM"),pen="BORDER_THIN") #定义结尾行样式——底端黑细直线
data_block_bottom <- CellBlock(design_tab, 5+nrow(mydata),5,1,ncol(mydata)) #选择最后一行
CB.setBorder( data_block_bottom, border_bottom, 1, 1:ncol(onetime_design_tab)) #定义最后一行格式
autoSizeColumn(design_tab, 5:(5+ncol(onetime_design_tab)))#调整列宽
saveWorkbook(test_template, file=output_xlsx_name) #保存
##add row data
write.xlsx(rawdata, file=output_xlsx_name, sheetName="raw_data",append=T,row.names=F) #直接贴原始数据,无格式
###add queries
R_file <- readLines(R_file_name, n=-1) #直接贴R代码
SQL_file <- readLines(SQL_file_name, n=-1)
write.xlsx(SQL_file, file=output_xlsx_name, sheetName="query_SQL",append=T,row.names=F) #直接贴代码到新的sheet中
write.xlsx(R_file, file=output_xlsx_name, sheetName="query_R",append=T,row.names=F)

 


Categories
游来游去

长安一片月,万户捣衣声——西安速记

不知道为什么,每次西安都是来去匆匆。没有呆过超过三天的。于是乎,对于这座我最喜欢的北方城市,印象总是断断续续的,一丝一缕的。

DSC07959-r
长安万户

一直在想,我可能再也不会经历早起赶飞机、暮迟宿夜车这样的旅行了,毕竟已经年老体衰、精神不比当年了。然而主观臆断就是用来被打破的。几句电话、几往短信,然后我就背着背包出现在了大雨滂沱的古城西安(小轩哥霸气~~~一硕下了班就直接来了,随性至此,V5~~~)。那天的雨着实太大(两朵乌云着实不能出现在同一座城市),一切的记忆都是湿漉漉的。那种酣畅淋漓的大雨,正是北方下雨的记忆——或许慢慢习惯了南方的阴雨绵绵,这样久违的畅快一下子勾起了北方的亲切。

“少小离家老大回,乡音未改鬓毛衰。”

南方实在是缺乏一点气势。总是柔柔的,柔柔的。时间久了,就觉得整个人都靡软了,缺乏奋斗的力气了。然而原本,尚年少,可疯狂。

长安是一座有脾气的城市。火车站正对着的城墙,相比于苏州火车站正对着的园林,气势上远远压过。一下子,就不知道自己身处的年代——为什么岁月可以这样变化,穿越古今?骑行在宽阔的城墙上,正如丞相当年那般气宇轩昂——两侧的车水马龙凡人喧嚣,与我何干?沏一壶清茶,落座于伞下。携三五好友,谈天论地,好不畅快!

DSC07933-r
冲天香阵透长安,满城尽带黄金甲。

DSC08070-r
长安陌上无穷树,唯有垂杨管别离。

金戈铁马,唤起的是对于远古的铁血记忆。许多奇迹,长埋地底。

DSC07881-r
秋风吹渭水,落叶满长安。

偶尔,月夜朦胧,恍若江南。停辙,起伞,落座。

DSC07868-r
长相思,在长安

DSC07846-r
曲江烟雨

回程之前,随意漫步。东北角楼,斜阳无数。偶逢高人,少聊摄影。略略指点,方知陕西之博大,意欲驾车重游。

DSC08083-r
古城落日

来长安,只要吃到皮脆里嫩的肉夹馍,以及酸酸辣辣的凉皮,人生就满足了。太解馋了。(战绩:5.5个肉夹馍,吼吼)

DSC08000-e
一只边走边吃的吃货的幸福

DSC07986-r
曲径求“道”

长安漫游路线图:钟楼/鼓楼(有定时钟鼓表演) -> 曲江池遗迹 -> 兵马俑/秦始皇陵 -> 城墙(骑行,南门有定时士兵表演) -> 书院门漫步 -> 东北角楼落日。下面是随手拍的照片,随便看看,权作回忆。

Categories
游来游去 经济、IT观察与思考

数据分析职业病

分析是种职业病,融贯在每一分血液里,每一分骨髓里...去参加个Qcon看看人家的创意网站,然后心里各种痒痒,拉着思喆哥、堰平兄饭局讨论实现的原理也就罢了,最近只要一出门就习惯性的开始思考某些稍微“违背常理”或者“略显聪明”的现象...

比如这次去西安,在去的航班上,就开始思考起来了“航空公司的数据挖掘”....
-------------------回忆的分割线-------------
有些事情纯属职业病。这次上海飞西安坐的是南航的航班,一路折腾到飞机上就已经疲惫不已了,直接睡过去。

后面的一切毫无波折,如果不是临下飞机十几分钟的一段对话,我估计会对这段航行毫无记忆。只是突然间空姐的一句问候,"您是***女士么(我的本名)",让我第一反应是我不是你们的金银卡啊,这也开始问候了?...然后笑意盈盈的递给我一张会员申请表。"您虽然还不是我们的会员,但是您是我们的潜在会员。所以请您加入我们南航明珠俱乐部"...

我第一反应是,"潜在会员"这个是怎么分析出来的?目测我大概有一年的时间没有飞过南航(在过去的半年时间我似乎都完全没有飞过),难道他们有个"沉睡用户苏醒监测"?要不就是,正巧这次我累计乘坐南航的次数达到了他们分析的阈值(比如10次)?要不就是,每次坐南航我都累积东航,让他们终于忍无可忍了...还是说,他们真有一个customer life value model,算出来我对他们的潜在价值了?

蛮有意思的是,我曾经有段时间周周飞南航,他们却从来对我爱理不理,所以我猜测他们的模型里面对于"reactivated"的顾客有个很高的权重。

到最后,南航猜的准吗?准,有可能是我确实在东航还有一些里程可以挥霍。不准,则是我现在飞行大都是私人旅行了,基本不可能象以前做咨询时候出差那般频率了,所以我的潜在价值肯定没有模型上估计出来的高。如果这个模型进一步分析"公务旅行"还是"私人旅行",怕是效果会更好吧。不知道能不能通过机票代理来区分这两类客源...所以,准,却有点晚了。

当然对于垄断国企来说,这个CRM并不是那么重要,反正利润会一直在那里,国内的常客计划也发展不起来。只是感慨一下,这样的分析要是想做好,绝对离不开自己对于这项服务的亲身体验。只有飞的多了,才知道常客计划的最大引力和最关键时点。而后的分析,才会水到渠成吧?

职业病发作完毕...

Categories
读书有感

统计学习精要(The Elements of Statistical Learning)课堂笔记(二十四):聚类

聚类讲的比较简单...怎么感觉老师不怎么待见unsupervised learning捏?...

---------------笔记开始---------------------

1. 一般概念

1)分类与聚类(分类标识)

评测纯度。我们有测试集,这样定义纯度为.

2) 输入

  • 特征向量的表示:
  • 相似矩阵的表示:,其中相似度的计算可以是的内积。显然,向量表示很容易可以计算相似度表示。
  • 距离矩阵的表示(不相似度):,其中距离可以用二阶范数定义,比如

3) 输出: ,对应K个聚类。这里还分为:

  • 非层次的
  • 层次的(类似于树结构)

2. K-means方法(非层次聚类)

(注意不要和KNN搞混了,都是K开头的...)

1) K-means方法(特征表示)

输入:,K——聚类的个数。

算法:

初始化,随机选定类中心.

  • (i)根据分配到距离最近的类。
  • (ii)修改,使得。重复上面两步。

2) K-medoids方法(相似度表示)

输入:s,k

初始化。然后根据分配,再按照确定新的中心。

3) 模糊的K-means方法

输入:,K

初始化。

  • (i) ,计算,然后根据这个距离的比重来“软”分配(需要归一化分配权重)。
  • (ii) ,利用中的进行加权平均。

重复上述两步。

4) 谱聚类(向量表示)

输入:,K

然后对原始数据做转换,形成新的数据集,然后再做K-means聚类。

其中转换的步骤如下:

  • (i) 计算相似矩阵S
  • (ii) 计算L=D-S,其中
  • (iii)计算L最小的K个特征值对应的特征向量
  • (iv)让U=,则是U的第i行,这样就从p维降到了K维。
  • (v)对Z进行K-means聚类。

3. 层次聚类

1) 自底向上的方法(聚合)

初始:每个都为一类

而后对于最相似的两类,合并到一类。对于类的最相似,可以定义为距离最近的类。而对于距离,则可以定义为三者之一:

  • (i) ,称之为单连。
  • (ii) ,称之为全连。
  • (iii) .

2) 自顶向下的方法(分裂)

初始:所有的x作为一类。选用一种非层次的方法进行聚类,递归使用。

例子:二分法。

初始:。而后选择离G最远的一个点g。

修改。重复步骤,选择离H近的离G远的逐渐加入H。

直到分不动了,彻底分为两类。

---------------------

下节课讲的是降维方法。

Categories
读书有感

统计学习精要(The Elements of Statistical Learning)课堂笔记(二十三):原型方法和最近邻KNN

笔记(二十二)需要等我找到上一本笔记本再说,暂时不知道扔到哪里去了...汗。届时补上。

这一章主要是讲的原型方法(prototype)和最近邻(KNN)。相对而言直觉更强,公式没那么复杂。

--------------------------笔记开始-------------------

1. 原型方法

1) 1-NN 最近邻居方法

最极端的情况:只找到最近的一位邻居。

数据集,输入,在中找到与最近的邻居,输出对应的类标记

2) 类中心的方法

类中心: ,相当于对于一群有着同样类标记的点,对x取平均。

输入:,而后在所有类中心中与其最近的类中心

输出:对应的类标记。

3) 对每个类可计算若干个“中心”(称之为原型或者样板,比如在每类中做聚类)。

输入:,而后在所有类中心中与其最近的类中心

输出:对应的类标记。

4) K-NN方法

输入:,在中找到与最近的K个邻居。

输出:(最多的那一类,从众原则的感觉)。

由于这一类方法都比较懒,所以称之为lazy learning methods.

2. K-NN方法的错误率(渐近性质)

1) 结果

为Bayes分类器的错误概率(最优分类器);为1-NN分类器的错误概率。

则有:当样本数时,。接下来会证明这个优良的性质。

2) 分类问题

给定,则

这里我们称 为先验分布,为类分布。从而

,称之为后验概率。

3) Bayes分类器

x对应的,即使得后验概率最大的k。

所以,,从

4) 1-NN分类器

1-NN输出的是离x最近的对应的,则

由于只限训练集,而那部分只跟测试集有关,所以由独立性我们可以拆分为:

,则当时,,,上面一项可以收敛为,为后验概率(条件误差)。

5)由于,设为所有中最大的,则

6)。得证。

下一章会讲到聚类,然后就是降维了。