網頁

2014年8月3日 星期日

Smilarity --- 到底有多相似:Euclidean Distance 及 Cos Distance

顧客A買了糖果、餅乾、衛生紙
顧客B買了餅乾、汽水、雜誌
顧客C買了汽水

要如何決定他們之間的相似程度?

Euclidean Distance:


一個滿符合直覺的做法就是用Euclidean distance,就是國中學過的平面中二點的距離

所以顧客A、B、C的座標分別是


1代表有買過,0代表沒買過


距離分別是


C跟A的距離是2.23,C跟B的距離是1.41,C跟B距離比較近,所以比較相似


Cosine Distance:

但是這裡有個問題,也就是有購買東西的意義遠大於沒購買東西的意義。

舉例來說:
說法1:因為B跟C都有買汽水,所以他們比較像
說法2:因為A跟C都沒有買雜誌,所以他們比較像
說法1看起來比較符合我們的思考方式,因為不買某商品的理由遠多於購買某商品的理由。

再舉個例子:
說法1:我跟歐巴馬比較像,因為我們都不是白人
說法2:我跟金城武比較像,因為我們都是帥哥
看起來說法2比較站得住腳,因為不同的東西太多,而相同的東西太少。

這樣的概念數值化後就是:Cosine Similarity


Cosine Distance 就是 1 - Cosine Similarity

情況一:A跟B同時買了4件東西,4件東西都一樣。A跟B的cosine similarity是 4 / sqrt(4)*sqrt(4) = 1,cosine distance = 1-1 = 0。他們之間沒有距離,代表他們一模一樣。

情況二:A買了100件東西,B買了4件東西,他們買的東西只有1件相同,A跟B的cosine similarity是 1 / sqrt(100)*sqrt(4) = 1/20,cosine distance = 1 - 1/20 = 0.95

回到最初的例子:B,C的cosine distance是多少?


cosine distance
= 1 - cosine similarity
= 1 - ( 1 / sqrt(4)*sqrt(1) )= 1 - 0.5
= 0.5

但是cosine distance只適用於有沒有購買的紀錄,有買就是1,不管買了多少,沒買就是0。如果還要把購買的數量考慮進來,就不適用於這種方式了。






2014年8月2日 星期六

unsupervised clustering --- 讓資料自己物以類聚:k-means

讓資料物以類聚可以用來區隔出不同類型的顧客,找出之前未曾注意到的顧客類型。比如說酒商可以透過分析顧客的購買紀錄找出有一群顧客特別喜歡某個產地的紅酒,另一群客戶喜歡打折的香檳...知道這些資訊就可設計出更合適的銷售活動。

這聽起來相當神奇的技術其實用的是你國中就學過的數學:計算平面上二點的距離。




這張圖很明顯地有三群資料,但是要如何讓電腦知道有三群資料(三個cluster)?如果能找出每一群資料的中心點用來代表該群體,那就太好了。

一群資料的中心點就像圖中紅色的點這樣。這些紅點(cluster centroid)有個特徵(有點像是圓心到圓上的任何一點的距離都是最短的):

sum( cluster裡的點到cluster center的距離 ) = 最小值

由這個特徵進一步推出:

sum( 每一個點到最接近的紅點的距離 ) = 最小值

可以藉由嘗試不同的cluster center座標找出最小值,當確定找出最小值時,也就找出了cluster center。最後計算一個點到各個cluster center的距離,找出距離最近的cluster center,就可以得知這個點是屬於哪一個cluster了。於是資料找到了它的歸宿,幸福快樂的生活下去。

那何需大費周章的用電腦找出cluster呢,這圖看起來不是一目了然嗎?假設圖中的X軸為購買餅乾的數量,Y軸為購買汽水的數量。這時尚可用眼睛分別不同的cluster;那再加入一個Z軸代表購買雜誌的數量,這時圖型變成立體的,要用眼睛判別就有點吃力了;如果再考慮顧客的帳戶餘額,要看出有幾個cluster就頗有難度了。但若用k-means,就可以這樣表示:

客戶(餅乾,汽水,雜誌,帳戶餘額)
A客戶可以用( 0, 0, 1, 200 )來表示
B客戶可以用( 2, 1, 1, 1200 )來表示
C客戶可以用( 10, 5, 0, 50000 )來表示
D
E ......

我想把這些資料分為2群(這就是k-means的k的。k是一個自訂值,決定你要把資料分成幾群,可以是2可以是4可以是5),於是我建立二個cluster center,並給他們初始值。

cluster center I ( 0, 0, 0, 0 )
cluster center II ( 0, 0, 0, 0 )

透過最佳化(如evolutionary algorithm)找到cluster center的座標最小值

cluster center I ( 1, 1, 1, 1500 )
cluster center II ( 20, 10, 0, 30000 )

從這些center可以知道有一群客戶帳戶餘額較少,購買少量的商品;另一群客戶帳戶餘額較多,一次購買較為大量的商品。

最後決定哪一個客戶屬於哪一個cluster:A距離I比較近,屬於I;B距離II比較近,屬於II...

到這裡大致完成了k-means,但還有一些問題:

分成二個cluster到底好不好,還是k=3會更準確,那就要看看silhouette (計算每給點跟自己群組裡的點比較近,或是跟別的群組裡的點比較近)。

這裡又有另一個問題:金錢所造成的距離遠大於汽水數量造成的距離,這是你所預期的嗎?如果不是的話可以試試讓數值標準化

還有一個問題:一家店裡的商品這麼多,購買一個商品的意義遠大於不購買一個商品的意義。所以最好只採計有購買的商品。這時可以採用cos distance


大數據分析技術 書籍推薦:DATA SMART

DATA SMART


這本書教你如何讓資料自己分組,物以類聚;教你Target是如何用購買紀錄預測顧客是否懷孕;教你如何使用電腦自動判斷一則留言是否在討論特定主題;也教你如何找出特異獨行的員工。這些看似神奇的技術,作者居然使用的是Excel帶領讀者一步步的實作,避開如R、SAS等常用的工具進行分析,大幅降低進入門檻。

整本書詼諧易讀,沒有艱深的理論,卻能帶領讀者踏入巨量資料分析的大門。正如同封面上的推薦語:Data Smart讓讀者不用再翻閱厚重的教科書或學術文章就能容易了解並實作現代的統計方法及演算法

作者本身是一名巨量資料分析顧問,也曾為FBI、可口可樂等等大組織工作。書中也常有作者的經驗談,更增加了這本書的實用性。

2014年7月28日 星期一

@RequestParam v.s. @PathVariable

  • @PathVariable: 路徑中的變數
    /user/{userId} userId為PathVariable,1,2,3,...
  • @RequestParam: ?後接的那一串
    如/oo/xx?name=aa,
    name=aa為RequestParam
example:
@RequestMapping(value="/user/{userId}/invoices", method = RequestMethod.GET)
public List listUsersInvoices(
            @PathVariable("userId") int user,
            @RequestParam(value = "date", required = false) Date dateOrNull) {
  ...
}

參考:http://stackoverflow.com/questions/13715811/requestparam-vs-pathvariable

Hello World!:GAE + Spring MVC + Maven + Eclipse


  1. 建立Maven專案




    1. 用 filter縮小範圍:org.apache.maven.archetypes

      選擇:
      Group Id: org.apache.maven.archetypes
      Artifact Id: maven-archetype-webapp



    2. 輸入:
      Group Id: 自己公司的名字
      Aftifact Id: 專案名稱



    3. 建立好的專案不知道為什麼只有src/main/resources,必須自己加入src/main/java (maven 只會compile src/main/java下面的classes)


      自行在maven的路徑下建立java資料夾


      update



      java出現了,以後程式就放這裡


  2. 設定pom檔
    (這pom是從各種可以執行的範本裡整合來的,有些內容尚待釐清)
    
     4.0.0
    
     com.tien
     webapp
    
     war
     0.0.1-SNAPSHOT
    
     webapp Maven Webapp
    
     http://maven.apache.org
    
     
      
       google-staging
       Google Staging
       https://oss.sonatype.org/content/repositories/comgoogleappengine-1004/
      
     
    
     
      UTF-8
      1
      1.9.7
      4.0.6.RELEASE
      1.6.6
     
    
     
         
         
      
       junit
       junit
       3.8.1
       test
      
      
      
      
       com.google.appengine
       appengine-api-1.0-sdk
       ${appengine.target.version}
      
      
      
      
       javax.servlet
       servlet-api
       2.5
       provided
      
      
       jstl
       jstl
       1.2
      
      
      
      
       org.springframework
       spring-core
       ${spring.version}
      
      
       org.springframework
       spring-context
       ${spring.version}
      
      
       org.springframework
       spring-beans
       ${spring.version}
      
      
      
      
       org.springframework
       spring-webmvc
       ${spring.version}
      
      
       org.springframework
       spring-web
       ${spring.version}
      
      
      
      
       org.slf4j
       slf4j-api
       ${org.slf4j-version}
      
      
       org.slf4j
       jcl-over-slf4j
       ${org.slf4j-version}
       runtime
      
      
       org.slf4j
       slf4j-log4j12
       ${org.slf4j-version}
       runtime
      
      
       log4j
       log4j
       1.2.15
       
        
         javax.mail
         mail
        
        
         javax.jms
         jms
        
        
         com.sun.jdmk
         jmxtools
        
        
         com.sun.jmx
         jmxri
        
       
       runtime
      
     
    
     
      webapp
    
      
       
        org.apache.maven.plugins
        2.5.1
        maven-compiler-plugin
        
         1.7
         1.7
        
       
    
       
        org.apache.maven.plugins
        maven-war-plugin
        2.3
        
         true
         
          
          
           ${basedir}/src/main/webapp/WEB-INF
           true
           WEB-INF
          
         
        
       
    
       
        com.google.appengine
        appengine-maven-plugin
        ${appengine.target.version}
       
      
     
    
    
    
  3. 設定GAE:在WEB-INF下建立appengine-web.xml


    appengine-web.xml:
    
        ooxx123
        1
        true
    
                   
    
  4. 設定Spring:
    同時設定IOC的application context與MVC的dispatcher sevelet。
    這二個context有階級的關係。
    application context在整個環境(包含一般類別)都可以呼叫;dispatcher sevelet涵蓋的範圍只包含有註冊的的路徑(在servlet的環境下可呼叫,而一般類別則無法呼叫)

    在WEB-INF下建立dispatch-servlet.xml及root-context.xml(application context)

    root-context.xml
    
     
     
      
    
    
    dispatch-servlet.xml
    
    
        
        
        
     
     
     
     
    
     
     
    
     
     
     
      
      
       
       
    
    
  5. 設定web.xml
    在web application啟動的同時,設定spring的context
    
    
     
     
      contextConfigLocation  /WEB-INF/spring/root-context.xml 
     
     
     
      org.springframework.web.context.ContextLoaderListener
     
    
     
     
      appServlet
      org.springframework.web.servlet.DispatcherServlet
      
       contextConfigLocation   /WEB-INF/spring/appServlet/dispatcher-servlet.xml  
      1
       
     
      appServlet
      /
     
    
    
    
    
  6. 測試一下,server選google app engine


    可喜可賀,設定檔都沒有出錯。dev app server is now running!!!



    至於java.io.FileNotFoundException: \WEB-INF\logging.properties (系統找不到指定的檔案。)是因為還沒建立log4j的設定檔。
     
  7. 建立spring mvc的hello world
     
    1. 在指定的package建立controller
      (也就是dispatcher-servlet.xml裡的
      <context:component-scan base-package="com.gae.test.controller" />)

      TestController
      @Controller
      //to specify this class is a controller. 
      //this pakage should be included in dispatcher-servlet.xml 
      //
      
      @RequestMapping( value="/test" )
      //requests which start with "/test" enter this class  
      public class TestController {
       
       @RequestMapping(value = "/hello", method = RequestMethod.GET)
       // url is "/test/hello" 
       public String hello(Locale locale, Model model) {
        System.out.println( "this is hello controller" );   
        return "hello"; // dispatch to /WEB-INF/views/hello.jsp
       }
       
      }
      
    2. 在指定的資料夾建立hello.jsp
      也就是dispatch-servlet裡的
      
        
        
       

      hello.jsp
      <html><head></head><body>Hello world!</body>





  • 測試一下
    在瀏覽器輸入http://localhost:8080/test/hello
    console:

    browser:

    大功告成!!!


  • 備註:
    google不是很喜歡spring的annotation,因為他們認為reflection的機制很沒效率。至於如何設定google認為有效率的方式可以參考這一篇:
    https://developers.google.com/appengine/articles/spring_optimization

    參考資料:
    https://developers.google.com/appengine/docs/java/gettingstarted/introduction
    http://www.loop81.com/2013/02/gae-google-app-engine-jpa2-maven-and.html
    http://rimo-art.com/2013/11/eclipse-spring-mvc-google-app-engine/

    2012年8月31日 星期五

    JPQL in clause with empty list

    jpql:
    select e from employee e where e.id in :param

    :param 是個list

    如果list裡面沒有值(.isEmpty() == true),就會出現以下莫名其妙的錯誤
    com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '))' at line 1 

    eclipselink轉譯出的sql:
    WHERE (t1.IN ())

    就是因為in裡面沒有東西,所以sql出錯。eclipselink居然沒有處理這種錯誤,還丟出這麼撲朔迷離的Exception......


    2012年8月30日 星期四

    position:relative的tag在IE消失

    html:


    css:

    這樣有時候在IE會失蹤,這是因為IE的Quirks mode

    換成下面的寫法,效果一樣,而且不會失蹤
    html:


    css:

    至於為什麼可以這樣做,可以看這一篇的第4步、第5步
    十步學會css定位