1

Let's say I have a set of tuples to be processed by Cascalog, formatted like [Date, Name, Value], e.g.

2014-01-01 Pizza        3
2014-01-01 Hamburger    4
2014-01-01 Cheeseburger 2
2014-01-02 Pizza        1
2014-01-02 Hamburger    2

Given that I have a list of columns like [Pizza, Hamburger, Cheeseburger], I want to transpose / pivot the data so it looks like this:

Date       Pizza Hamburger Cheeseburger
2014-01-01 3     4         2
2014-01-02 1     2         0

What's the best way to do this in Cascalog?

4

1 回答 1

2

这是一种方法:

(:use cascalog.api)

(def input
  [["2014-01-01" "Pizza"        3]
   ["2014-01-01" "Hamburger"    4]
   ["2014-01-01" "Cheeseburger" 2]
   ["2014-01-02" "Pizza"        1]
   ["2014-01-02" "Hamburger"    2]])

(defn init-aggregate [k v]
  {k v})

(def combine-aggregate
  (partial merge-with +))

(defparallelagg aggregate
  :init-var #'init-aggregate
  :combine-var #'combine-aggregate) 

(defn select-values [hashmap keyseq]
  (map #(get hashmap %) keyseq))

(def columns
  ["Pizza" "Hamburger" "Cheeseburger"])

(defn transpose [data]
  (<- [?date !pizza !hamburger !cheeseburger]
      ((<- [?date ?sum]
           (data ?date ?name ?value)
           (aggregate ?name ?value :> ?sum))
         ?date ?sum)
      (select-values ?sum columns :> !pizza !hamburger !cheeseburger)))

(?- (stdout) (transpose input))

让我们快速浏览一下代码:

大多数操作发生在transpose函数中,该函数包含两个查询:

  1. 内部查询?name ?value将给定日期的所有对聚合到?sum地图中。

  2. 外部查询用于select-values从映射中获取列的值?sum,并进入最终结果行。

由于我们知道列是Pizza, Hamburger, Cheeseburger我们可以简单地将它们硬编码到查询中。如果您想知道如何使列动态化,请阅读 Nathan Marz 关于在 Cascalog 中创建新闻提要的博客文章。

请注意,我们必须将列表示为可空变量(使用!),因为并非每一列都对任何给定行都有一个值。如果我们想避免null结果,我们可以更改select-values为使用 0 作为默认值。

(需要注意的是,这不会在最终输出中产生任何标题,因此必须作为后处理步骤来完成。)

于 2014-04-29T08:03:04.937 回答