很荣幸收到了 ILC2012组委会的邮件

ILC2012 预定在日本的京都(应该是京都大学)举办,组委会的黄先生发邮件给我交流议题。真是令我受宠若惊啊。感谢田春的介绍哈。

Posted in Uncategorized | 3 Comments

如何写一个冷博客

把博客迁移到自己的主机上,冷清了很多:)

检讨下原因:

1. Lisp (包括进来的R方面的内容)本身就是冷话题,虽然有近期的《黑客与画家》的催生,但是该冷还是会冷的。如果那些人聪明到读了几篇文章就能认准Lisp的话,那他们早在5年前就该认识到了。

2. 文章内容在外行眼里看着古怪,在行家眼里看着肤浅。

3. 没有了CSDN博客上“专家”的戳。

4. 我本来就想搞个冷博客。

Posted in Uncategorized | 14 Comments

Emacs下使用R的利器

ESS-Emacs Speak Statistics 是Emacs下使用R的一个交互环境,拿来开发调试R程序非常得心应手。而且整个的使用习惯很像是 Slime 下写Lisp,感觉很亲切。

Posted in Data, R | Tagged , | Leave a comment

简单介绍下在Common Lisp中调用R的方法

发在 统计之都论坛上的: http://cos.name/cn/topic/104458

前两天去第四届R语言会议,听各位大牛的讲座,讲到了 C, Perl, Excel, Matlab, C++, .Net 等与R的交互。这里我补充一个 Common Lisp中与R的交互方式。

首先试用的Lisp实现是 SBCL , (其他的 CLisp, CCL 等应该也是可以的,我没有尝试).
使用的库是 rcl 。 推荐安装库的方式是通过 quicklisp ,安装很简单:

(ql:quickload “rcl”)

安装好后,通过 asdf调入:

(asdf:oos ‘asdf:load-op “rcl”)

使用:

(use-package :rcl)
(r-init) ;; 首先初始化 R的环境

* (r “seq” 1 5) ; 调用 R的函数

(1 2 3 4 5) ; 返回的结果就是一个标准的Lisp列表

* (r “summary” ‘(3 5 7 2 9 12 52)) ;; 调用R的函数 , 传入的是一个标准的Lisp列表做参数

(2.0d0 4.0d0 7.0d0 12.86d0 10.5d0 52.0d0)
((:NAMES “Min.” “1st Qu.” “Median” “Mean” “3rd Qu.” “Max.”)
(:CLASS “summaryDefault” “table”))

可以看到 R与Common Lisp中的调用,数据交互是很方便的。

整个RCL接口库也很简单,只包含如下的方法:

* (listlib :rcl)

R
R%
R-INIT
WITH-DEVICE
ENABLE-RCL-SYNTAX

=====
实例: 调用R绘图:

(loadlib "rcl")
(use-package :rcl)
(r-init)
(enable-rcl-syntax)
 
(defun plot-1 ()
  (with-device ("/tmp/s0" :png)
    (r "hist"
       (r "rnorm" 100 :mean 10 :sd 1)
       :main "测试Lisp调用R绘图"
       :ylab "数量"
        lab "样本")))
 
(plot-1)

Posted in Uncategorized | Leave a comment

R统计软件交流会见闻

今天去人大参加R统计软件交流会议,收获很多。
第一,从老黄那学到一手nc的用法。回去要深度挖掘下,一定要用到最变态。
第二,两位演讲者讲的R的优化,以及一些扩展库,省去很多摸索的曲折。

基于nc的思路,我要把之前那个分布编译程序升级改造一下,利用起那些闲置计算资源。这个项目就叫ncdoop吧。

Posted in Data | Tagged , | 2 Comments

酷库:RCL – Common Lisp中调用R

R是功能强大的统计软件,和Lisp一样也有一个交互式的命令行环境,还有众多的扩展库,可以用来进行专业的统计分析。要在Common Lisp中方便的调用R的功能,可以试用rcl这个库。安装方法很简单,因为它已经纳入到quicklisp库中了:

(ql:quickload “rcl”)

使用:

span class="sy0"> * (use-package :rcl)
T
* (r-init)
T
* (r "R.Version")
("x86_64-pc-linux-gnu" "x86_64" "linux-gnu" "x86_64, linux-gnu" "" "2" "12.1"
 "2010" "12" "16" "53855" "R" "R version 2.12.1 (2010-12-16)")
((:NAMES "platform" "arch" "os" "system" "status" "major" "minor" "year"
  "month" "day" "svn rev" "language" "version.string"))
* (r "seq" 1 5)
(1 2 3 4 5)
* (r "*" 2 (r "seq" 1 5))
(2 4 6 8 10)
* (r "summary" '(123 543 3242 8934 234 643))
(123.0d0 311.2d0 593.0d0 2286.0d0 2592.0d0 8934.0d0)
((:NAMES "Min." "1st Qu." "Median" "Mean" "3rd Qu." "Max.")
 (:CLASS "summaryDefault" "table"))
Posted in LISP | Tagged | Leave a comment

今日宏: Anaphoric Macro

Anaphoric Macro 是“指代宏”。

作者:Paul Graham  ( On Lisp)

作用:简化语法结构

宏定义中,经常要小心“变量捕捉”,它有可能引入微妙的bug。但是如果合理使用它,会给程序带来简介性。指代宏,很像是 Perl 里面的 $_ 变量。

我们在程序中经常需要获得一个表达式的返回值,然后判断值是否为nil,然后再进行处理。通常的写法:

ret = expr()
if ret:
    do_something()

在Lisp中需要多打一些字:

(let ((ret (expr)))
    (when ret
             (do-something ret)))

这个语法结构经常重复出现,因此用宏将其简化:

;; Anaphoric Macro
(defmacro aif (test-form then-form &optional else-form)
  `(let ((it ,test-form))
     (if it ,then-form ,else-form)))
(defmacro awhen (test-form &body body)
  `(aif ,test-form
        (progn ,@body)))

 

现在只需要:

(awhen (expr)
     (do-something it))
Posted in LISP | Tagged | 2 Comments

在Lisp中使用Singleton Class 模式

很久没有说起或听到“设计模式”这个词了。

Common Lisp中的CLOS对OO的支持很灵活,体现在对class, instance, method 等的高度可控性上。由于Lisp的动态特性,很多时候,并不需要GoF的经典模式。但有些模式还是很好用的,例如singleton class。

废话不多说,直接上代码:

(代码来自:http://www.tfeb.org/programs/lisp/singleton-class.lisp

;;; Singleton 类的父类
(defclass singleton-class (standard-class)
  ((instance :initform nil)))
(defmethod validate-superclass ((class singleton-class)
                                (superclass standard-class))
  ;; it's OK for a standard class to be a superclass of a singleton
  ;; class
  t)
 
(defmethod validate-superclass ((class singleton-class)
                                (superclass singleton-class))
  ;; it's OK for a singleton class to be a subclass of a singleton class
  t)
 
(defmethod validate-superclass ((class standard-class)
                                (superclass singleton-class))
  ;; but it is not OK for a standard class which is not a singleton class
  ;; to be a subclass of a singleton class
  nil)
 
(defmethod make-instance ((class singleton-class)
                          &key)
  (with-slots (instance) class
    (or instance
        (setf instance (call-next-method)))))
 
(defvar *singleton-classes* '())
 
(defmethod initialize-instance :after ((c singleton-class) &key)
  (pushnew c *singleton-classes*))
 
(defun reset-singleton-classes ()
  ;; This means you will get new singletons from now on.
  (loop for c in *singleton-classes*
        do (setf (slot-value c 'instance) nil)))

 

要定义一个singleton class ,只需要在 defclass 中声明 metaclass:

(defclass foo ()
  ()
  (:metaclass singleton-class))

运行实例:

> (MAKE-INSTANCE 'foo)
#<FOO {1003B4F001}>
> (MAKE-INSTANCE 'foo)
#<FOO {1003B4F001}>
> (eq * **)
T
Posted in Uncategorized | Leave a comment

今日宏: dolist-bind

名称: dolist-bind

作者:Albert Lee

作用: dolist 与 destructuring-bind 的组合体。方便遍历带有结构的列表。

源代码:

(defmacro dolist-bind ((item list) &body body)
  (let ((list-rom-item (gensym)))
     `(dolist (,list-rom-item ,list)
       (destructuring-bind ,item ,list-rom-item
         ,@body))))

 

应用实例:

(setq lst '(("192.168.1.1" 10) ("192.168.1.2" 15) ("192.168.1.3" 20)))
 
(dolist-bind ((ip cnt) lst)
    (format t "~A : ~A~%" ip cnt))
>>
192.168.1.1 : 10
192.168.1.2 : 15
192.168.1.3 : 20
NIL
Posted in Uncategorized | 3 Comments

快速查询用户IP所处地理位置

统计网站访问用户的地理位置是一个常用的操作。

一般来说,ip地址库的记录格式如下:

(start-ip  end-ip   国家  省 市  …. )

可以把这些地址库记录放到数据库中,然后通过sql查询:

select * from ip-table where start-ip >= IP and end-ip <= IP limit 1;

这种方式比较简单。因为需要进行批量的统计,如果总是要去连接到数据库,有些不爽。

因此我用了另一种方法:把整个地址库放到内存中,占用空间在几百M内,存储在一个红黑树中。

我用的库是:  hh-redblack ,代码是 MIT协议的。以 start-ip 作为节点的 key ,以 end-ip 及地理位置信息作为节点的值。

这里有一个需要hack的地方:红黑树的 rb-get 函数只能找到一个特定的key,如果查询的值在ip段内,它不能直接查询。我通过读它的源代码,自己修改了两个函数,作用就是在查询时,如果找到特定的key,就返回它的节点,如果找不到这个key,就返回比它小的那个节点。然后再判断这个小一些的节点的  end-ip 值即可。

 

;; 增加的两个函数
(in-package :hh-redblack)
(defmethod rb-find2 ((tree red-black-tree) key)
  (let ((tmp-node nil))
    (loop with node = (root tree)
       until (leafp tree node)
       for comparison = (rb-key-compare key (key node))
       until (eq :equal comparison)
       do
         (progn
           ;(format t "KEY: ~A~%" (key node))
           (when (< (key node) key)
             (setq tmp-node node))
           (if (eq :less comparison)
               (setf node (left node))
               (setf node (right node))))
       finally (if (leafp tree node)
                   (return (values nil tmp-node))
                   (return (values node tmp-node))))))
 
(defmethod rb-get2 ((tree red-black-tree) key &optional (default nil))
 (multiple-value-bind (node tmp-node) (rb-find2 tree key)
   (if node
	(values (data node) t)
	(values (data tmp-node) nil))))
 
;; Tree node format :  ip-start(key)  : (ip-end 国家 省份 城市 ...)
;; Search tree
;; 在red-black tree 中
(defun rb-find-seg (tree key)
  (multiple-value-bind (val found) (hh-redblack::rb-get2 tree key)
    (if found
        (cdr val)    ;  ip-start == key
        (when (>= (car val) key)   ; 前一个段
          (cdr val)))))
 
;; sample line: (1 3402551296 3402555391 "中国" "河北" "保定" "" "" "" "")
 
(defun load-ip-tree (fn)
  (let ((ips (read (open fn)))
        (tree (make-red-black-tree)))
    (dolist (line ips)
      (rb-put tree (cadr line) (cddr line)))
    tree))
 
(defparameter ip-tree (load-ip-tree "ip.dat"))
 
(defun ip-s-2-i (ip)
  "将 192.168.1.1 类ip地址转换成数字"
  (handler-case
      (destructuring-bind (a b c d) (mapcar #'read-from-string (split-sequence #\. ip))
        (+ (* a 256 256 256)
           (* b 256 256)
           (* c 256)
           d))
    (error () nil)))
 
(defun find-ip (ip)
  (rb-find-seg ip-tree (ip-s-2-i ip)))
Posted in LISP | Leave a comment