【问题标题】:How do I flatten a sequence of sequences of maps into a sequence of vectors?如何将一系列地图序列展平为一系列向量?
【发布时间】:2015-05-24 04:14:36
【问题描述】:

我正在尝试在 Clojure 中构建一个 POS 标记器。我需要遍历文件并构建特征向量。输入是来自文件的 (text pos chunk) 三元组,如下所示:

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))))   

我认为其中一个问题是 apply 引用了一个序列本身,因此 select-keys 不在地图上运行。不过,我不确定如何在其中嵌套另一个应用函数。

对此代码的任何想法都会很棒。谢谢。

【问题讨论】:

  • 如果你的问题真的只是关于如何展平一系列地图,那么前两个代码块和地图用途的描述等,只是把问题弄乱了。不相关的信息会降低您快速得到答案的可能性。在这个特定的问题中,举例说明您尝试将其作为输入处理的地图序列的序列类型以及您想要作为输出的说明,这将很有帮助。 (如果您不确定额外的材料是否相关,请解释原因——在这种情况下,这是问题的一部分。)
  • 我认为您真正想要的不仅仅是展平操作,而是按键选择然后展平。
  • to-map 从未使用过......?应该如何理解这里的要求? windowsize 的目的是什么?输入与“超基本输出”有何关系?你想解决什么问题?
  • 哎呀。我澄清了这个问题,包括我实际在做什么。

标签: clojure


【解决方案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 在什么都没有找到时返回 {},但 {} 是真值,在这种情况下我们需要一个假值用于下一步。 selkeys-or-not 返回一个虚假值 (nil) 而不是 {}

现在我们可以使用filter identity过滤掉nils——过滤器返回一个包含所有值的序列,使得它的第一个参数返回一个真值。

此时我们有一个映射序列,但我们想要一个向量序列。 applying concat 将映射序列转换为映射条目序列,在它们上映射vec 将映射条目转换为向量。

【讨论】:

  • 顺便说一句。你或多或少地重新实现了not-empty :)
  • 哦!好点@LeonGrapenthin。 selkeys-or-not 可以定义为 (comp not-empty select-keys),但参数的顺序除外。我将编辑定义。 (任何想查看 Leon 评论的原件的人都可以查看编辑历史记录。)
【解决方案2】:
(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)

如果你想在函数之外,你可以把它放到一个向量中。这种方式懒惰是调用者的一个选项。

【讨论】:

    猜你喜欢
    • 2010-10-02
    • 2015-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-09
    • 2014-07-24
    • 2011-02-05
    相关资源
    最近更新 更多