2017-07-24 6 views
-1

Ich habe eine CSV-Datei mit zwei Spalten: ‚id‘ undExtrakt aus jeder Gruppe N

eine ID ‚Werten‘ kann mehrfach in der Datei mit unterschiedlichen Werten auftreten. Ich möchte ein geschichtetes Sampling der Daten durchführen, um eine kleinere Datei zu erhalten, die genau oder höchstens N jeder ID enthält.

Beispiel Eingabe:

a 1,2,3 
    a 2,2,3 
    a 2,2,3 
    a 2,4,3 
    a 4,2,3 
    a 4,4,4 
    b 3,4,4 
    b 8,8,8 
    b 3,3,3 
    c 4,5,6 
    c 5,5,4 

gewünschte Ausgabe (N = 2):

a 1,2,3 
    a 2,2,3 
    b 3,4,4 
    b 8,8,8 
    c 4,5,6 
    c 5,5,4 

An diesem Punkt, den ich getroffen werden, nicht die IDs aus einer Gruppe kümmern, aber Bonuspunkte, wenn es ist zufällig.

Da die Textdatei kann sehr groß sein, ich einen Speicher effizient bevorzugen (Linux) Befehlszeile-Lösung (dh bash, awk, sed, etc.)

+3

bitte fügen Sie hinzu, was Sie versucht haben, dies zu lösen ... mit 'awk', können Sie ein Array mit ID als Schlüssel verwenden und drucken, wenn dieser Schlüssel höchstens N mal gesehen wurde – Sundeep

+0

Danke für den Tipp, bin ich nicht sehr vertraut mit awk.Ich habe eine Lösung mit Ihrem Vorschlag erstellt. – Deruijter

Antwort

1

Per @ Sundeep Vorschläge habe ich eine Lösung mit shuf und awk mit einer Array [id] Zählung Konstruktion (für N = 10):

shuf ./data.csv | awk '{count[$1]++} {if (count[$1] < 10)print $1, $2}' ./data.csv 

Das die ersten 10 Elemente von jeder ID dauert.

+2

für zufällige, können Sie etwas wie 'shuf data.csv | verwenden awk -v n = '2' '++ gesehen [$ 1] <= n' | sort' – Sundeep

+0

Das ist perfekt, danke! – Deruijter

0
[[email protected] tmp]$ awk -v n=2 '++arr_seen[$1] <=n' file 
    a 1,2,3 
    a 2,2,3 
    b 3,4,4 
    b 8,8,8 
    c 4,5,6 
    c 5,5,4 

Eingang

[[email protected] tmp]$ cat file 
    a 1,2,3 
    a 2,2,3 
    a 2,2,3 
    a 2,4,3 
    a 4,2,3 
    a 4,4,4 
    b 3,4,4 
    b 8,8,8 
    b 3,3,3 
    c 4,5,6 
    c 5,5,4 
0
$ n=2; awk -v n=$n 'arr[$1]<n{arr[$1]++;print $0}' file 
    a 1,2,3 
    a 2,2,3 
    b 3,4,4 
    b 8,8,8 
    c 4,5,6 
    c 5,5,4 

Kurze Erklärung,

  • n=2: Gewünschte Show-up-Zeiten als bash variable n
  • arr[$1]<n: Die ID wäre der Schlüssel des Arrays, und der Wert für jede ID wäre der Wert für jeden Schlüssel. Wenn der Wert des Schlüssels <n ist, drucken Sie die Zeile und dann arr[$1]++.
2

Hier ist eine in Awk, die eine Art von Zufälligkeit implementieren. Es liest die Datei zweimal. In der ersten Runde zählt es Schlüssel und an der zweiten Ausgabe Datensätze mit einige eine Art Wahrscheinlichkeit. Nicht ausgiebig getestet, aber es sollte eine Division durch Null zu vermeiden und die 2 letzten Datensätze für jeden Schlüssel werden zurückgegeben, wenn die Götter der Wahrscheinlichkeit haben nicht vor, dass interveniert:

$ awk -v seed=$RANDOM -v n=2 ' # n is the count of keys wanted 
BEGIN { 
    srand(seed)     
} 
NR==FNR {      # on the first run 
    nc[$1]=n     # ncound for each key (2) 
    c[$1]++      # count of keys 
    next 
} 
{ 
    if(nc[$1]>0 && c[$1]>0 && (nc[$1]/c[$1]/(1-rand()))>1) { 
     print 
     nc[$1]--    # reduce n count for key when printing 
    } 
    c[$1]--      # keys left counter reduces at each iteration 
}' file file 
a 1,2,3 
a 4,2,3 
b 8,8,8 
b 3,3,3 
c 4,5,6 
c 5,5,4 

Ein weiterer Lauf produziert:

a 2,2,3 
a 4,2,3 
b 3,4,4 
b 8,8,8 
c 4,5,6 
c 5,5,4 

(nc[$1]/c[$1]/(1-rand())) > 1 Dies garantiert, dass die 2 (oder n) letzten Datensätze für jeden Schlüssel zurückgegeben werden, wenn keiner früher gedruckt wurde, zum Beispiel , dann nc/c==1 und 1/[0-1[ > 1 immer. rand() liefert Werte im Bereich [0-1[ und zu vermeiden /0 gibt es /(1-rand()) Zufallsverteilung möglicherweise nicht gleichmäßig, obwohl.

+0

Große Antwort und in der Lage, es mit einem Samen reproduzierbar zu machen, ist genial. Wenn Sie die Datei jedoch zweimal durchlaufen, ist das für meinen Fall etwas weniger praktisch. – Deruijter

Verwandte Themen