2013年10月10日 星期四

[R] OOP(1) class的寫法

OOP就是 object-oriented programming的縮寫

中文比較常見的翻譯是「物件導向」

我其實還蠻討厭把「物件導向」不斷掛在嘴上的人,因為我覺得這四個字非常難以顧名思義

尤有甚者,一大堆屬性啦、方法啦之類完全莫名其妙的名詞就是要嚇退那些剛剛接觸程式設計的人阿!

好啦曾經的我就是被嚇得很慘的人之一(愧)




言歸正傳,說到OOP,R裡語言中當然也是有class寫法的

R語言裡主要有兩種形態的class:S3和S4

S3 Class

在R中最原始的class就是S3 class

我們可以把任何東西指定一個S3 class,比如說一個list開始

假設我今天把a這個list指定給一個叫做BodyIndex的類別
> a<- list(name="John", weight=65, height=166)
> class(a)<- "BodyIndex"
> a
$name
[1] "John"

$weight
[1] 65

$height
[1] 166

attr(,"class")
[1] "BodyIndex"

我們現在就可以幫這個特定的class寫一個他的print
print.BodyIndex<- function(l){
    BMI<- l$weight/((l$height/100)^2)
    cat(l$name,"\n")    
    cat("BMI is ", BMI)
}

當我們再請系統把它print出來的時候
> a
John 
BMI is  23.58833

S3 class當然是可以繼承的
> b<- list(name="Tom", weight=75, height=172, sex="Male")
> class(b)<- c("profile","BodyIndex")
> b
Tom 
BMI is  25.35154

隨著需求,你可以改寫更多某個類別專屬的內建函數(generic function)

S4 Class

R語言裡也提供比較安全的S4類別,但是寫法就比較複雜了

首先要用setClass()定義class

然後用new()把特定的東西指向class
> setClass("BodyIndex",
+     representation(
+         name = "character",
+         weight = "numeric",
+         height = "numeric"
+     )
+ )
> a<- new("BodyIndex",name="John", weight=65, height=166)

在S4 class裡的member我們都叫做slot

我們可以用@把他們叫出來
> a@name
[1] "John"
> a@weight
[1] 65
> a@height
[1] 166

然後不同於S3 class,S4 class是用show()讓我們看到它裡面的slot
> show(a)
An object of class "BodyIndex"
Slot "name":
[1] "John"

Slot "weight":
[1] 65

Slot "height":
[1] 166

當然我們也可以修改它,只是要用setMethod()
> setMethod("show", "BodyIndex",
+     function(obj){
+         BMI<- obj@weight/((obj@height/100)^2)
+         cat(obj@name,"\n")    
+         cat("BMI is ", BMI)
+     }
+ )

> a
John 
BMI is  23.58833

S4 class的架構下可以用setGeneric()設定自己的generic function
> setGeneric("Warnning",
+     function(obj){
+         BMI<- obj@weight/((obj@height/100)^2)
+         if(BMI>35){
+             cat("You are over-weight")
+         }else{cat("You are normal")}
+     } 
+ )

> Warnning(a)
You are normal

當然也可以用setMethod()客制化

> setMethod("Warnning", "BodyIndex",
+     function(obj){
+         BMI<- obj@weight/((obj@height/100)^2)
+         if(BMI>35){
+             cat("You are over-weight")
+         }else{cat("Good for you~~")}
+     } 
+ )

> Warnning(a)
Good for you~~

2013年10月7日 星期一

[Mahout] Big Data(3) 天殺的馬浩如何跑kmeans??

最近在研究用Mahout跑Kmeans clustering

個人認為眉眉角角很多

網路上找得到的幾乎都是文檔分群的範例

讓在嘗試的時候非常吃力


請看步驟:




1. 轉檔(.csv => sequence file)

個人認為這裡很關鍵

mahout裡似乎是沒有可以直接用的commend line

必須要自己寫JAVA轉檔

這裡附上我的JAVA code

獻醜了

import java.io.*;
import java.util.*;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.io.SequenceFile.Writer;
import org.apache.hadoop.io.Text;
import org.apache.mahout.math.*;
 
 
public class Convert2Seq {
 
  public static void main(String args[]) throws Exception{
  
        //轉好的檔案命名為point-vector
        String output = "~/point-vector";
        FileSystem fs = null;
        SequenceFile.Writer writer;
        Configuration conf = new Configuration();
        fs = FileSystem.get(conf);
        Path path = new Path(output);
        writer = new SequenceFile.Writer(fs, conf, path, Text.class, VectorWritable.class);
        
        //所有的csv檔都在factory路徑底下
        File folder = new File("~/factory");
        File[] listOfFiles = folder.listFiles();
            
        //分批把factor路徑底下的csv轉成name-vector格式之後寫進point-vector裡面
        for (int i=0; i<listOfFiles.length; i++){
        
            String input = listOfFiles[i].toString();
        
            VectorWritable vec = new VectorWritable();
            try {
                FileReader fr = new FileReader(input);
                BufferedReader br = new BufferedReader(fr);
                String s = null;
                while((s=br.readLine())!=null){    
                    String spl[] = s.split(",");
                    String key = spl[0];
                    Integer val = 0;
                    double[] colvalues = new double[1000];
                    for(int k=1;k<spl.length;k++){
                                colvalues[val] = Double.parseDouble(spl[k]);
                                val++;
                    }
                    NamedVector nmv = new NamedVector(new DenseVector(colvalues),key);
                    vec.set(nmv);
                    writer.append(new Text(nmv.getName()), vec);
                }
            } catch (Exception e) {
                System.out.println("ERROR: "+e);}
       }writer.close();
    }    
}

接下來在compile的時候要記得指定classpath

javac -classpath/{hadoop_home}/hadoop-core-0.20.2-cdh3u1.jar
    :/{mahout_home}/{mahout_version}/core/target/mahout-core-0.5.jar
        :/{mahout_home}/{mahout_version}/core/target/mahout-core-0.5-job.jar
        :/{mahout_home}/{mahout_version}/core/target/mahout-core-0.5-sources.jar
        :/{mahout_home}/{mahout_version}/math/target/mahout-math-0.5.jar
        :/{mahout_home}/{mahout_version}/math/target/mahout-math-0.5-sources.jar
        :/{mahout_home}/{mahout_version}/math/target/mahout-math-0.5-tests.jar Convert2Seq.java
 
 
java -Djava.library.path=/{hadoop_home}/lib/native/Linux-amd64-64 
     -cp .:/usr/local/hadoop-0.20.2-cdh3u1/hadoop-core-0.20.2-cdh3u1.jar
     :/{mahout_home}/{mahout_version}/core/target/mahout-core-0.5.jar
     :/{mahout_home}/{mahout_version}/core/target/mahout-core-0.5-job.jar
     :/{mahout_home}/{mahout_version}/core/target/mahout-core-0.5-sources.jar
     :/{mahout_home}/{mahout_version}/math/target/mahout-math-0.5.jar
     :/{mahout_home}/{mahout_version}/math/target/mahout-math-0.5-sources.jar
     :/{mahout_home}/{mahout_version}/math/target/mahout-math-0.5-tests.jar Convert2Seq

基本上這樣就可以了

忍不住再怨一下,轉這個超煩!

2. Canopy clustering

在做kmeans的時候,mahout會要求要有initial cluster

mahout裡的canopy cluster就可以幫我們生出來


$mahout canopy 
-i point-vector 
-o center-vector #結果存在center-vector裡 
-dm org.apache.mahout.common.distance.SquaredEuclideanDistanceMeasure 
-t1 500 -t2 250 
-ow 
-cl

然後就可以用他的結果(就是center-vector啦!)做kmeans clustering了~

t1、t2參數的設定和相關原理請參考線上mahout文件


3. Kmeans clustering

input是轉好的point-vector data
center是canopy生出來的initial clusters
output就取一個自己喜歡的名字囉~

$mahout kmeans 
-i point-vector 
-c center-vector 
-o clusters 
-dm org.apache.mahout.common.distance.SquaredEuclideanDistanceMeasure 
-x 20 
-cl 
-k 15 
-ow


4. dumping clustering result

跑完之後

結果是存在~clusters/clusterPoints裡面

因為是sequence file格式,得動用到seqdumper把他轉成看得懂的格式

檔案通常不止一個,用for-loop打他們通通打回原形~~~

typeset -i i
let i=1
for file in `$hadoop fs -ls clusters/clusteredPoints | grep 'part' | awk '{print $8}'`
do
 
 $mahout seqdumper -s $file -o ~/$i.txt
 let i++
done

2013年10月2日 星期三

[無關程式] AIC和統計建模


這篇是我最近在讀這本書的一些些筆記,主題是AIC,除非你這個人夠無聊又極富耐性,不然請慎入(是說這個網誌除了我以外大概也沒有其他人會來吧吧吧吧)

沒耐性的就早早洗洗睡了吧

AIC就是Akaike Information Criterion的縮寫,在使用各種常見的統計方法進行建模時,常常都會用它來作為評估模型好壞的指標

顧名思義,這個指標是由一個叫做Akaike的人提出的,基本上不要試著用英文去唸這個字,因為他是日本人。這個人的名字應該要唸成『阿-咖-咿-擠』

噢扯遠了

言歸正傳,AIC基本上長這樣:

$-2log(L)+2p $

其中$log(L)$就是的log-likelihood然後$p$是參數的數目


先來看看看最大概似估計(maximum likelihood estimator)吧:

假設我們現在有一筆資料$x_n$,我們假設有一個模型$f(x|\theta)$是這筆資料最好的描述,我們必須解出$\theta$!

maximum likelihood estimator幫我們找到的是這樣的解 $\widehat{\theta}_n$:

$\widehat{\theta}_n = \operatorname*{arg\,max}_{\theta  \in  \Theta } log\big(f(x_n|\theta)\big)$

然而,夠大的log-likelihood就行了嗎?其實不然,在maximum likelihood estimate的架構下,一味追求把$log\big(f(x_n|\theta)\big)$變大其實會帶來非常不合理的結果

舉個非常簡單的例子,線性迴歸模型(linear regression model):

$Y=\bf{X^T} \bf{\beta}+\epsilon$       $\epsilon\sim N(0,\sigma^2)$

likelihood function長這樣:


$f(y_i|\bf{x_i};\beta) = \frac{1}{2\pi\sigma^2} exp\big\{ -\frac{1}{2\sigma^2}(y_i-\bf{x^T_i} \bf{\beta})^2\big\}$


log-likelihood如下:


$l(\widehat{\beta}) = \sum_{i=1}^n logf(y_i|x_i;\beta) $

                                        $= - \frac{n}{2} 2log(\pi \sigma^2)  -\frac{1}{2\sigma^2} \sum_{i=1}^n(y_i-\bf{x^T_i}\beta)^2 $ 


如果我們的目的只是要讓$l(\widehat{\beta})$變小,我們就只要無止盡的增加$\bf{x^T_i}\beta $的維度,就可以讓每個$y_i-(x^T_{i1} \beta_1+x^T_{i2}\beta_2+x^T_{i3}\beta_3+...)$變得超小。但是這樣反而會使model裡有太多沒用的預測子,造成over-fitting的問題


因此,單靠夠大的log-likelihood是不夠的!!!


接下來插播Kullback-Leibler Divergence ($KL_{D}$):

$KL_{D}$是一個表示兩個pdf距離的量,定義是:


$KL_{D} =\int g(z)\frac{g(z)}{f(z)} dx$

其中$g(z)$是true probability 
$f(z)$則是model

其實也就G(Z)是真實pdf的情況下,一個log-likehood的概念

$E_{G}  \left[log \frac{G(Z)}{F(Z)} \right]$


啊這到底和統計建模有筍磨關係?


$KL_{D}$、統計建模和log-likelihood

其實,統計建模的精神就是,我們永遠不知道真實的分配$G(Z)$長怎樣,所以我們就去創造一個叫做$F(Z)$的model來模擬$G(Z)$。換句話說,$F(Z)$和$G(Z)$越接近,我們對$F(Z)$就越有把握

所以我們希望$KL_{D}\big(G,F\big)$很小,最好小到不能再小,這樣就表示我們的$F(Z)$非常完美

$KL_{D}\big(G,F\big)= E_{G}\left[\textrm{log} \frac{G(Z)}{F(Z)} \right]$

$=E_{G}\left[\textrm{log} g(Z)\right]-E_{G}\left[\textrm{log}f(Z)\right]$

$E_{G}\left[\textrm{log} g(Z)\right]$是一個常數,基本上我們對他無能為力。我們只能盡量讓$E_{G}\left[\textrm{log}f(Z)\right]$變大,只要$E_{G}\left[\textrm{log}f(Z)\right]$夠大,就可以讓$KL_{D}\big(G,F\big)$就夠小,我們的model就越完美!

所以,請記得,越好的model的可以使得

$E_{G}\left[\textrm{log}f(Z)\right]$夠大!



log_likelihood的誤差估計

我們回到熟悉的log-likelihood:

$l(\widehat{\theta}) = \sum_i^n \textrm{log}f(x_i|\widehat{\theta})$

$\frac{1}{n} \sum_i^n \textrm{log}f(x_i|\widehat{\theta}) \rightarrow \int \textrm{log}f(z|\widehat{\theta})d \widehat{G}(z) = E_\widehat{G}\left[{log}f(Z|\widehat{\theta})\right]$

所以照理來說,$l(\widehat{\theta})$應該是$nE_\widehat{G}[{log}f(Z|\widehat{\theta})]$)的估計值,但是因為使用了同一筆資料兩次(先估計$\theta$再用來估計$nE_\widehat{G}[{log}f(Z|\widehat{\theta})]$)使得這樣的估計出現了偏誤(bias)

我們把這個bias寫成

$b(G) = E_G( \bf{x_n})\left[\textrm{log}f(\bf{X_n}|\widehat{\theta}(\bf{X_n}))-nE_G(z) \left[\textrm{log} f(Z|\widehat{\theta}(\bf{X_n}))\right]\right]$

假設當$n\rightarrow\infty$時$\theta_n$會逼近真實的值$\theta_0$

我們把剛剛的$b(G)$改寫一下,改成$D1$、$D2$和$D3$的相加


$b(G) = E_G( \bf{x_n} )\left[\textrm{log}f(\bf{X_n}|\widehat{\theta}(\bf{X_n}))-nE_G(z) \left[\textrm{log}f(Z|\widehat{\theta}(\bf{X_n}))\right]\right]$

$=E_G( \bf{x_n})\left[\textrm{log}f(\bf{X_n}| \widehat{\theta}( \bf{X_n} ))-\textrm{log}f(\bf{X_n}|\theta_0)\right]...D1$

$+E_G( \bf{x_n})\left[\textrm{log}f(\bf{X_n}|\theta_0)-nE_G(z) [\textrm{log}f(Z|\theta_0)]\right]...D2$

$E_G( \bf{x_n})\left[nE_G(z) \left[\textrm{log}f(Z|\theta_0)\right]-nE_G(z) [\textrm{log}f(Z|\widehat{\theta}(\bf{X_n}))]\right]...D3$

計算$D1$:

先把$logf(\bf{X_n}|\theta_0)$寫成$l(\theta_0)$

然後搬出泰勒展開式

$l(\theta_0) \sim l(\widehat{\theta}) + (\theta_0-\widehat{\theta})^T\frac{\partial l(\widehat{\theta})}{\partial \theta} + \frac{1}{2}(\theta_0-\widehat{\theta})^T\frac{\partial^2 l(\widehat{\theta})}{\partial \theta \partial \theta^T} (\theta_0-\widehat{\theta})$

因為maximum likelihood estimator基本上就是在找可以使$\frac{\partial l(\widehat{\theta})}{\partial \theta}$為0的$\theta$,所以

$(\theta_0-\widehat{\theta})^T\frac{\partial l(\widehat{\theta})}{\partial \theta}=0$

maximum likelihood estimator在大數法則下:

$\frac{\partial^2 l(\widehat{\theta})}{\partial \theta\partial \theta^T} \rightarrow nJ(\theta_0)$

然後$D1$就可以寫成

$E_G(x_n)\left[l(\widehat{\theta}) - l(\theta)\right]$

$=\frac{n}{2}E_G(x_n)\left[(\theta_0-\widehat{\theta})J(\theta_0)(\theta_0-\widehat{\theta})^T\right]$

$=\frac{1}{2}tr\big\{I(\theta_0)J(\theta_0)^{-1}\big\}$

其中:

$I(\theta_0)=\int g(x)\frac{\partial \textrm{log}f(x|\theta)}{\partial \theta}\frac{\partial \textrm{log}f(x|\theta)}{\partial \theta^T}dx$

$J(\theta_0)=\int g(x)\frac{\partial^2 \textrm{log}f(x|\theta)}{\partial \theta \partial \theta^T}dx$


計算$D2$:

$E_G( \bf{x_n})\left[\textrm{log}f(\bf{X_n}|\theta_0)-nE_G(z) [\textrm{log}f(Z|\theta_0)]\right]$

$=E_G( \bf{x_n})\left[\sum_{i=1}^n\textrm{log}f(\bf{X_i}|\theta_0)\right]-nE_G(z)\left[ [\textrm{log}f(Z|\theta_0)]\right]$

$=0$


計算$D3$:

先把$nE_G(z) \left[\textrm{log}f(Z|wide_theta{\theta})\right]$寫成$\eta(\widehat{\theta})$

然後再度搬出泰勒展開式:

$\eta(\widehat{\theta}) \sim \eta(\theta_0) + \sum_{i=1}^n(\widehat{\theta}_i-\theta_i^{(0)})\frac{\partial \eta(\theta_0)}{\partial \theta_i} +\frac{1}{2}\sum_{i=1}^n\sum_{j=1}^n(\widehat{\theta}_i-\theta_i^{(0)})(\widehat{\theta}_j-\theta_j^{(0)})\frac{\partial^2 \eta(\theta_0)}{\partial \theta_i \partial \theta_j}$


和在計算$D1$時一樣,

$\frac{\partial \eta(\theta_0)}{\partial \theta_i}=E_G(z)\left[\frac{\partial}{\partial theta_i} \textrm{log} f(Z|\theta)\right|\theta_0] = 0,$   $i=1,2,...n$

因此

$\eta(\widehat{\theta}) \sim \eta(\theta_0) - \frac{1}{2}(\theta_0-\widehat{\theta})J(\theta_0)(\theta_0-\widehat{\theta})^T$

$D3$就可以寫成

$nE_G(z) \left[\eta(\theta_0)-\eta(\widehat{\theta})\right]$

$=nE_G(z) \left[\frac{1}{2}(\theta_0-\widehat{\theta})J(\theta_0)(\theta_0-\widehat{\theta})^T\right]$

$=\frac{n}{2}tr \big\{J(\theta_0)E_G(z) \left[(\theta_0-\widehat{\theta})(\theta_0-\widehat{\theta})^T\right]\big\}$

$=\frac{1}{2}tr\big\{I(\theta_0)J(\theta_0)^{-1}\big\}$


現在我們把$D1$、$D2$和$D3$加起來

$b(G)=\frac{1}{2}tr\big\{I(\theta_0)J(\theta_0)^{-1}\big\}+0+\frac{1}{2}tr\big\{I(\theta_0)J(\theta_0)^{-1}\big\}$

$=tr\big\{I(\theta_0)J(\theta_0)^{-1}\big\}$


現在我們回過頭來看看$I(\theta_0)$和$J(\theta_0)$

$-J(\theta_0)=\int g(x)\frac{\partial^2 \textrm{log}f(x|\theta)}{\partial \theta \partial \theta^T}dx$

$=E_G\left[\frac{1}{f(x|\theta)}\frac{\partial^2 }{\partial \theta \partial \theta^T}f(x|\theta)\right]-E_G\left[\frac{\partial}{\partial \theta_i} \textrm{log}f(x|\theta) \frac{\partial}{\partial \theta_j }\textrm{log} f(x|\theta)\right]$

當$g(x)=f(x|\theta_0)$時

$E_G\left[\frac{1}{f(x|\theta)}\frac{\partial^2 }{\partial \theta \partial \theta^T}f(x|\theta)\right]$

$=\int \frac{\partial^2}{\partial \theta_i \partial \theta_j} f(x|\theta_0)dx$

$=\frac{\partial^2}{\partial \theta_i \partial \theta_j}\int  f(x|\theta_0)dx=0$

這個時候$I(\theta_0)$就會等於$J(\theta_0)$

$b(G) =tr\big\{I(\theta_0)J(\theta_0)^{-1}\big\}$

$=tr(I_p) = p$


AIC、log-likelihood和$b(G)$

AIC其實就是

$-2(\textrm{log-likelihood})+2(\textrm{estimator of }b(G))$

因此AIC越小表示model越好

log-likelihood和$b(G)$代入就完成了!

$AIC = -2log(L)+2p$

參考資料:

Konishi, Sadanori, Kitagawa, Genshiro (2007). Information criteria and statistical modeling. Springer

2013年10月1日 星期二

[JAVA] Big Data(2) 終於寫出小兒科等級的mapreduce!!!

先來個最近當紅的半澤直樹



在Big Data的時代,很多工具都可以做mapreduce的計算,甚至不用知道mapreduce的原理
像是Hive, Pig
又或者是更有彈性的R的rmr2套件

說穿了以上的解決方案底層的邏輯都還是把較簡單的程式碼轉換成java code再執行
因此,為了炫耀或是其他更重要目的,用java寫mapreduce還是有其必要性的(肯定貌)

用java寫mapreduce的架構主要有三個部分:
1.Map class
2.Reduce class
3.主程式

在建立好Map和Reduce兩個class以後
再於主程式內用job方法呼叫
另外job方法也用來設定運行時的指令和資料輸入

說了一大堆,實際開始寫code才發現太複雜的mapreduce我也hadle不了啦(逃~~)
只好從小怪開始打起
wordcount的範例在網路上實在太多了有點蘚
所以就來做個平均數計意思意思一下

首先data長這樣,已經丟到hadoop上了是用逗點分隔的
我希望計算Tom和Mary等人三科的平均分數

$hadoop fs -cat chinese.txt
Tom,90
Mary,95
Lisa,94
Luke,87
Marx,76
Teresa,89

$hadoop fs -cat math.txt:
Tom,67
Mary,68
Lisa,75
Luke,82
Marx,66
Teresa,74

$hadoop fs -cat science.txt:
Tom,56
Mary,75
Lisa,85
Luke,96
Marx,74
Teresa,69


java code在這:

import java.io.IOException;
import java.util.StringTokenizer;
import java.util.Iterator;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.filecache.DistributedCache;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.Mapper.Context;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
import org.apache.hadoop.util.StringUtils;

public class Avg{

 //map步驟
 public static class Map extends Mapper {
 
  //撰寫map方法
  public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
      String line = value.toString();//數據先轉成字串(String)
      StringTokenizer script = new StringTokenizer(line, "\n");//分割數據
      while (script.hasMoreElements()) {
       StringTokenizer scriptLine = new StringTokenizer(script.nextToken());
           //將Key和Value用逗號(",")分開
              Text Name = new Text(scriptLine.nextToken(","));
              int Score = Integer.parseInt(scriptLine.nextToken(","));
              context.write(Name, new IntWritable(Score));
      }
  }
 }
 
 //reduce 步驟
 public static class Reduce extends Reducer {
         //撰寫reduce方法
   public void reduce(Text key, Iterable value, Context context) throws IOException, InterruptedException{
          int numerator = 0;//初始化分子
          int denominator = 0;//初始化分母
          for (IntWritable v : value) {
                  numerator += v.get();//分子累加
                  denominator ++;//分母每次+1
          }
          int avg = numerator/denominator;//相除
             context.write(key,new  IntWritable(avg));
         }
 }
 
 //主程式
 public static void main(String[] args) throws Exception {
 
   Configuration conf = new Configuration();
   String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
         Path dst_path = new Path (otherArgs[1]);
         FileSystem hdfs = dst_path.getFileSystem(conf);
 
         //檢查OUTPUT的路徑是否存在,有的話就宰了他!
         if (hdfs.exists(dst_path)){
          hdfs.delete(dst_path, true);
         };
 
         Job job = new Job(conf, "Avg");
            job.setJarByClass(Avg.class);
            job.setMapperClass(Map.class);
            job.setCombinerClass(Reduce.class);
            job.setReducerClass(Reduce.class);
            job.setOutputKeyClass(Text.class);
            job.setOutputValueClass(IntWritable.class);
            FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
            FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));

            System.exit(job.waitForCompletion(true) ? 0 : 1);
         }
 }


寫完之後還沒結束
得先用commend line把code做成一個job

mkdir test_classes javac -classpath /{hadoop_home}/hadoop-core-0.20.2-cdh3u1.jar
:/{hadoop_home}/commons-cli-1.2.jar : -d test_classes Avg.java
jar -cvf ~/Avg.jar -C test_classes/ .

用javac編譯的時候記得要用-classpath指令把參考的library指給他(很重要)
之後再把它打包成.jar的檔案
之後就可以用hadoop jar指令執行了!
$hadoop jar ~/Avg.jar org.test.Avg {input} {output}

執行完來看看結果
$hadoop fs -cat ~/part-m-0000

Luke    88
Marx    72
Mary    79
Teresa  77
Tom     71



------ 後記:

其實這樣的東西不是很夠用 T_T 稍微進階版的Multiple input可以參考另一篇

2013年9月11日 星期三

[R] 效能(3) hash套件

hash table其實就是一種key-value的資料格式
像是Java的HashMap、Python裡的Dictionary等等

在R裡的list也是一種key-value資料格式,個人覺得蠻好用的,想塞甚麼就塞甚麼
但是如果要塞進list的東西很多,就會遇到麻煩的效能問題,就是速度會拖慢啦

hash套件提供一種key-value的資料格式就叫hash
在執行速度上比list要來得快頗多


1. 使用.set(hash, key = value,...) 函數給定key-value值

> library(hash)
>
> test<- hash()
>
> .set( test,
+   name = "AirQuality",
+   May = datasets::airquality[which(datasets::airquality$Mon==5),],
+   Jun = datasets::airquality[which(datasets::airquality$Mon==5),],
+   Jul = datasets::airquality[which(datasets::airquality$Mon==5),],
+   Aug = datasets::airquality[which(datasets::airquality$Mon==5),]
+  )
> 

然後就可以像list一樣輸入key值叫出value了!

> head(test[["May"]])
  Ozone Solar.R Wind Temp Month Day
1    41     190  7.4   67     5   1
2    36     118  8.0   72     5   2
3    12     149 12.6   74     5   3
4    18     313 11.5   62     5   4
5    NA      NA 14.3   56     5   5
6    28      NA 14.9   66     5   6
>
> head(test$May)
  Ozone Solar.R Wind Temp Month Day
1    41     190  7.4   67     5   1
2    36     118  8.0   72     5   2
3    12     149 12.6   74     5   3
4    18     313 11.5   62     5   4
5    NA      NA 14.3   56     5   5
6    28      NA 14.9   66     5   6
>

或是直接insert key-value也可以

> test$"Sep"<- datasets::airquality[which(datasets::airquality$Mon==5),]
> 
> head(test[["Sep"]])
  Ozone Solar.R Wind Temp Month Day
1    41     190  7.4   67     5   1
2    36     118  8.0   72     5   2
3    12     149 12.6   74     5   3
4    18     313 11.5   62     5   4
5    NA      NA 14.3   56     5   5
6    28      NA 14.9   66     5   6


2. 用 has.key(key,hash) 和 keys(hash) 函數檢查hash裡有哪些key

> has.key(c("May","Jun"),test)
 May  Jun
TRUE TRUE
> keys(test)
[1] "Aug"  "Jul"  "Jun"  "May"  "name" "Sep"

3. 用copy(hash)函數複製hash

官方文件裡建議不要直接用<- assign給某物件,所以在assign的時候最好用copy(hash)函數把hash直接複製給物件

> test2<- copy(test)


4. 用clear(hash)函數清理hash

如果直接用rm(hash)的話,hash所佔據記憶體容量並不會釋放,得先用clear(hash)把hash清空然後再刪掉

> clear(test)
> is.empty(test)
[1] TRUE
> rm(test)

5. 效能比較

最後來做一個無聊實驗,比較把資料塞進進list和塞進hash裡在效能上究竟熟優熟劣

> test1<- hash()
> test2<- list()
> system.time(
+  for (i in 1:10000){
+   test1[[as.character(i)]]<- 1:i
+  }
+ )
   user  system elapsed
  1.082   0.059   1.139
> system.time(
+  for (i in 1:10000){
+   test2[[as.character(i)]]<- 1:i
+  }
+ )
   user  system elapsed
  1.770   0.199   2.057

速度大概是兩倍左右,完畢!



2013年9月9日 星期一

[Python] 超級基本的網頁抓取

這篇是完全沒有基礎的我最近的小小心得

厲害的爬蟲技巧在這裡完全都沒有喔~~~

沒辦法誰叫我實在是嫩了!




抓取步驟(EX: 中央氣象局台北市氣溫預報)

第一步:

先到想去的網頁,記下網址(廢話)

http://www.cwb.gov.tw/V7/forecast/taiwan/Taipei_City.htmimport urllib2

到想抓的東西上反藍後「檢查元素」



找到他的標籤

像我要找的這個東西的標簽就是「td」!!




然後把python打開

把該import的套件import(他們都是python內建的,算是非常仁慈)

然後繼承SGMLParser寫成一個叫做WeatherList的類別

『is_td』是SGMLParser內建的,因為我們要抓的東西是被「td」標簽的,所使在這裡是使用is_td,如果有不同需求也有is_a之類的可以使用。之後定義start_td和end_td函數,最後定義handle_data函數把被td標簽包住的東西全寫進name裡面。

import urllib2
from sgmllib import SGMLParser
 
class WeatherList(SGMLParser):
    is_td=""
    name=[]
    def start_td(self, attrs):
        self.is_td = 1
    def end_td(self):
        self.is_td=""
    def handle_data(self, text):  
        if self.is_td:
                self.name.append(text)  

寫完之後就可以開始抓囉!
content = urllib2.urlopen('http://www.cwb.gov.tw/V7/forecast/taiwan/Taipei_City.htm').read()

Tempreature = WeatherList()
Tempreature.feed(content)

for i in Tempreature.name:
    if '\t' not in i:
        print i.decode('utf-8')

首先先用urllib2的工具把目標網頁上的東西抓下來

然後把name裡的東西排除不要的東西(「\t」這種東西就別來亂了)

再把東西印出來,就可以囉~~
26 ~ 30
舒適至悶熱
0 %
26 ~ 34
舒適至易中暑
0 %
26 ~ 30
舒適至悶熱
0 %
31.1
24.8
360.5
05:38
18:05
08:53
20:27
°C
°F

2013年8月30日 星期五

[R] 效能(2) compiler套件

Compiler套件的功能是把寫好的R code變成位元碼(byte code),以加快執行速度。

對於懶得動腦優化程式的人還真是一大福音。

用下面這個蠢到不行的function來做demo,這個function傳回的是一條由1到n取log 的向量:

demo<- function(n){
  test<- 1:n
  for(i in length(test)){
    test[i]=log(test[i])
  }
  return(test)
}

用cmpfun函數把它轉成位元碼

> democmp<- compiler::cmpfun(demo)

先來做個十萬筆來比較看看有沒有變快

> system.time(a<- demo(100000))
   user  system elapsed 
  0.142   0.000   0.140 
> system.time(a<- democmp(100000))
  user  system elapsed 
  0.025   0.000   0.024 


現在我們把處裡的資料從十萬筆慢慢拉大到一百萬試試看!
經過窮極無聊的實驗可以發現,隨著函數處裡的資料量,效率的差別也會越明顯。在做大量資料運算的compile真的會是個好幫手喔!!!

2013年8月29日 星期四

[R] Big Data(1) rmr2套件 多重input

rmr2是一個可以使用R語言在Hadoop上做map-reduce的套件。

尚不知Hadoop和mapreduce為何物的人請參考這篇文章

以往做過的東西和網路上看得到的demo幾乎都是單一dataset利用鍵值(key)打散然後做平行運算。然而最近在處理的問題必須要把不同來源和結構(schema)的資料送到同一個node裡做運算,想說網路上找demo code卻遍尋不著,整個讓我非常頭大。

就在我試了老半天之後,竟然就成功了!!!於是就來寫一篇網誌告訴大家遇到好多個dataset的時候該怎麼辦~~~

用來demo的三組資料A、B、C
我們要做這件事:

資料長這樣(我隨便亂生的)。
> head(A)
  key         A1         A2         A3
1   1 -1.0348640  1.8177439  0.1352576
2   3 -1.3735558 -0.2437948 -0.4509937
3   2 -0.2034888  1.0297576  0.6305115
4   1  0.2270242  0.9087429 -0.4122123
5   3 -0.3290382 -0.4840644 -0.3688641
6   3 -0.1822808 -1.1303439 -0.4175791
> head(B)
  key           B1         B2          B3          B4
1   3  0.363861211  1.5158812 -1.20591630  0.08659873
2   3 -0.001122564  0.1037150  0.25809288  1.60135858
3   2  1.465006010 -0.4572000 -1.89767865 -0.60817508
4   2  1.964748118  0.8320135  0.50937176  0.77755846
5   1 -0.390667063  0.8493213  0.09075889  0.36958850
6   1 -0.768992997  0.7308232 -0.82277576  0.33674132
> head(C)
  key         C1         C2
1   1  0.4192436  0.1554905
2   2 -0.2125050 -1.4696090
3   1  0.3410178  0.3290381
4   2 -2.2716488  1.3529220
5   2 -0.2565037 -0.1575783
6   2 -0.4259541  0.1968482
接下來用函數split,把資料打散成一份一份的存成list格式。
> A_wk<- split(A,A$key)
> head(A_wk)
$`1`
   key         A1         A2          A3
1    1 -1.0348640  1.8177439  0.13525756
4    1  0.2270242  0.9087429 -0.41221232
13   1 -0.3573558 -1.2751938 -0.03458945
14   1 -0.7453312 -1.1503369  1.08577621
16   1  0.8465141  0.2366092  0.91902192
19   1  1.4896751  0.3213586 -0.98961302
23   1 -0.3143099  2.0754432 -1.29391057

$`2`
   key          A1          A2          A3
3    2 -0.20348880  1.02975761  0.63051151
7    2  1.53614888  1.96886642  0.04558348
9    2 -0.07431669 -0.03700706 -1.47200277
10   2  0.66355253  0.07667024 -1.22673427
17   2  1.13416422 -1.69200417 -0.13861365
18   2 -0.99696590  0.24465904  0.54821302
24   2 -0.44196754 -0.28170710 -0.73912548
27   2 -1.34823336 -0.06120274  2.12261003
30   2  1.83861168 -0.02982669  0.14312250

$`3`
   key         A1         A2         A3
2    3 -1.3735558 -0.2437948 -0.4509937
5    3 -0.3290382 -0.4840644 -0.3688641
6    3 -0.1822808 -1.1303439 -0.4175791
8    3  1.2317304 -0.7572487 -0.4401060
11   3 -0.4940248 -0.1259619 -1.1145702
12   3 -1.4488153 -0.9855823 -0.7537385
15   3 -0.6147528  0.6804414 -0.7799006
20   3  0.5340705 -0.2427455 -1.5272875
21   3 -1.2019567 -0.1434495 -0.3046498
22   3  0.1311908 -0.4900816  0.8861471
25   3 -1.1544569 -0.1732862 -2.2312314
26   3 -1.3264688 -0.6784207  1.5171326
28   3  1.1866616 -1.9195358  0.3591871
29   3  0.7476575 -0.3390230 -1.6448516

> B_wk<- split(B,B$key)
> head(B_wk)
$`1`
   key          B1         B2          B3            B4
5    1 -0.39066706  0.8493213  0.09075889  0.3695884990
6    1 -0.76899300  0.7308232 -0.82277576  0.3367413230
8    1 -1.05567857 -0.5663445  0.32075285  1.0807403069
9    1 -0.07174419 -0.6553943 -0.30134811 -1.2155568454
13   1 -0.39760179  0.5973388 -0.43153826 -0.0003626449
14   1  0.38234556 -0.4762401  0.90686094 -3.8579677970
15   1 -0.73177601 -0.6438049 -1.52620752  0.0814186088
20   1  0.07927141 -1.7918052 -1.27799659  0.1533002628

$`2`
   key          B1         B2          B3         B4
3    2  1.46500601 -0.4572000 -1.89767865 -0.6081751
4    2  1.96474812  0.8320135  0.50937176  0.7775585
7    2  0.35856113  0.1048170 -0.76270331 -0.5114040
10   2  1.11808088 -0.5707235 -0.16225111 -1.0749321
12   2 -0.32032713 -0.7167343 -0.03320639  0.2495948
18   2  1.36768551  1.1874533  2.13816520  1.0105115
19   2  0.02825361  0.8781400 -1.44303311  1.2391620

$`3`
   key           B1         B2         B3          B4
1    3  0.363861211  1.5158812 -1.2059163  0.08659873
2    3 -0.001122564  0.1037150  0.2580929  1.60135858
11   3  0.180619368 -0.8830636  0.7562675  1.09992035
16   3  2.644110325 -1.8546195  2.4887309 -0.03694847
17   3  1.131906794  0.9559589 -1.9111856  1.16240718

> C_wk<- split(C,C$key)
> head(C_wk)
$`1`
   key          C1         C2
1    1  0.41924361  0.1554905
3    1  0.34101785  0.3290381
14   1 -1.27793718 -0.2728525
18   1 -0.72084207  0.3307406
20   1  0.05193866 -0.4465938
27   1  1.03553670  1.7562845
29   1  2.35281628 -1.6114928
37   1  0.02295450 -0.9392724

$`2`
   key         C1         C2
2    2 -0.2125050 -1.4696090
4    2 -2.2716488  1.3529220
5    2 -0.2565037 -0.1575783
6    2 -0.4259541  0.1968482
7    2 -1.1866331 -0.3687882
13   2  0.7102612 -1.1221971
15   2  0.1592025  0.2775758
17   2  0.3842816 -0.6379072
22   2  0.1516206 -1.0723437
24   2 -0.4070279 -0.2998299
25   2  0.7779358 -0.2862851
28   2 -0.6860207 -0.9731296
30   2 -0.1319815  1.4057571
31   2  0.2845947 -0.3443439
33   2  0.7927496  0.9126125
34   2  0.4733910 -1.6850074

$`3`
   key          C1           C2
8    3 -0.13961645  0.204808027
9    3  1.49999162 -0.435241747
10   3 -0.94473626  1.768523536
11   3 -1.68380914 -0.172574070
12   3  1.12455947  0.611700128
16   3  0.19875147 -1.356228028
19   3  0.78590745 -0.796733981
21   3 -1.02839096  0.254459297
23   3 -1.00747198  0.593401435
26   3  0.81168025 -1.447740656
32   3  0.74883355 -0.170628912
35   3 -0.82805688 -1.792942718
36   3 -0.68229982  0.001420327
38   3  1.11185787  1.452839232
39   3  0.01296254 -0.676003236
40   3 -0.70681824 -0.027688693

打散之後我們用keyval函數把list的物件名稱(用names函數提取)當作key值(其實就是把打散的資料和key值兜在一起)
> Total<- keyval(c(names(A_wk),names(B_wk),names(C_wk)),c(A_wk,B_wk,C_wk))

之後放進mapreduce裡面! 因為已經用keyval把資料賦予key值,所以這裡我就不需要map了,直接在reduce裡面把資料還原成我要的東西。 先把資料用欄位名稱打散(在這裡不同dataset欄位名稱是不同的,如果有一樣的話請加上其他條件),打散之後再把它們合併成data.frame

> Demo<- mapreduce(
+     input = to.dfs(Total),
+     reduce = function(k,v){
+         test<- split(v,sapply(v,function(x) paste(colnames(x),collapse = "")))
+         test<- lapply(test,function(x) Reduce(rbind,x))
+         keyval(k,list(test[[1]],test[[2]],test[[3]]))
+     }
+ )
然後來看結果
> from.dfs(Demo)
$key
[1] "1" "1" "1" "2" "2" "2" "3" "3" "3"

$val
$val[[1]]
   key         A1         A2          A3
1    1 -1.0348640  1.8177439  0.13525756
4    1  0.2270242  0.9087429 -0.41221232
13   1 -0.3573558 -1.2751938 -0.03458945
14   1 -0.7453312 -1.1503369  1.08577621
16   1  0.8465141  0.2366092  0.91902192
19   1  1.4896751  0.3213586 -0.98961302
23   1 -0.3143099  2.0754432 -1.29391057

$val[[2]]
   key          B1         B2          B3            B4
5    1 -0.39066706  0.8493213  0.09075889  0.3695884990
6    1 -0.76899300  0.7308232 -0.82277576  0.3367413230
8    1 -1.05567857 -0.5663445  0.32075285  1.0807403069
9    1 -0.07174419 -0.6553943 -0.30134811 -1.2155568454
13   1 -0.39760179  0.5973388 -0.43153826 -0.0003626449
14   1  0.38234556 -0.4762401  0.90686094 -3.8579677970
15   1 -0.73177601 -0.6438049 -1.52620752  0.0814186088
20   1  0.07927141 -1.7918052 -1.27799659  0.1533002628

$val[[3]]
   key          C1         C2
1    1  0.41924361  0.1554905
3    1  0.34101785  0.3290381
14   1 -1.27793718 -0.2728525
18   1 -0.72084207  0.3307406
20   1  0.05193866 -0.4465938
27   1  1.03553670  1.7562845
29   1  2.35281628 -1.6114928
37   1  0.02295450 -0.9392724

$val[[4]]
   key          A1          A2          A3
3    2 -0.20348880  1.02975761  0.63051151
7    2  1.53614888  1.96886642  0.04558348
9    2 -0.07431669 -0.03700706 -1.47200277
10   2  0.66355253  0.07667024 -1.22673427
17   2  1.13416422 -1.69200417 -0.13861365
18   2 -0.99696590  0.24465904  0.54821302
24   2 -0.44196754 -0.28170710 -0.73912548
27   2 -1.34823336 -0.06120274  2.12261003
30   2  1.83861168 -0.02982669  0.14312250

$val[[5]]
   key          B1         B2          B3         B4
3    2  1.46500601 -0.4572000 -1.89767865 -0.6081751
4    2  1.96474812  0.8320135  0.50937176  0.7775585
7    2  0.35856113  0.1048170 -0.76270331 -0.5114040
10   2  1.11808088 -0.5707235 -0.16225111 -1.0749321
12   2 -0.32032713 -0.7167343 -0.03320639  0.2495948
18   2  1.36768551  1.1874533  2.13816520  1.0105115
19   2  0.02825361  0.8781400 -1.44303311  1.2391620

$val[[6]]
   key         C1         C2
2    2 -0.2125050 -1.4696090
4    2 -2.2716488  1.3529220
5    2 -0.2565037 -0.1575783
6    2 -0.4259541  0.1968482
7    2 -1.1866331 -0.3687882
13   2  0.7102612 -1.1221971
15   2  0.1592025  0.2775758
17   2  0.3842816 -0.6379072
22   2  0.1516206 -1.0723437
24   2 -0.4070279 -0.2998299
25   2  0.7779358 -0.2862851
28   2 -0.6860207 -0.9731296
30   2 -0.1319815  1.4057571
31   2  0.2845947 -0.3443439
33   2  0.7927496  0.9126125
34   2  0.4733910 -1.6850074

$val[[7]]
   key         A1         A2         A3
2    3 -1.3735558 -0.2437948 -0.4509937
5    3 -0.3290382 -0.4840644 -0.3688641
6    3 -0.1822808 -1.1303439 -0.4175791
8    3  1.2317304 -0.7572487 -0.4401060
11   3 -0.4940248 -0.1259619 -1.1145702
12   3 -1.4488153 -0.9855823 -0.7537385
15   3 -0.6147528  0.6804414 -0.7799006
20   3  0.5340705 -0.2427455 -1.5272875
21   3 -1.2019567 -0.1434495 -0.3046498
22   3  0.1311908 -0.4900816  0.8861471
25   3 -1.1544569 -0.1732862 -2.2312314
26   3 -1.3264688 -0.6784207  1.5171326
28   3  1.1866616 -1.9195358  0.3591871
29   3  0.7476575 -0.3390230 -1.6448516

$val[[8]]
   key           B1         B2         B3          B4
1    3  0.363861211  1.5158812 -1.2059163  0.08659873
2    3 -0.001122564  0.1037150  0.2580929  1.60135858
11   3  0.180619368 -0.8830636  0.7562675  1.09992035
16   3  2.644110325 -1.8546195  2.4887309 -0.03694847
17   3  1.131906794  0.9559589 -1.9111856  1.16240718

$val[[9]]
   key          C1           C2
8    3 -0.13961645  0.204808027
9    3  1.49999162 -0.435241747
10   3 -0.94473626  1.768523536
11   3 -1.68380914 -0.172574070
12   3  1.12455947  0.611700128
16   3  0.19875147 -1.356228028
19   3  0.78590745 -0.796733981
21   3 -1.02839096  0.254459297
23   3 -1.00747198  0.593401435
26   3  0.81168025 -1.447740656
32   3  0.74883355 -0.170628912
35   3 -0.82805688 -1.792942718
36   3 -0.68229982  0.001420327
38   3  1.11185787  1.452839232
39   3  0.01296254 -0.676003236
40   3 -0.70681824 -0.027688693
OK,和我想要的一樣!
前面三組dataset屬於key "1"
中間三組dataset屬於key "2"
後面三組dataset屬於key "3"
大功告成!!!
在reduce裡面可以加上更多的東西,像是資料表之間彼此join之類的運算。

2013年8月28日 星期三

[R] 效能(1) apply和他的快樂朋友們

在R的世界裡,for迴圈是幾乎所以R programmer都要盡量避免的,因為for迴圈真的很容易拖慢速度!

apply系列的函數可以把運算向量化(vectorization),讓程式簡潔快速喔!!!並且可以和還在用for迴圈的新手們炫耀自己的功力。

先來看看Demo的資料,都是R內建的
> library(datasets)
> head(cars)
  speed dist
1     4    2
2     4   10
3     7    4
4     7   22
5     8   16
6     9   10
> head(airquality)
  Ozone Solar.R Wind Temp Month Day
1    41     190  7.4   67     5   1
2    36     118  8.0   72     5   2
3    12     149 12.6   74     5   3
4    18     313 11.5   62     5   4
5    NA      NA 14.3   56     5   5
6    28      NA 14.9   66     5   6

1. apply(資料名稱,計算方向,套用函數)

apply算是基本款的,但是就已經蠻強大的了

其中計算方向比較需要注意:
1 表示逐列
2 表示逐行

EX: 用apply函數來計算demo資料cars中不同欄位的平均數或者檢查資料格式,通通一行搞定!
> apply(cars,2,mean)
speed  dist
15.40 42.98
> apply(cars,2,class)
    speed      dist 
"numeric" "numeric" 

2. tapply(資料$欄位,分層欄位,套用函數)

個人認為tapply還蠻好用的,尤其是要做分層的時候,功能就像是SQL語法的group by

EX: 我們可以用它來計算demo資料airquality中不同月份(Month)的最大風速(Wind)
> tapply(airquality$Wind, airquality$Month,max)
   5    6    7    8    9
20.1 20.7 14.9 15.5 16.6 

3. sapply(列表或向量,套用函數) 

是作用在列表(list)或是向量(vector)上面的

EX: 把向量a通通取絕對值!
> sapply(-4:4,abs)
[1] 4 3 2 1 0 1 2 3 4
> a<- -4:4
> a
[1] -4 -3 -2 -1  0  1  2  3  4

或者把a這個list裡面的東東通通取平均
> a=list(a=c(1,2,3),b=c(2,3,4),c=c(3,4,5))
> a
$a
[1] 1 2 3

$b
[1] 2 3 4

$c
[1] 3 4 5

> sapply(a,mean)
a b c 
2 3 4 

4. mapply(函數,函數引數)

mapply其實就是sapply的多重版,可以放數多個函數引述

EX: 由N(0,1)中做五次抽樣,第一次抽一個樣本,第二次抽兩個樣本,...第五次抽五個樣本

> mapply(rnorm, n=1:7, mean=0, sd=1)
[[1]]
[1] -2.112067
[[2]]
[1]  0.7254029 -1.2384776
[[3]]
[1]  0.8083143 -1.6875636  0.6863660
[[4]]
[1]  2.0391266  0.2182393 -0.6225456  0.4714035
[[5]]
[1] 1.0811637 0.1209754 1.1659376 0.5173664 0.1244459

5. lapply(列表或向量,套用函數)

傳回列表(list)的apply函數

EX: 向量a中每個元素都+1並存在列表(list)裡
> > a <-1:4> a
[1] 1 2 3 4
> lapply(a,function(x) x+1)
[[1]]
[1] 2

[[2]]
[1] 3

[[3]]
[1] 4

[[4]]
[1] 5

6. rapply(列表或向量,套用函數) 

針對嵌套列表(nested list就是,list中又有list的東東)的apply函數

how選項可以決定要不要針對各list裡的value

EX: 加總(how="unlist")
> a<- list(x1=1:5,x2=2:7)
> b<- list(x1=7:5,x2=0:7)
> rapply(list(a,b),sum,how="unlist")
x1 x2 x1 x2 
15 27 18 28 
EX: 加總(how="list")
> rapply(list(a,b),sum,how="list")
[[1]]
[[1]]$x1
[1] 15

[[1]]$x2
[1] 27


[[2]]
[[2]]$x1
[1] 18

[[2]]$x2
[1] 28