简单的“R型”融化:更好的方法吗?

时间:2016-01-05 17:21:15

标签: clojure reduce melt

今天我尝试实现“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 by map,给出引用列表中每个项目列表中的位置。

然后,我想通过为组中的每个项创建自己的行以及其在组中的排名来融合“数据帧”。

所以我创建了这个函数:

(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 感到很困惑,不知道是否可以在这里应用,因为在某种程度上有两个参数。

非常感谢!

1 个答案:

答案 0 :(得分:1)

如果您不需要split-data-rank功能,我会选择:

(defn melt [datatab value]
  (mapcat (fn [x]
            (let [items (str/split (get x value) #",")]
              (map-indexed (fn [idx item]
                             (-> x
                                 (assoc :Rank (inc idx) :item item)
                                 (dissoc value)))
                           items)))
          datatab))