2

私はclojureにかなり慣れていないので、xmlドキュメントから解析してExcelファイルに表示した以下のデータセットを持っています:

({:Total 28, :p3percent 89.28571428571429, :p2percent 0.0, :p1percent 10.71428571428571, :APP "A", :p1 3, :p2 0, :p3 25}
 {:Total 40, :p3percent 92.5, :p2percent 0.0, :p1percent 7.5, :APP "b", :p1 3, :p2 0, :p3 37} 
 {:Total 64, :p3percent 93.75, :p2percent 0.0, :p1percent 6.25, :APP "c", :p1 4, :p2 0, :p3 60} 
 {:Total 128, :p3percent 83.59375, :p2percent 12.5, :p1percent 3.90625, :APP "d", :p1 5, :p2 16, :p3 107}
 {:Total 6, :p3percent 83.33333333333333, :p2percent 16.66666666666667, :p1percent 0.0, :APP "e", :p1 0, :p2 1, :p3 5}
 {:Total 8, :p3percent 87.5, :p2percent 12.5, :p1percent 0.0, :APP "f", :p1 0, :p2 1, :p3 7})

各キーの値を合計/平均し、APPキー「Total」を使用してデータセットに新しいエントリを作成し、最後の行にすべての合計/平均値を表示します。これはExcelで簡単に実行できますが、明らかに最初にclojureで実行したいと考えています。

各キーの合計を取得する方法、つまり (apply + map( :p1 dataset)) を取得する方法は知っていますが、データセットを反復処理して合計をデータセットの余分な行として追加する関数を作成するにはどうすればよいですか?

ありがとう

D

4

3 に答える 3

1

各キーの値を合計/平均し、APPキー「合計」を使用してデータセットに新しいエントリを作成し、最後の行にすべての合計/平均値を表示したいと思います。

以前の回答は質問を誤解していると思います。一部のキーの合計と他のキーの平均を含む新しいエントリをデータセットに作成する場合は、私の答えが役立つ場合があります。


数のコレクションの観点から定義することから始めsumます。avgこれらの関数の実装は後でいつでも改善できるので、今のところは単純にしてください。

(defn sum [coll] (reduce + coll))
;;(sum [1 2 3])
;;=> 6
(defn avg [coll] (/ (sum coll) (count coll)))
;;(avg [1 2 3])
;;=> 2

繰り返しを避けるために、データセットを減らすための関数を定義してください。

(defn dataset-keys [d] (reduce #(into %1 (keys %2)) #{} d))

(defn reduce-dataset
  [f val dataset]
  (reduce (fn [m k] (assoc m k (f (map k dataset))))
          val
          (dataset-keys dataset)))

reduce-datasetデータセットのように、マップであり、マップのコレクションであることが期待valされます。dataset

およびをreduce-dataset定義するために使用します。totalsaveragessumavg

(defn totals [dataset] (reduce-dataset sum {:APP "Totals"} dataset))
(defn averages [dataset] (reduce-dataset avg {:APP "Averages"} dataset))

データセット内のいくつかのキーの合計と他のキーの平均が必要なため、データセット全体でそれらのキーだけを選択する方法が必要になります。

(defn select-cols [dataset ks] (map #(select-keys % ks) dataset))

これで、データセット全体で選択的に合計と平均を計算するために必要なすべてが揃いました。

(totals (select-cols your-dataset [:Total :p1 :p2 :p3]))
;;{:Total 274, :p2 18, :p3 241, :p1 15, :APP "Totals"}

(averages (select-cols your-dataset [:p1percent :p2percent :p3percent]))
;; {:p3percent 88.32713293650794, :p1percent 4.728422619047618, :p2percent 6.9444444444444455, :APP "Averages"}

conjを使用して、結果を元のデータセットと組み合わせることができます。

(conj dataset
      (totals (select-cols dataset [:Total :p1 :p2 :p3]))
      (averages (select-cols dataset [:p1percent :p2percent :p3percent])))

これにより、データセットに2つの行が追加されます。1つは合計用、もう1つは平均用です。単一の行を追加するには、接続する前に結果をマージできます。

(conj dataset
      (merge (totals (select-cols dataset [:Total :p1 :p2 :p3]))
             (averages (select-cols dataset [:p1percent :p2percent :p3percent]))
             {:APP "Total/Avg"}))

キーが競合する場合、mergeは常に最後に表示された値を使用するため、上記の例では、の値はまたはで:APPはあり"Total/Avg"ません。"Totals""Averages"

于 2012-06-07T17:09:35.460 に答える
1

関数とのマージを試してください。リンクから2番目の例を確認してください。
私はそれがあなたが望むものだと思います。この関数は、最後の「合計」行を作成するのに役立ちます。数値ではないフィールドが1つあるという唯一の問題。merge-withしたがって、文字列を無視する特別な関数を渡すことができます。

于 2012-06-06T13:50:39.947 に答える
0

対応するキーの合計または平均を含むマップの作成について質問している場合は、reduceこれをうまく行うことができます。

user>(pprint(reduce#(assoc%2:Total(+(:Total%2)(:Total%1)))
                      {:合計0}データ))
{:p1 0、
 :p3 7、
 :p2pe​​rcent 12.5、
 :p2 1、
 :p1percent 0.0、
 :APP "f"、
 :p3percent 87.5、
 :合計274}
nil

これは、キーの合計を取得し、その平均も取得できるようにするために重要な元のキーを保持する関数にまとめることができます。

(defn sum-key [key new-key map] 
  (reduce #(assoc %2 new-key (+ (%1 new-key) (%2 key))) {new-key 0} data))
#'user/sum-key
user> (sum-key :Total :Total-sum data)
{:p1 0, :p3 7, :p2percent 12.5, :p2 1, :p1percent 0.0, :APP "f", :p3percent 87.5, :Total-sum 274, :Total 8}

そして、この関数をチェーン化して、必要なキーを要約することができます

user> (->> data 
        (sum-key :Total :Total-sum) 
        (sum-key :p1 :p1-sum) 
        (sum-key :p2 :p2-sum))
{:p1 0, :p2-sum 18, 
 :p3 7, :p2percent 12.5, 
 :p2 1, :p1percent 0.0, 
 :APP "f", :p3percent 87.5, 
 :Total 8}

累計が必要な場合は、reductions代わりに使用してください。

于 2012-06-06T18:52:29.980 に答える