Wie berechne ich den Mittelwert aus ASCII-Dateidaten in Bash?


7

In Bash kann ich einige Zeitmessungen aus einer solchen Protokolldatei abrufen

grep "time:" myLogfile.txt | cut -d' ' -f 3 >> timeMeasurements.txt

#timeMeasurements.txt
2.5
3.5
2.0
...

Jetzt möchte ich den Mittelwert aus den Werten in berechnen timeMeasurements.txt. Was ist der schnellste Weg, um das in Bash zu tun?
Ich weiß, dass es Gnuplot und R gibt, aber es scheint, als müsste man für beide ein langes Skript schreiben.


Antworten:


11

Ein anderer Weg, mit sedund bc:

sed 's/^/n+=1;x+=/;$ascale=1;x/n' timemeasurements.txt | bc

Der sed-Ausdruck konvertiert die Eingabe in etwa Folgendes:

n+=1;x+=2.5
n+=1;x+=3.5
n+=1;x+=2.0
scale=1;x/n

Dies wird weitergeleitet, bcum es Zeile für Zeile auszuwerten.


13

Obligatorische GNU-Datamash- Version

$ datamash mean 1 < file
2.6666666666667

ASIDE : es fühlt sich an wie dies wirklich sollte möglich sein , nativ in bc(dh ohne die Schale verwendet wird , oder ein externes Programm, um eine Schleife über Eingangswert). Die GNU- bcImplementierung enthält eine read()Funktion - es scheint jedoch frustrierend schwierig zu sein, das Ende der Eingabe zu erkennen. Das Beste, was ich mir einfallen lassen kann, ist:

#!/usr/bin/bc

scale = 6
while( (x = read()) ) {
  s += x
  c += 1
}
s/c
quit

Anschließend können Sie die Dateieingabe weiterleiten, sofern Sie die Eingabe mit einem nicht numerischen Zeichen beenden, z

$ { cat file; echo '@'; } | ./mean.bc
2.666666

1
Nicht nur die kürzeste Antwort, sondern setzt diejenigen, die an Statistiken interessiert sind, einem praktischen Dienstprogramm aus +1
WinEunuuchs2Unix

Das sieht faszinierend kurz aus. Gibt es eine apt-get-Version von datamash?
McExchange

@mcExchange sudo apt install datamashwar auf meiner Ubuntu 16.04 VM ausreichend.
Digitales Trauma

Leider ist es unter Ubuntu 14.04 nicht in den Repositories ...
mcExchange

12

Sie könnten verwenden awk. Bash selbst ist nicht sehr gut in Mathe ...

awk 'BEGIN { lines=0; total=0 } { lines++; total+=$1 } END { print total/lines }' timeMeasurements.txt

Anmerkungen

  • lines=0; total=0 Setzen Sie die Variablen auf 0
  • lines++linesfür jede Zeile um eins erhöhen
  • total+=$1 Addieren Sie den Wert in jeder Zeile zur laufenden Summe
  • print total/lines Wenn Sie fertig sind, teilen Sie die Summe durch die Anzahl der Werte

3
Obwohl es gute Praxis ist, tun Variablen nicht tatsächlich benötigt in initialisiert werden awk- so könnte man „Golf“ diesawk '{total+=$1} END{print total/NR}'
steeldriver

@steeldriver danke!
Ich


5

Sie können bcden Basisrechner in einer whileSchleife verwenden mit read:

count=0; sum=0; while read -r num; do ((count++)); sum=$(echo "$sum + $num" | bc); done < timeMeasurement.txt; echo "scale=2; $sum / $count" | bc -l

Oder besser lesbar:

count=0
sum=0
while read -r num
do
  ((count++))
  sum=$(echo "$sum + $num" | bc)
done < timeMeasurement.txt
echo "scale=2; $sum / $count" | bc -l

Erläuterung:

  • Zuerst setzen wir die Anzahl der Werte und die Gesamtsumme als Variablenanzahl und Summe mit den Werten 0.
  • Lesen Sie die Datei Zeile für Zeile und legen Sie den Wert in der Zeile als Variable num fest. Wir benutzen die Konstruktion while read -r num; do ... ; done < timeMeasurements.txt, um dies zu tun. Dies bedeutet, dass wir für jede Zeile der Datei etwas tun.
  • Inkrementieren Sie innerhalb der while-Schleife die Zählvariable für jede Zeile mit Bash-Arithmetik um eins ((count++)).
  • Verwenden Sie die Ersetzung des Befehls bash $(...)mit echopiped, bcum den Wert der Variablen num für diese Zeile der Datei zur Summe der Variablen num aus allen vorherigen Zeilen hinzuzufügen. bcwird verwendet, da bash mit Gleitkomma-Arithmetik nicht gut zurechtkommt.

An diesem Punkt endet die Schleife, die Zählvariable enthält die Anzahl der Zeitmesswerte, die Summenvariable enthält die Summe der Zeitmessungen.

  • Verwenden Sie echodiese Variablen, um die Mittelwertberechnung zu erstellen, an die übergeben wird bc. Der scale=2Teil gibt an, bcwie viele signifikante Zahlen angezeigt werden sollen.

4

Das Datamash One scheint eine gute Option zu sein, aber selbst wenn ich anerkenne, dass meine Antwort übertrieben sein kann, ist die Oktave nicht so ausführlich, nur für den Fall, dass Sie ein bisschen mehr als nur einen Mittelwert machen möchten:

$ octave
octave:1> load timeMeasurements.txt 
octave:2> mean(timeMeasurements)
ans =  2.6667

Wenn Sie Mittelwerte verwenden, denken Sie daran, dass der gleiche Mittelwert aus sehr unterschiedlichen Verhaltensweisen stammen kann. Daher ist die Standardabweichung normalerweise auch relevant:

octave:3> std(timeMeasurements)
ans =  0.76376

oder sogar ein einfaches Histogramm ist einfach zu machen:

octave:4> hist(timeMeasurements)

Ich denke auch, dass Datamash nicht in den apt-get-Repositorys für vertrauenswürdige Versionen enthalten ist, sondern nur für neuere Versionen.

Bearbeiten:

Oneliner für skriptfreundlichere Anwendungen:

octave -q --eval "m = load(\"timeMeasurements.txt\"); mean(m)"
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.