本福德定律

2010年10月26日

当Shriram第一次发布这个练习时,我的解决方案使用了uniq-c型,组成数字来自标准前奏曲,加上非标准但非常有用的打印Chez Scheme的功能:

(定义(benford xs)
(每个人)
(λ(x)(打印f“~a~f~%”(汽车x)(/(cdr x)(长度xs)))
(uniq-c=(排序<(地图(合成汽车数字)xs))))

Shriram的评论是“我的单词-那很可爱。”在帖子的后面,Joe Marshall提出了一个Lisp函数来计算数字的第一个数字,对此我说“我的词-那很有趣:”

(defon最左边的数字(n个基数)
(如果(>基数n)
n个
(做*(下一步(i基))
(下一个(*底座)(*i i))
((>下一个n)(最左边的数字(楼层n i)基数)))

这是我对Scheme函数的翻译;制作基础默认值为10会使函数比原始值稍长:

(定义(第一位数字n.基数)
(让*((b(如果(null?基数)10(汽车基数)))
(b2(*b b))
(let循环((n n)(i b)(k b2))
(条件((<n b)n)
((<n k)
(循环(商n i)b b2))
(其他(回路n k(*i i))))

Shriram的第二个挑战是从CSV文件中提取第一位数的比例,例如上一页二者的文本文件数据库功能以前的 练习简单点。首先,我们编写一个谓词来保存有用的记录,并丢弃各种标头、“N/a”值和其他无用的记录:

(define(keep?xs)(字符串->数字(list-ref xs 3))

然后我们使用读取csv记录,过滤器端口地图还原端口以计算第一位百分比:

>(让*((fds(带输入from文件“mn-lakes.csv”)
(λ()
(地图还原端口
(过滤器端口读取-csv-记录保留?)
(λ(x)
(值
(第一位数字(楼层(字符串->数字(列表参考x 3)))
                        1))
(λ(k v1 v2)(+v1 v1))
                    <))))
(fds-count(应用+(映射cdr-fds)))
(每个(λ(x))
(打印f“~a~f~%”
(x车)
(/(cdr x)fds计数0.01))
fds))
1 32.05699020480855
2 19.768477292965272
3 12.733748886910062
4 9.082813891362422
5 6.678539626001781
6 6.144256455921639
7 5.253784505788068
8 4.452359750667854
9 3.8290293855743545

在测试期间,我编写了以下awk程序来比较结果:

awk-F,'
$4>0{c[子($4,1,1)]++;t++}
结束{对于(i=1;i<10;i++)打印i,c[i]/t*100}
'mn-lakes.csv

运行该程序产生的结果与Scheme程序不同;Scheme程序计算第一位数字1的一条记录由awk程序计算为第一位数字4。问题是记录

“海鸥,上部”,“尼斯瓦”,422154,54,7.5

简单的awk程序将“Gull,Upper”视为两个字段,而实际上它是一个字段,再次证明很难解析CSV文件。

您可以在以下位置运行程序http://programmingpraxis.codepad.org/7l3dRSAn.

页:1 2

12对“本福德定律”的回应

  1. […]今天的编程实践练习,我们的任务是看看Benford定律(小写数字更多[…]

  2. My Haskell解决方案(请参阅http://bonsaicode.wordpress.com/2010/10/26/programming-praxis-benford%E2%80%99s-法律/对于带有注释的版本):

    导入数据。列表导入文本。打印第一位数字::[Foat]->[(Char,Double)]firstDigits xs=map(\ds->(头ds,100*toEnum(长度ds))/toEnum(长度xs))。组。排序$map(head.show)xsshriram::[[String]]->[(Char,Double)]shriram xs=firstDigits[n|[(n,_)]<-map(读取。(!!3))xs]
  3. 格雷厄姆

    我直接跳过从csv文件中读取值,然后执行分析。我的Python解决方案:

    #!/usr/bin/env-python导入csvdef benford(csv文件,数字位置):"""计算numerical_position中第一个数字出现的百分比在有问题的csv文件中。"""r=csv.reader(打开(csv_file))d=dict(zip(范围(1,10),[0]*9))对于r中的行:尝试:d[int(行[numerical_position][0])]+=1除:通过总计=浮点(总和(d.值()))对于k in d:打印“%s:\t%.4s%%”%(k,100*d[k]/总计)返回如果__name__=='__main__':本福德('lakes.csv',3)

    在给定的csv文件(我将其命名为lakes.csv)上运行时,将生成:

    $ ./benford.py公司
    1: 32.0%
    2:19.7%
    3:12.7%
    4: 9.08%
    5: 6.67%
    6: 6.14%
    7: 5.25%
    8: 4.45%
    9: 3.82%

  4. 格雷厄姆

    对不起,我的输出张贴得一团糟!

  5. 赌徒

    与乔·马歇尔的类似:

    (定义(第一位数n基数)
    ;; 返回n的第一个基数
    (let((基数^2(*基数)))
    (秒((<n基数)n)
    ((<n基数^2)(商n基数)
    (否则
    (第一位(第一位n基数^2)基数))))

  6. 杀人

    一个ruby版本也将直接进行CSV计算…

    需要“csv”def benford(csv文件,位置)first_digits=数组.new(10,0)CSV.foreach(CSV_file)do|row|数字=行[位置].to_s[0]如果数字=~/[0-9],则first_digits[digit.to_i]+=1/结束第一位数字结束first_digits=benford(“lakes.csv”,3)total=first_digits.inject(0){|sum,v|sum+v}如果i!=,则first_digits.each_with_index{|v,i|将“#{i}#{(v.to_f/total.to_f)*100.0}的百分比”放入0 }
  7. Axio公司

    ;; 自然->数字
    (定义(头部-数量n)
    (let loop((n n))(如果(<n 10)n(loop(商n 10))))

    ;; 自然值列表->数字
    (定义(benford l)
    (let((res(使向量为10 0));;存储结果
    (计数0)
    (映射(λ(n);;递增每个看到的数字的计数器
    (let((i(head-of-num n)))
    (向量集!res i(+1(向量引用res i)))
    (设置!计数(+1计数))
    l)
    (地图(λ(i);;除以元素数
    (let((val(/(vector-ref res i)计数))
    (向量集!res i(列表i值(精确->不精确值)))
    (iota 09))
    res))

    (定义(测试数据)
    (本福德数据)

  8. Axio公司

    ;; 我更喜欢这个版本。
    (定义(头部-数量n)
    (let loop((n n))(如果(<n 10)n(loop(商n 10))))

    (定义(benford l)
    (让*(计数0)
    (res(左折叠式
    (λ(n态)
    (let((i(head-of-num n)))
    (向量集!状态i(+1(向量引用状态i))
    (设置!计数(+1计数))
    状态))
    (品牌矢量10 0)
    l))
    (映射(λ(x)(精确->不精确(/x计数)))(矢量->列表res)))

    (定义(测试数据)
    (本福德数据)

  9. Khanh Nguyen先生

    我的F#代码

    //将单个数字列表划分到存储箱中让分裂l=让rec拆分所有i=如果(i=9),则【ll】其他的让tt=列表分区(fun x->x=i)ll(fst-tt)::(split_aux(snd-tt)(i+1))split_aux l 0让rec first_digit x=如果x<10,则x else为first_digit(x/10)让benford l=let-first_digit_list=列表.map first_digit llet digits_counts=List.map List.length(拆分first_digit_List)//计算百分比List.map(fun x->(float x)/(float)(List.sum digits_counts))数字计数
  10. KNguyen公司

    我的F#实现:

    //将单个数字列表划分到存储箱中让我分开=让rec split_aux all i=如果(i=9),则【ll】其他的让tt=列表分区(fun x->x=i)ll(fst-tt)::(split_aux(snd-tt)(i+1))split_aux l 0让rec first_digit x=如果x<10,则x为第一位数字(x/10)让benford l=let-first_digit_list=列表.map first_digit llet digits_counts=List.map List.length(拆分first_digit_List)//计算百分比List.map(fun x->(float x)/(float)(List.sum digits_counts))数字计数
  11. 大卫

    然而,在FORTH中,我去掉了其中一个湖的引号中冒犯的逗号,而不是完全正确地解析csv…

    {--------------------拆分--------------------}{取自字符串库--------------}:(调整)(adr1 c1 adr2 ard3)2dup=如果在末尾2次丢弃0:0 2swap,则将余数设置为“”ELSE压区2拾取->r2向上r@1+/string\调整余数2swap下降r>\调整结果然后;:拆分(adr c delim--adr1 c1 adr2 c2)>r \保存分隔符2dup+2 pick \(adr c--adr c end adr adr)开始2dup>如果dup c@r@<>ELSE为false,则WHILE(当)1+重复r>下降(调整);{--------------本福德--------------}可变样本大小创建数字10个单元格分配:第n场(adr c delim n--adr c)交换本地人|熟食|0 ?DO delim分体式2滴回路熟食二分熟;:get-digit(地址计数--数字)0>如果IF中的c@dup[char]1[char 9 1+]文字[字符]0-ELSE公司下降-1然后ELSE公司下降-1然后;:count-digit(地址计数--)获取digit dup 0>IF单元格数字+1交换+!1个样本大小+!ELSE公司然后;:init-beford(--)数字10单元格0填充0样本大小;:导入字段(n fd--)局部变量|输入n|开始填充1024输入读线抛出WHILEpad swap[char],n个第n字段count-digitREPEAT下降;:四舍五入(n--n)10/mod掉期5+10/+;:.%(n--)10000个样本尺寸@*/四舍五入0<#[char]%保持#[char]。保持#s#>类型空间;:报告10 1完成铬i2.r。“:”i个单元格数字+@.percent回路;:benford(字段--)初始-边界bl字数r/o打开文件抛出2dup导入字段近距离抛投报告;

    执行:

    3 benford lakestats-mn.csv1: 32.1%2: 19.8%3: 12.7%4: 9.1%5: 6.7%6: 6.1%7: 5.3%8: 4.5%9:3.8%合格
  12. [……]约翰·库克(John D.Cook)是一位写数学的程序员(他可能会把自己描述成写编程的数学家),他最近写了一篇关于2的幂的前导数字的分布的文章,观察到它们遵循我们在前一个练习中研究过的本福德定律。[…]

留下评论