【问题标题】:How can I modify a column in an Incanter dataset?如何修改 Incanter 数据集中的列?
【发布时间】:2014-02-12 07:13:59
【问题描述】:

我希望能够转换 incanter 数据集中的单个列,并将生成的数据集保存到新的 (csv) 文件中。最简单的方法是什么?

基本上,我希望能够在数据集中的列上映射一个函数,并用这个结果替换原始列。

【问题讨论】:

    标签: clojure incanter


    【解决方案1】:

    你可以定义如下:

    (defn map-data [dataset column fn]
      (conj-cols (sel dataset :except-cols column)
                 ($map fn column dataset)))
    

    并用作

    (def data (get-dataset :cars))
    (map-data data :speed #(* % 2))
    

    更改列名只有一个问题 - 我会尝试解决它,当我有空闲时间时......

    【讨论】:

      【解决方案2】:

      这里有两个类似的函数,列名和顺序保留。

      (defn transform-column [col-name f data] 
        (let [new-col-names (sort-by #(= % col-name) (col-names data))
              new-dataset (conj-cols
                            (sel data :except-cols col-name)
                            (f ($ col-name data)))]
      
          ($ (col-names data) (col-names new-dataset new-col-names) )))
      
      (defn transform-rows [col-name f data] 
        (let [new-col-names (sort-by #(= % col-name) (col-names data))
              new-dataset (conj-cols
                            (sel data :except-cols col-name)
                            ($map f col-name data))]
      

      下面是一个说明差异的示例:

      => (def test-data (to-dataset [{:a 1 :b 2} {:a 3 :b 4}])) 
      => (transform-column :a (fn [x] (map #(* % 2) x)) test-data)
      [:a :b]
      [2 2]
      [6 4]
      
      => (transform-rows   :a #(* % 2) test-data)
      [:a :b]
      [2 2]
      [6 4]
      

      transform-rows 最适合简单的转换,而transform-column 适用于某一行的转换依赖于其他行的情况(例如在规范化列时)。

      可以使用标准 Incanter 函数来保存和加载 CSV,因此完整示例如下所示:

      (use '(incanter core io)))
      
      (def data (col-names (read-dataset 'data.csv') [:a :b])
      
      (save (transform-rows :a #(* % 2) data) 'transformed-data.csv')
      

      【讨论】:

        【解决方案3】:

        再次:也许您可以使用数据集的内部结构。

        user=> (defn update-column
                 [dataset column f & args]
                 (->> (map #(apply update-in % [column] f args) (:rows dataset))
                   vec
                   (assoc dataset :rows)))
        #'user/update-column
        user=> d
        [:col-0 :col-1]
        [1 2]
        [3 4]
        [5 6]
        
        user=> (update-column d :col-1 str "d")
        [:col-0 :col-1]
        [1 "2d"]
        [3 "4d"]
        [5 "6d"]
        

        应该再次检查这是公共 API 的程度。

        【讨论】:

        • 是的,也许它会更优化,尽管在数据集上添加相应的操作可能会更好
        • 这个解决方案的优点是它可以适应每一行是关联数据结构、映射或序列的情况。
        【解决方案4】:

        注意:此解决方案需要 Incanter 1.5.3 或更高版本

        对于那些可以使用 Incanter 最新版本的人...

        add-columnadd-derived-column 在 1.5.3 中被添加到 Incanter (pull request)

        来自文档:

        add-column

        “将具有给定值的列添加到数据集中。”

        (add-column column-name values)
        

        (add-column column-name values data)
        

        或者你可以使用:

        add-derived-column

        "此函数将列添加到数据集中,该列是 现有的列。如果没有提供数据集,$data(由 with-data 宏)将被使用。 f 应该是 from-columns,参数按此顺序排列。”

        (add-derived-column column-name from-columns f)
        

        (add-derived-column column-name from-columns f data)
        

        一个更完整的例子

        (use '(incanter core datasets))
          (def cars (get-dataset :cars))
        
        (add-derived-column :dist-over-speed [:dist :speed] (fn [d s] (/ d s)) cars)
        
        (with-data (get-dataset :cars)
          (view (add-derived-column :speed**-1 [:speed] #(/ 1.0 %))))
        

        【讨论】:

          猜你喜欢
          • 2021-11-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-08-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-07-12
          相关资源
          最近更新 更多