我希望能够转换 incanter 数据集中的单个列,并将结果数据集保存到新的(csv)文件中。最简单的方法是什么?
本质上,我希望能够在数据集中的列上映射一个函数,并用这个结果替换原始列。
这里有两个类似的函数,列名和顺序保留。
(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
当一行的转换依赖于其他行时(例如在规范化列时)。
保存和加载 CSV 可以使用标准 Incanter 函数完成,因此完整示例如下所示:
(use '(incanter core io)))
(def data (col-names (read-dataset 'data.csv') [:a :b])
(save (transform-rows :a #(* % 2) data) 'transformed-data.csv')
您可以定义如下内容:
(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))
更改列名只有一个问题 - 我会尝试修复它,当我有空闲时间时......
注意:此解决方案需要 Incanter 1.5.3 或更高版本
对于那些可以使用最新版本的 Incanter 的人...
add-column和add-derived-column在 1.5.3 中被添加到 Incanter (pull request)
从文档:
“将具有给定值的列添加到数据集中。”
(add-column column-name values)
或者
(add-column column-name values data)
或者您可以使用:
“此函数向数据集添加一列,该列是现有列的函数。如果未提供数据集,将使用 $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 %))))
再说一遍:也许你可以使用数据集的内部结构。
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 的程度。