2016-12-20 1 views
0

Betrachten Sie die folgende Beispieltabelle:Finden Cluster von Werten mit Postgresql

CREATE TABLE rndtbl AS 
SELECT 
    generate_series(1, 10) AS id, 
    random() AS val; 

und ich möchte voneinander mindestens 0,1 für jeden id ein cluster_id, so dass die Cluster sind weit entfernt zu finden. Wie würde ich eine solche Cluster-Zuweisung berechnen?

wäre ein spezifisches Beispiel sein:

select * from rndtbl ; 
id |  val 
----+------------------- 
    1 | 0.485714662820101 
    2 | 0.185201027430594 
    3 | 0.368477711919695 
    4 | 0.687312887981534 
    5 | 0.978742253035307 
    6 | 0.961830694694072 
    7 | 0.10397826647386 
    8 | 0.644958863966167 
    9 | 0.912827260326594 
10 | 0.196085536852479 
(10 rows) 

Das Ergebnis wäre: id s (2,7,10) in einem Cluster und (5,6,9) in einem anderen Cluster und (4,8) in einem anderen und (1) und (3) als Singleton-Cluster.

+0

Vielleicht gibt es einen Weg, dies in Postgres zu tun, aber ich persönlich würde eher Data Science Sachen mit einem Werkzeug wie R, das viele Pakete hat, um mit dieser Art von Problem umzugehen. –

Antwort

3

Von

SELECT * FROM rndtbl ; 
┌────┬────────────────────┐ 
│ id │  val   │ 
├────┼────────────────────┤ 
│ 1 │ 0.153776332736015 │ 
│ 2 │ 0.572575284633785 │ 
│ 3 │ 0.998213059268892 │ 
│ 4 │ 0.654628816060722 │ 
│ 5 │ 0.692200613208115 │ 
│ 6 │ 0.572836415842175 │ 
│ 7 │ 0.0788379465229809 │ 
│ 8 │ 0.390280921943486 │ 
│ 9 │ 0.611408909317106 │ 
│ 10 │ 0.555164183024317 │ 
└────┴────────────────────┘ 
(10 rows) 

Verwenden Sie die LAG Fensterfunktion zu wissen, ob die aktuelle Zeile in einem neuen Cluster ist oder nicht:

SELECT *, val - LAG(val) OVER (ORDER BY val) > 0.1 AS new_cluster 
FROM rndtbl ; 
┌────┬────────────────────┬─────────────┐ 
│ id │  val   │ new_cluster │ 
├────┼────────────────────┼─────────────┤ 
│ 7 │ 0.0788379465229809 │ (null)  │ 
│ 1 │ 0.153776332736015 │ f   │ 
│ 8 │ 0.390280921943486 │ t   │ 
│ 10 │ 0.555164183024317 │ t   │ 
│ 2 │ 0.572575284633785 │ f   │ 
│ 6 │ 0.572836415842175 │ f   │ 
│ 9 │ 0.611408909317106 │ f   │ 
│ 4 │ 0.654628816060722 │ f   │ 
│ 5 │ 0.692200613208115 │ f   │ 
│ 3 │ 0.998213059268892 │ t   │ 
└────┴────────────────────┴─────────────┘ 
(10 rows) 

Schließlich können Sie die Anzahl der trueSUM (noch Bestellung von val), um den Cluster der Zeile (gezählt von 0) zu erhalten:

SELECT *, SUM(COALESCE(new_cluster::int, 0)) OVER (ORDER BY val) AS nb_cluster 
FROM (
    SELECT *, val - LAG(val) OVER (ORDER BY val) > 0.1 AS new_cluster 
    FROM rndtbl 
) t 
; 
┌────┬────────────────────┬─────────────┬────────────┐ 
│ id │  val   │ new_cluster │ nb_cluster │ 
├────┼────────────────────┼─────────────┼────────────┤ 
│ 7 │ 0.0788379465229809 │ (null)  │   0 │ 
│ 1 │ 0.153776332736015 │ f   │   0 │ 
│ 8 │ 0.390280921943486 │ t   │   1 │ 
│ 10 │ 0.555164183024317 │ t   │   2 │ 
│ 2 │ 0.572575284633785 │ f   │   2 │ 
│ 6 │ 0.572836415842175 │ f   │   2 │ 
│ 9 │ 0.611408909317106 │ f   │   2 │ 
│ 4 │ 0.654628816060722 │ f   │   2 │ 
│ 5 │ 0.692200613208115 │ f   │   2 │ 
│ 3 │ 0.998213059268892 │ t   │   3 │ 
└────┴────────────────────┴─────────────┴────────────┘ 
(10 rows) 
Verwandte Themen