2015-05-24 35 views
0

我試圖在Clojure中構建一個POS tagger。我需要迭代一個文件並構建特徵向量。的輸入是(文本POS塊)從如下所示的三倍文件:如何將一系列映射序列拼合成一系列向量?

input from the file: 
     I PP B-NP 
     am VBP B-VB 
     groot NN B-NP 

我寫功能,以輸入該文件,變換每一行到地圖,然後通過數據可變量的滑動。

(defn lazy-file-lines 
    "open a file and make it a lazy sequence." 
    [filename] 
    (letfn [(helper [rdr] 
     (lazy-seq 
     (if-let [line (.readLine rdr)] 
      (cons line (helper rdr)) 
      (do (.close rdr) nil))))] 
(helper (clojure.java.io/reader filename)))) 

(defn to-map 
    "take a a line from a file and make it a map." 
    [lines] 
    (map 
    #(zipmap [:text :pos :chunk] (clojure.string/split (apply str %) #" "))lines) 
) 

(defn window 
    "create windows around the target word." 
    [size filelines] 
    (partition size 1 [] filelines)) 

我打算使用上述功能通過以下方式:

(take 2 (window 3(to-map(lazy-file-lines "/path/to/train.txt")))) 

其給出對於序列中的前兩個條目的輸出如下:

(({:chunk B-NP, :pos NN, :text Confidence} {:chunk B-PP, :pos IN, :text in} {:chunk B-NP, :pos DT, :text the}) ({:chunk B-PP, :pos IN, :text in} {:chunk B-NP, :pos DT, :text the} {:chunk I-NP, :pos NN, :text pound})) 

鑑於每個序列我想爲每個地圖提取:pos:text,並將它們放在一個向量中。像這樣:

[Confidence in the NN IN DT] 
[in the pound IN DT NN] 

我還沒有能夠概念化如何在clojure中處理這個問題。我的部分嘗試的解決方案是如下:

(defn create-features 
    "creates the features and tags from the datafile." 
    [filename windowsize & features] 
(map #(apply select-keys % [:text :pos]) 
    (->> 
    (lazy-file-lines filename) 
    (window windowsize)))) 

我想到的一個問題是,申請被引用序列本身,所以選擇密鑰是不是一個地圖上進行操作。不過,我不確定如何嵌套另一個應用函數。

對此代碼的任何想法都會很棒。謝謝。

+1

如果你的問題實際上只是關於如何拼接一系列地圖序列,那麼前兩個代碼塊和地圖目的的描述等等,只是混淆了這個問題。不相關的信息使得你很快就能得到答案。在這個特定的問題中,給出一個你想要作爲輸入處理的地圖序列序列的例子,以及你想要輸出的例子。 (如果您不確定額外材料是否相關,請解釋原因 - 在這種情況下,這是問題的一部分。) – Mars

+0

我認爲您實際需要的不僅僅是展平操作,而是通過按鍵選擇然後變平。 – Mars

+0

'to-map'永遠不會被使用........?應該如何理解這裏提出的問題? windowsize的目的是什麼?輸入與「超級基本輸出」有什麼關係?你想解決什麼問題? –

回答

1

我不完全確定你想要什麼作爲輸入和輸出,說實話,我不想通過你提供的所有代碼來解決這個問題,因爲我沒有認爲所有的代碼對於這個問題都是至關重要的。其他人可能會給你一個很適合你的代碼的答案,但我認爲真正的問題是更一般的。

我猜,你想實現什麼樣的總體思路是:

鑑於地圖的序列的序列,選擇具有特定按鍵的映射條目,然後返回向量的代表序列地圖條目。如果這不是你想要的,我認爲以下內容可能會給你一個關於如何進行的想法。

這種方法最有效的還是簡潔,但它下跌打破了問題分解成一系列易於理解的步驟:

(defn selkeys-or-not 
    "Like select-keys, but returns nil rather than {} if no keys match." 
    [keys map] 
    (not-empty (select-keys map keys))) 

(defn seq-seqs-maps-to-seq-vecs 
    "Given a sequence of keys, and a sequence of sequences of maps, 
    returns a sequence of vectors, where each vector contains key-val 
    pairs from the maps for matching keys." 
    [keys seq-seqs-maps] 
    (let [maps (flatten seq-seqs-maps)] 
    (map vec 
     (apply concat 
       (filter identity 
         (map (partial selkeys-or-not keys) maps)))))) 

發生了什麼事在第二個功能:

首先,我們將外部序列展平,因爲地圖在內部序列內的事實與我們的目標無關。這給了我們一個單一的地圖序列。

然後,我們映射幫助函數selkeys-or-not遍歷映射序列,將我們的鍵傳遞給輔助函數。 select-keys返回{}當它什麼都沒發現,但{}是truthy,我們想在這種情況下爲下一步falsey值。selkeys-or-not返回錯誤的值(nil)而不是{}

現在我們可以使用filter identity過濾出nil - 過濾器返回一個包含所有值的序列,以便它的第一個參數返回一個真值。

在這一點上,我們有一個地圖序列,但我們需要一個向量序列。 apply ing concat將地圖序列變成地圖條目序列,並且在它們上映射vec將地圖條目變成矢量。

+0

順便說一句。你有或多或少的重新實現'非空':) –

+0

哦!好點@LeonGrapenthin。 'selkeys-or-not'可以被定義爲'(comp not-empty select-keys)',除了參數的順序。我將編輯定義。 (任何想看到Leon評論的原創者都可以查看編輯歷史。) – Mars

0
(defn extract-line-seq 
    [ls] 
    (concat (map :text ls) 
      (map :pos ls))) 

(extract-line-seq '({:chunk B-NP, :pos NN, :text Confidence} {:chunk B-PP, :pos IN, :text in} {:chunk B-NP, :pos DT, :text the})) 

;-> (Confidence in the NN IN DT) 

如果您想要在函數之外使用,您可以將它放入矢量中。這種懶惰是呼叫者的選擇。