【发布时间】:2016-04-09 15:01:52
【问题描述】:
今天我尝试实现一个“R-like”的融化功能。我将它用于来自 Big Query 的大数据。 我对计算时间没有太大的限制,而且这个函数在数百万行上的工作时间不到 5-10 秒。
我从这种数据开始:
(def sample
'({:list "123,250" :group "a"} {:list "234,260" :group "b"}))
然后我定义了一个将列表放入向量的函数:
(defn split-data-rank [datatab value]
(let [splitted (map (fn[x] (assoc x value (str/split (x value) #","))) datatab)]
(map (fn[y] (let [index (map inc (range (count (y value))))]
(assoc y value (zipmap index (y value)))))
splitted)))
启动:
(split-data-rank sample :list)
如您所见,它返回相同的序列,但将 :list 替换为一个映射,给出引用列表中每个项目在列表中的位置。
然后,我想通过为组中的每个项目创建其自己的行及其在组中的排名来融化“数据框”。
所以我创建了这个函数:
(defn split-melt [datatab value]
(let [splitted (split-data-rank datatab value)]
(map (fn [y] (dissoc y value))
(apply concat
(map
(fn[x]
(map
(fn[[k v]]
(assoc x :item v :Rank k))
(x value)))
splitted)))))
启动:
(split-melt sample :list)
问题是它缩进很多并且使用了大量的地图。我将 dissoc 应用于 drop :list (现在没用了),我还必须使用 concat 因为没有它我有一个序列序列。
您认为设计此功能是否有更有效/更短的方法? 我对 reduce 很困惑,不知道它是否可以在这里应用,因为在某种程度上有两个参数。
非常感谢!
【问题讨论】:
-
嵌套的
map函数和大量匿名函数表明这不是理想的 Clojure。我不确定您打算如何处理,但我建议您以map-indexed为起点。您是否绑定到该示例数据结构?为什么被引用?你想从中返回什么? -
感谢您的意见。 reduce-kv 好像真的很强大,会考虑的。像这样的嵌套地图是不是很好写和读。我打算计算每个不同项目的平均排名,但我知道如何使用 group-by。我受制于这种引用数据,尤其是因为我从 Google Big Query 中获取它。