Skip to content


开源推荐框架DUINE概览

本文原文发在中国推荐系统社区的第一期电子杂志上,文栋为杂志的面世作出了大量的努力。因为原文的配图在出版中出了些纰漏,在这里作出了更正。

 

Duine 是由一个挪威的团队开发的开源推荐引擎,发音为 Dinner 少一个 r 音。不久前 resys group 里有人提出来,能翻墙的朋友可通过这个链接来挖坑。当时我提过一点初步的见解,最近抽时间把它大致地作了一番研究,不妨拿出来与大家一同探讨。


总的来说,我认为相对于大部分文章与系统里研究具体的推荐算法或推荐系统的某个要点,Duine 做了一个很好的探索:就是怎样把这一切整合成一个很完善而且很优美的系统,是很值得研究的框架。但如果从代码层面来说,则是作个参考即可,因为代码库已经快一年没更新了。这个项目的不足之处,或者说任何一个个性化推荐系统的困难之处,大都已经列在这个项目的 RoadMap 页面。在其 RoadMap 中有这么一句话:

Our collaborative prediction technique does not scale well currently, we need to add clustering (and probably more) and get in track with current research. We’d like to have more techniques, for instance a matrix factorization prediction technique.

可惜这已经是一年前的愿景,至今仍未有什么更新。一言概之,如果你想做一个完善的推荐系统,Duine 极具参考价值,但如果要实际使用,并面向一定量的用户,不能偷懒,每个模块的代码你还是得重新来实现。

 

与 Mahout-Taste 的对比

Taste 是推荐领域另一个更著名的项目。简单来说,Taste 是一个推荐器的集合,而 Duine 立志于做一个推荐框架,可以认为 Taste 要解决的问题是 Duine 的一个子集。Taste 专注于利用 Mahout 的分解思想来能高效地实现一些推荐算法,而在 Duine 中推荐器只是其中的一个模块,它同时还处理用户资料库(User Profile)、反馈(Feedback)、推荐可解释性(Explanation)等等更多的模块,以及这些模块之间如何交互的问题。


下面根据我个人的理解介绍 Duine 的三个主要的方面:推荐框架、推荐过程、自省过程,其实还应该有一个很重要的是反馈过程,但由于在 Duine 中这并不是一个重要的模块,这里就不多说了。以下不完全是按照原文档的叙述,有些地方会加入了我个人的理解或实践上的认识,如有不妥之处,还请指出。

 

推荐框架

 


 

图1. Duine 推荐框架各个模块/概念及其相互的关系


1、Ratable Item:例如书、电影、音乐等等用户可以对它表达自己的观点与爱好的事物集,它所包含的一 meta 信息也可作为推荐器的依据之一。拓展一下这个概念,你可以为自己的推荐系统构建一个 Item Profile 模块。


2、User Profile:用户资料库,这是所有模块里最不容易定义的一部分,通常用户的性别、年龄、职业等人口统计学的信息是应该被包含在资料库中的(如果有的话);如果能通过对用户行为与收藏的统计得到一些有价值的表征用户兴趣的信息与类别信息,也应该存放在其中;有些系统会把用户的收藏与评分信息也归入该模块,有些系统则倾向于把这部分数据独立出来,因为这部分数据量毕竟比较大,这关系到应该把源数据还是应该把中间计算结果存储在资料库中。Duine 实际采用的是一个更广义的 Profile Model 的概念,其中包括:Rating Model、Interest Model、User Similarity Model 以及 Item Similarity Model。


3、Prediction Technique:这是推荐框架的核心,也是推荐系统研究中被讨论最多的模块。学术研究与工业应用中已经催生出大量的推荐算法,目前为止可以说最强大的推荐算法不是某一个算法,而是一个适用于不同用户需求的混合式的推荐算法。Duine 的推荐池中采用的推荐器并不太复杂,下面会逐一介绍。


4、Prediction & Explanation:这是推荐器模块直接输出到用户的结果,推荐池依据已知的 User Profile 与Ratable Item(或许你可以认为它是 Item Profile)的输入,对未知的 user-item 作出预测。如果这个推荐系统足够 User Friendly 的话,它还应该输入自己对这个预测的解释,毕竟一个可解释的推荐结果更容易为用户所接受,这也是为什么 amazon 在每个推荐的下面都会给出自己的推荐依据。可解释的东西有很多,比如某一个推荐器的决策依据,再比如下一节要讲的推荐决策过程。


5、Feedback & Feedback Processor:一个有反馈的推荐系统才能向着更优化的方向演进,反馈更快,系统会得到更快的学习机会。Feedback Processor 收集来自用户的显式或隐式的反馈,并把变化更新到 User Profile 中。这里的反馈包括面比较广,不单指用户对推荐结果的爱好表达,还包括一般的收藏、评分行为这类用户与推荐系统之间的交互。


6、Validity Indicators:这个我不知道该如何翻译更合适,所以在下文根据自己的理解把它译为“自省”。每个推荐器都需要一个自我评价与校正的机制,这样才能促使系统的不断竞争与进化。Duine 中对这一模块的处理比较简单,只是根据测试集的测试结果对每个推荐器的可靠程度作一个评价。实际上这是很难以解决好的一部分,不同的推荐器应该有不同的校验方法,并且需要有能力根据用户的反馈对自身进行校正,也许拥有一个高级的“自省过程”是一个“有智能”的推荐系统的前提条件。


推荐过程


现在 Duine 包含有如下的一些推荐器:

  • UserAverage:返回该用户对其它条目打分的平均值。
  • AlreadyKnow:返回用户 Ui 对条目 Ij 的实际打分,适用于 Ui 已经对 Ij 有打分的情况。
  • TopNDeviation:通过其它用户对 Ij 的打分,预测 Ui 对 Ij 的打分。我的理解是应该根据时间、用户权值选择一个已经打分用户的子集,进行预测。
  • Collaborative Filtering (Social Filtering):相当于 user-based 的 KNN,根据以往的打分历史算出跟 Ui 相似的用户,再根据这批用户对 Ij 的打分预测 Ui 对 Ij 的打分。
  • Information Filtering:相当于 content-based 的推荐,提取 Ij 的语义,跟 Ui 的 profile 中相应的信息进行匹配,预测其打分。
  • Case-based Reasoning:相当于 item-based 的 KNN,先算出条目间的相似度,然后根据 Ui 的打分条目及其与 Ij 的相似度,预测 Ui 对 Ij 的打分。
  • InterestLMS:根据条目本身的信息来计算条目的吸引程度。


这里的推荐器大都比较寻常,但基本上已经覆盖了大多的用户需求。实际使用中可以根据本身的技术贮备改善原有的推荐器,或加入更多其它类型的推荐器。

 

 


                                               图2. DUINE的推荐过程


图 2 展示的是一个推荐器结构图,从最顶部的根结点到叶子结点走一遍即是一个推荐过程,非叶子节点代表某一类推荐策略。如图红线所示则表示了对一个新用户的推荐流程。在这个例子中,系统在根结点发现该用户并未对该条目评分,并且在 User Profile 中没找到用户的 taste 信息,因而转到 rationalStrategy;这个推荐策略有一个子推荐策略及两个推荐器,根据判断那两个推荐器不满足推荐要求,则转向 firstTimeUser 推荐策略;以此类推直到找到一个叶子节点作为合适的推荐器为止。

自省(Validation)过程:

正如上文所述,Duine 的自省是一个狭义的自省过程,主要的目的在于根据一组训练数据集对各个推荐器进行测试,并得到相应的置信度,以便在推荐过程为不同的用户选择合适的推荐器。比如 MovieLens、Netflix 的开放数据就可以用来实现这个过程。除此之外,Duine 的自省过程还可以看作是对其推荐交互过程的一种仿真。最后,自省过程体现了一个仲裁者的角色,任何对推荐算法改动后造成的效果变化都可以通过自省过程体现出来。拥有一个评价体系也是推荐系统进化的必要基石,虽然 Duine 的这个评价体系还比较简单。

跟我们想像中的不一样,Duine 的自省过程并不是把所有数据载入,然后对推荐器进行训练,相对而言,它的训练过程更接近于现实中人与推荐系统的交互,即更像是一种对现实情况的仿真,很难说这样做的效果就比批量训练的方式更好,但这无疑更贴近一种在线的训练模式,与离线训练模式可以形成互补。

 

图3. Duine自省过程

一个采用 MovieLens 作为训练数据集的完整的 Duine 自省过程如图 3 所示。Replayer 是整套系统的驱动者,首先把 MovieLens 的数据导入数据库并存成 Duine 通用的 log 数据格式,这种格式犹如日志一般,一条一条地记录了用户对系统的输入(反馈),然后 Replayer 把这些记录再一次一条地取出来作预测,同时作为输入的还有条目自身的信息,即图中所示的 content 模块。预测任务由 Recommender 模块完成,也即上文所述的推荐器池,Validator 负责把预测结果与真实结果进行比较,算出误差与推荐器的置信度,把这些数据存到数据库。此外,从 log 中得到的用户反馈也会存储到 Profile Models 这个资料库里,积累用户资源,为此后的推荐作贮备。很显然,Replayer 其实就是一个仿真器,并且是对一个推荐系统从完全没有用户资料到逐步成熟的全过程的仿真。在这个过程中,各个推荐器都得到了测试并计算出相应的置信度,以此作为可以现实系统中使用的参数,辅助推荐决策过程。


这是一个很直观的模拟过程,可以让人很形象地了解到一个整体的推荐系统的各个模块是可以怎样协同工作的。不同之足在于忽略了太多困难的细节,各模块之间为了简单直观而赋予了太强的耦合,以致于看起来也只能是一个仿真器,无法真正地在现实中使用。另外就是效率问题,由于 Duine 更注重整体,所以在效率上没有太多关注,这个自省的过程非常缓慢,处理 9 万多条 log 数据也要耗费几个小时的时间。

我们可以得到什么

首先,这肯定不是一个能马上就用在生产环境的推荐系统,但从这套框架我们至少了解了一个完善的推荐系统应该有哪些模块组成,功能模块化之后就能有针对性地解决某一方面的问题,并方便地挂接新的模块;此外,Duine 通过配置文件来管理各个模块间的依赖关系与参数配置,个人认为这是个可供借鉴的很优美地整合了各个零乱模块的方式;最后,最强大的推荐器是混合推荐器,这是无论在学术界上还是在工业界上都已经多次被验证,至于怎么解决推荐器间的选择问题,Duine 也提供了一个可参考的思路。

注:本文的配图均来自Duine的官方网站。如有显示不完全的,可使用文章的水平滚动条来拖动。

Posted in Algorithm.

Tagged with .


回首比迈步更难,2010新春记事

站在我现在住处的窗前,可以很方便地看到外面被焰火点缀得灿烂异常的夜空。今夜是元宵,过完今天,据说这个新年就过完了。短短的新年前后很容易让人产生一些异于平常的思绪,算是平淡的宅居生活中的几分色彩,不妨作一些零碎的记录。

回家前,参加了一场朋友的婚礼。新郎是大学时代的好朋友,一起在球场上摸爬滚打出来的。同时代去参加婚礼的不多,但全都是多年来的老友,一起笑过,一起醉过,一起困惑过。那是一个血性迸射的年代,那是杀红了眼可以拿命来拼的年代,多少年来,“男人!男人!男人!”的口号再也没有在耳边响起过。当年数理的macofour,自此也开始走进一个新的阶段,从只管挥洒热汗的球场,开始走向肩挑更多责任的家庭。新娘是新郎的同班同学,一起坚持了近7年的爱情长跑,这也许是千百个遗憾中的一次意外,李雷终于牵着了韩梅梅的手。

看到一些故人,总会不由自主地想起另一些故人,虽然已经多年未见,虽然我也知道TA们都已经有了各自的生活,但我们有着共同的回忆,共同的人生风景。有多少人会与你匆匆擦肩而过,有些人则注定会成为你生命中隽永的回忆。那些花儿,无论随风散落在何方,最终都会深埋在你的心田。

我的春节从来就是南下的概念,火车在相当长的一段时期之内都会是联系中国人的思念与家乡的纽带。

火车上不一定是最佳的阅读场所,但对于我来说是的。这几年南下的火车上,我开始捡起了自己丢弃多年的“闲书”,它们陪我度过那一个个孤清的旅途。08年的春节,我即将离开生活了近20年的象牙塔,走进社会,那一年的火车上,我在读《长尾理论》。我应该是属于后知后觉的,因为成为网民多年的我,从此好像窥见了一个从未得知的世界。这本书的序和前言我看了一个星期,第一章看了一天,因为中途被思考打断得太多。剩下的都是在火车上看完了。自此我就有了这么一个观念:畅销书的思想只有一个,你把它参透之后,其它的都是装裱。09年的春节,我已经在《长尾理论》描述的世界里工作了半年,开始思考一些别的东西,那一年的火车上,我看《决策与判断》。对心理学的接触,其实从大学时代就开始,心理学及AI,曾一度是支撑我继续读研的动力。但是那一阵子,我第一次感觉到心理学是那么活生生地发生在我身边,它不再是那硬梆梆的理论与无休止的实验,我开始了解到理性之外那人性缺陷的所造就的真实世界的美与丑。今年的春节,我带了一本《沸腾十五年》,没看完。这本书不算好,珠玑与沙砾混杂,没有线条,难以串成珍饰。好的史书并不是史料的简单堆砌,那不过是历史教科书。但我的选择基本反映了这段时间里我关注与思考的问题,再往前推的一段时间里,我看了《激荡三十年》与《封面中国》,只是我喜欢在历史中进行思考。知道得太多不该知道的事实,有太多的现实问题我无法找到答案,我希望能从历史中得到启示。历史总是惊人地相似,只是它仍旧会一遍又一遍地重演。

冬天里的南下,只消闭上眼睛过一宿,再睁开眼时,你会发现两旁原本光秃秃的树木都长满了翠绿的叶子,像刘谦的魔术一般神奇。

火车之后是汽车,家乡,就在一片群山丛中。南方水量充足,山与山之间如果有水汇成了河流,就能冲出一片相对平整的土地,可以用于种植农作物。有农田的地方就会有人,有了人就会有村落,我家乡就座落在这么一个推门见山,扭头见河的山沟沟。翻过一座山,就是一个镇,山路九转十八弯,不单考验司机的功夫,更考验乘客的身体。农家人起初都不习惯这般的颠簸,所以在相当长的时间里,很多的山里人更愿意使用传统的交通工具——双脚——来翻山越嶺地探亲访友。出门一趟不容易,所以通常会挑上两个箩筐,里面放一些稻米、粽子之类的农作物或是农家食品,如果带上小孩,还可以很方便地把小孩往箩筐里一塞,一边农作物一边人,晃悠晃悠地就走个一上午的山路。我小时就坐过这种土制的“人力车”,天气热就把大帽子往箩筐上一扣,隔着小缝隙看两边的稻田小溪从眼前晃过。寂静的山路里,经常摇啊摇地就睡着了,跟在摇篮里一般的平稳和安详。山间的小溪,流得如时间般地细腻无声,也慢慢地逃却宁静,翻越群山,终将汇入大海之中。

每年回家,总会有些老人再也见不着,总会有些玩伴成为丈夫或父亲,当年在河边嬉戏、农田掏鱼的少年们,早已经长大成人,结婚生子,终日为生计而奔波。就连那条潺潺小河也因建水电站之故早已变成一汪静湖,农田也已淹没在水底下。每年回家,看到二老日益佝偻的身影,总会有一丝愧疚,我总想要为他们做些什么,可现在能做的总是太少,两个姐姐出嫁得早,哥哥结婚多年,回家的次数却越来越少,而我自初中以来多年来一直漂泊在外,仍旧没有能力让他们颐养天年。漂泊在外的游子,不是鸿雁,是风筝,飞得越远,越让你感受到那根牢牢牵挂着的线。如果说,所有的成长到最后总是一次旅行,我这何尝不是一次旷日持久的旅行,何时是行程的结束,我心里依然没有答案。

不知道是不是出于巧合,每年过年家乡都会很冷,一个人静静坐着就会有种莫名的阴寒与孤独。所以,过年人们总是要凑在一起,说说话,取取暖。初四日,家中亲戚满座,不知觉间,两个外甥都已经长大了,即将上高中的大外甥,也许再过两年,就比我还高。只是曾经那么聪明活泼的小男孩,却变得那么沉默寡言。读小学的小外甥有一个好母亲,听他母亲说,他跟我小时候颇为相似,总喜欢抱了一本书就坐在角落里看,吃饭叫唤也不应声。晚饭后,在家门外点起了一堆篝火,家人亲戚与邻里老少地开始坐在一起取暖,怀念那些逝去的人与事。总是会有头发日渐花白的老人在叙说着自己的父辈甚至爷辈的事情,总是会有几个无忧无虑的小孩围着大人们耍乐,每年都会有一两张稚嫩的面孔,我感觉自己从未见过。年年岁岁花相似,岁岁年年人不同,终归有一天,我们也要成为历史的尘埃,成为后来人言说的对象。唯独那一晚我记忆中难以忘怀,无论是谈及被老虎叼走的先人,抑或三代前地主家中妻妾与现人的复杂血缘关系,又或来自长辈对后辈的婚嫁催促。我的话语好像一年比一年少,印象中篝火烧得哔啪作响,似乎照着通往往昔与将来岁月的那条时间隧道。

越是喧闹的时候,越是容易让人感到寂寞。今夜烟花真是灿烂,虽然闪耀过后就是漫长的黑暗。

哎,人真的是不能想得太多的,下楼看焰火去。

Posted in Life & Thinking.


从pentaho到jaspersoft

因infobright之故,我认识了pentaho和jaspersoft,因为infobright提供与它们配套的虚拟机,人都是懒惰的,更何况我使用虚拟机已经到了痴迷的程度。于是我先上了pentaho的贼船,至今仍徘徊在jaspersoft这条不知道能不能驶到头的幽灵船上。

infobright网站上是这样描述它的这两个partner的:

pentaho:

Pentaho Corporation provides a full spectrum of commercial open source Business Intelligence (BI) capabilities including reporting, analysis, dashboards, data mining, data integration, and a BI platform that have made it the world’s most popular open source BI suite.

jaspersoft:

Jaspersoft’s open source business intelligence suite   is the world’s most widely used BI software, with more than 8 million total downloads worldwide and more than 10,000 commercial customers in 96 countries. The company’s Jaspersoft Business Intelligence Suite provides a web-based, open and modular approach that address the next generation business intelligence needs of the enterprise. Jaspersoft’s software is rapidly updated by a community of more than 90,000 registered members working on more than 350 projects, which represents the world’s largest business intelligence community.

大意是说pentaho是世界上最popular的开源BI(商务智能)套件,而Jaspersoft是世界上最widely used的BI软件。尽管我并不知道“最popular”跟“最widely used”到底有何区别,尽管我也知道自己的直觉往往是不准,但我还是根据自己的直觉选择了pentaho,作为我的第一个BI尝试。大概是觉得强调BI suite与BI platform的pentaho怎么说也得比强调software的jaspersoft更为强大,也有可能仅仅是因为infobright.org中download菜单上pentaho排得比jaspersoft靠前。但是我后来惨重的经历再次血淋淋地证明,庞大并不等于强大,事无巨细还不如专注做好细节。

于是我先下载了infobright+pentaho的虚拟机,解压,vmware启动就能用,还是以web方式提供的一个服务,立马就能体验,很有成就感。其实中间还是遇到了一些小麻烦,主要是网络与访问权限方面的,把vmware的Network Connection设置为Host-only,同时参考着压缩包里的README来做,基本没有太大问题。

瞎折腾一番后,觉得好玩,想深入还是重新下载代码自己重新搭建吧,于是跑到这个页面开始下载。不要眼花瞭乱,基于WEB的BI套件通常包括几部分:一个WEB服务、一个报表设计器、数据聚合与转换(ETL)。一定要下载的是服务平台:Business Intelligence Server,同时把Report Designer也下载下来作报表设计之用。其它的可以先不用管,这两个就够折腾的了。

经过一段时间的使用之后,颇感疲惫不堪,商务智能这玩意,面向企业用户,使用的技术门槛不高,但有一本详尽的使用手册或者接受软件提供方的培训教程非常重要,否则一个人摸索起来着实费劲。pentaho的报表设计软件Report Designer用起来BUG也很多,我不知道windows版本是否这样,但linux版本的实在是个考验人耐心的玩意儿。到最后实在没有心思再跟它折腾,更别提其它几个似乎功能更强大的data integration和metadata editor这些套件。

pentaho的web界面看起来更user friendly,用起来却完全不是那么回事,相对而言,jaspersoft的web界面则更工程师化,让人感觉有厚重感。jaspersoft所配带的官方文档也比pentaho要丰富得多,虽然两者的文档都是旧版本的文档,jaspersoft甚至还有一些中文文档。

jaspersoft套件列表在这里,必装的是jasperserver,里面内嵌了jasperReports和jasperAnalysis,前者是报表系统,后者是数据立方分析系统。iReport是报表制作的客户端软件,jasperETL是商务智能软件里必备的数据集成工具。有配套文档的是现在是3.5版本,安装包及文档可以这里下载。

参考着文档即可进行安装,可能会需要建立一些数据库,应该会比较顺利。安装后好后在安装目录启动服务,就可以通过web访问服务。有一些概念问题说明一下:

做一个jasper analysis,需要几个步骤:

  1. 需要建立一个data source,这相当于定义一个数据源,所有的操作将对这个数据源进行;
  2. 需要有一个data schema,这是一个xml格式的数据定义文件,对data source里需要用到的表及其表连接作相应的定义;
  3. 建立一个data connection,这是一个数据立方的查询连接,在这里选择合适的data source及data schema;
  4. 最后建立一个analysis view,在这里选择一个data connection,及定义一个MDX查询语句,MDX查询语句决定将会显示的数据立方是什么样子的。

需要注意的是,在定义data schema时,需要查询的表也要作维度化,分离出fact表和dimension表,详细内容可参看文档Mondrian-3.0-Technical-Guide.pdf,jaspersoft自带的几个样例也非常有参考价值。一个analysis view定义完成之后,就可以进行drilling, pivoting, filtering, visualizing等等操作,详情可参看文档JasperAnalysis-User-Guide.pdf。

jaspersoft的另一大功能是报表的制作,通常的做法是先用客户端软件iReport做出一个报表来,然后同步到服务器,即可在服务器进行实时查询,或者制订实时任务,让任务定时运行,定时发送报表到指定邮箱。这方面文档不多,得自己摸索的比较多,一些简单的指引可以从文档JasperServer-User-Guide.pdf中得到。一个报表可以包括数据源、控件、自定义参数、图表等等,如果有比较丰富的文档,再加一些耐心,可以做出很漂亮的报表来。因为不是设计人员,我更偏向于编码方面的实践,设计方面只求做出能用的报表即可,所以这方面并没有太多的深入。

Posted in Database.

Tagged with .


编写R包C扩展的核心指引

以下,$RHOME都是指代你安装R所在的目录。

R的配置文件,在$RHOME/etc下

  • Renviron:环境变量与路径配置,大都可顾名思义,主要介绍以下两个。
    • R_LIBS_SITE: 包搜索路径,在R命令行下可用.libPaths()显示,;
    • R_LIBS_USER: 用户包目录,如果设置为”~/Rlibs/”,则每个用户在没有全局安装权限时,默认地会把包安装到~/Rlibs/下,无需添加到R_LIBS_SITE也能被搜索到,但在R命令行下用.libPaths()不会显示该路径,这样每个用户可以拥有一个自己本地的R库;
    • 如果想配置一个本地测试环境,以便与生产环境区分开,可以在安装包时指定一个路径,如R CMD INSTALL testR.tar.gz -l ~/Rtest 可以把testR包安装到~/Rtest下,写测试文件时第一行加上.libPath(‘~/Rtest’),就可以正确找到testR包了。
  • ldpaths:动态库载入路径配置。
    • R_LD_LIBRARY_PATH:R 包载入时动态库搜索路径,默认为${R_LD_LIBRARY_PATH=${R_HOME}/lib:},如果要加上/usr/local/lib,则 变为${R_LD_LIBRARY_PATH=${R_HOME}/lib:/usr/local/lib:}
  • Makeconf:包编译链接配置,类似于Makefile,可被用户引用或重载。在R CMD INSTALL/build时使用。
    • 如果使用Makevars文件,则把该文件放到包的src目录下,文件中的配置可使用并扩展Makeconf的配置。
    • 例 子:在Makevars中定义PKG_LIBS = -L/usr/local/lib -lmylibs $(LAPACK_LIBS) $(BLAS_LIBS),其中$(LAPACK_LIBS)与$(BLAS_LIBS)是Makeconf中预定义的变量,这里定义的PKG_LIBS变量会被Makeconf中的ALL_LIBS变量所使用,作为链接参数的一部分。
  • repositories:cran站点。

R的头文件在$RHOME/include,对于用C写R扩展这个应用场景来说,有用的是R.h,Rdefines.h和Rinternals.h这几个文件。

  • R.h是每一个为R作接口的C扩展里必须包含的。
  • Rinternals.h是最核心的定义文件,它定义了最基本也是唯一的R结构SEXP(详见这里)及其它的一些数据类型与结构、常量、以及所有你会用得到的接口函数。
  • Rdefines.h中include了Rinternals.h,并且为了方便使用,定义了一大批的宏,对Rinternals.h中的函数进行了封装,虽然还不是完全的封装,但已经很够用,语义上也好理解得多。

Rdefines.h中一些常用的R扩展函数,让你可以在C里操作R的数据结构,以下的函数参数x的类型都是SEXP,n为int型变量:

  • AS_XXX:类型转换,等同于R中的as()函数。如AS_INTEGER(x)把x转换为INTEGER类。类似的还有IS_XXX,等同于R中的is()函数。
  • NEW_XXX:生成一个向量对象,如NEW_INTEGER(n)生成一个长度为n的向量,SEXP类型。通过NEW_OBJECT(MAKE_CLASS(“classname”))可生成任意一个类的对象。
  • XXX_POINTER:取得SEXP向量对象数据的指针,如INTEGER_POINTER(x)返回指向x的数据的指针,接下来可以在C里自由操作。
  • mkString:比较简便地生成一个字符串型SEXP对象的方法,如mkString(“xyz”)。
  • GET_ATTR, SET_ATTR, GET_SLOT, SET_SLOT:获取/设置对象属性,获取/设置对象SLOT,可参考文件中的定义。
  • allocVector, allocMatrix:生成一个向量/矩阵,在Rinternals.h中定义。
  • NEW_LIST, SET_ELEMENT:list相关的操作。
  • PROTECT, UNPROTECT:为避免被R的垃圾回收机制错误回收,在用NEW_XXX或alloc*分配内存生成对象时,需要用PROTECT()函数括起来,最后用UNPROTECT(n)取消保护,n的个数应该等于之前PROTECT函数被使用过的次数。

Posted in Programming.

Tagged with .


网摘2010-01-13

这期的网摘很有些悲观与愤怒,因为今年发生太多无耻的事情,特别是这个冬天,来得特别早,也特别地寒冷,去期却仍遥遥。然而北京11月初大雪中异常的冬雷,能敲响某些人心目中的警钟么。

  • 适逢康乾盛世,便又一次闭关锁国,于我天朝上国又有何碍,至多百年后又一次国土沦丧而已,我当权者已不得见。吾辈只能陪你到这里,好自为之。(壮士断腕,2010年1月13日是个值得记住的日子,如果失去google.cn,无论对于中国的高端网民还是低端网民,都不会是个大的影响,然而中华大局域网一成,墙外风光必无我辈可瞻仰之处,墙内处于阴暗角落的垄断与所谓创新,必得用人民之血泪灌溉)
  • 来自一个很有智慧的朋友:人会失去,最终来说,甚至包括生命。然而,危险所在之处,也生成着拯救。终极的拯救,不是免于失去,而是免于恐惧。(来自李开复。开复先前之离去,是不是因为他已经知道这一天的终将到来?)
  • 这个世界上有两部分中文信息,一部分是全世界都能看的,一部分是中国人不能看的。(来自和菜头。天让我从事这个行业,看到那么多中国人不能看的东西,看到了那赤裸裸地横亘在我们面前的数字鸿沟)
  • 最终组织的荣衰代替了思想的成败,最终组织的目的代替了过程的正义,组织代替了理想,成为正义本身(来自十月围城的评论:http://www.douban.com/review/2870206/)
  • 当今中国已是一个自由程度很高的国家,对于大多数普通公民来说,其实只有两件事是不允许的——就是“这也”和“那也”(来自东东枪。饭否没了、译言没了、BT没了,Youtube消失了、Facebook消失了、twitter消失了,因为她们能让人找到一些有价值的信息。下一个会是谁)
  • 为了在一言下听到点异言,于是就有了译言,结果译言很快变成遗言,美好的网络创意产业最终变成了义演。(来自和菜头。随着国家队的进驻,谁说我们一切的努力不会最终成为一场义演?所幸,几天前译言又再涅磐重生,虽然原来的面目已经模糊)
  • 如果争论没有对手,又怎能得到有意义的结论。可悲的是我们政治课本上写的结论大都是来自于那样的争论。
  • 人类社会是个非线性系统,在细节级别对它进行任何长期的预测,除了碰运气,就是徒劳。这就是为什么从来没有一个人可以有效地对商业公司建立一个成功模型。但是从大数定律来说,任何的不可预测现象的总和,却总是有序的,这就是为什么大的趋势有时我们是可以把握的。
  • Success is 50 percent luck and 50 percent preparedness for that luck(一句名言,可译为:成功,那就是50%的运气,加上50%为这运气所做的准备)
  • 我意想中的企业家:知识分子的良知、冒险者的冲劲、商人的逐利。
  • 我总是通过登山、徒步,与大自然接触,试图找到人生的意义,但是最终的答案,只是找到那个渺小的自己?
  • 网络,即是信息的交流,思想的沟通,无论神经网络、互联网、手机网络,都是一样的。
  • 欧美社会的基本组织单位是个人,中国社会的基本组织单位是精英分子、团体、甚至巨头。(有感于开放平台在国内触礁,时代周刊把06年风云人物投给YOU,在中国,目前看来,不可能)
  • 有一种遗憾,当你历经磨难时,无人在你身边鼓励,当你一步步走向收获时,无人分享你的喜悦。
  • 很多人都有过一个梦魇,当幸福向你走近的时候,它总是很及时地敲响你的门。
  • 要做最悲观的猜测,并用最乐观的心态去面对。

Posted in Life & Thinking.

Tagged with .


诡异的R变量作用域

在调试一个递归函数的时候,发现的一个变量作用域的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
a = 0
 
test <- function(){
 a <- a+1
 #assign("a", a+1, env=.GlobalEnv)
 if(a>3)
   print("reach")
 else{
   print(a)
   test()
 }
 print(a)
}
 
test()

该代码的原意是利用全局变量作一个递归,但实际上它会陷入死循环,永远都在打印1。关键在第4行,首先根据R的变量搜索路径,局部变量a取得全局变量a的值0,然而a<-a+1这一步,却是把值赋给局部变量a,而非全局变量a。所以每次调用test()函数a的值都会被置为0。如果想赋给全局变量,则应用第5行被注释的代码替换第4行的代码,才能得到如下正确的输出。

补充:a <<- a+1这种方式可以给全局变量赋值。

[1] 1
[1] 2
[1] 3
[1] "reach"
[1] 4
[1] 4
[1] 4
[1] 4

当然如下纯粹用局部变量实现递归也是可以的,只是因为我的应用中需要用到一些全局变量,所以才面临了些诡异的问题。

1
2
3
4
5
6
7
8
9
10
11
12
test <- function(a){
 a <- a+1  
 if(a>3)
   print("reach")
 else{
   print(a)
   test(a)
 }
 print(a)
}
 
test(0)

Posted in Programming.

Tagged with .