niedziela, 23 listopada 2014

Wyliczanie mediany w bashu :).

Ostatnio miałem okazję napisać skrypt do wyliczania mediany w bashu, więc postanowiłem się nim podzielić.
Skrypt jest dość ciekawy, ponieważ korzysta z różnych narzędzi dostępnych w systemie operacyjnym Linux.

Zawartość skryptu:

#!/bin/bash
a=`cat $1 | wc -l `
echo "Lista składa się się z $a elementów"

if [ `expr $a % 2` -ne 0 ]
then
echo "$a jest nieparzystą liczbą elementów"
b=`expr $a / 2 + 1` ### Zmienna zawierająca środkową wartość
echo "Element, którego wartości poszukuję to $b "
echo "Jego wartość to `cat $1 | sort -n | sed -n "$b"p`"

else


echo "$a jest parzystą liczbą elementów"
### Ustawienie zmiennej lista elementów podzielona na dwa oraz lista elementów podzielona na dwa i plus jeden.
c=`expr $a / 2`
d=`expr $a / 2 + 1`
echo "Poszukiwane są wartości elemntu $c oraz $d"
### Ustawienie wartości dla zmiennych c oraz d
cc=`cat $1 | sort -n | sed -n "$c"p`
dd=`cat $1 | sort -n | sed -n "$d"p`
ee=`expr $cc + $dd`

echo "Które mają nastepujące wartości $cc oraz $dd"
echo "Wynik dla parzystej ilości liczb wynosi:"
echo "`echo $ee 2 | awk '{print $1/$2}'`"

fi


Wzory na wyliczenie mediany znalazłem na stronie http://www.matmana6.pl/tablice_matematyczne/liceum/statystyka/44-mediana_wariancja_i_odchylenie_standardowe .
Są dostępne dwie jego wersje pierwszy dla nieparzystej ilości analizowanych liczb, drugi dla parzystej liczby analizowanych liczb.
Dla nieparzystej ilości liczb medianą jest środkowa liczba ze wzoru.
Dla parzystej ilości liczb medianą jest średnia wyciągnięta z dwóch liczb najbliżej środka.


Rozbicie skryptu na czynniki pierwsze :):
a=`cat $1 | wc -l ` ### Tworzymy zmienną "a" i sprawdzamy ile ma elementów (przydatne do późniejszego sprawdzenia czy mamy do czynienia z parzystą czy też nieparzystą ilością liczb).

if [ `expr $a % 2` -ne 0 ] ### Sprawdzamy czy ilość elementów jest nieparzysta "% 2" oznacza że dzielimy przez dwa i jest zwracana reszta z dzielenia, jeżeli wynik jest równy 0 to wówczas mamy do czynienia z liczbą parzystą, jeśli nie to jest to liczba nieparzysta (stosujemy pierwszy wzór).

b=`expr $a / 2 + 1` ### Tworzymy zmienną b, dzielimy ilość elementów na dwa (expr auto-magicznie zaokrągli wynik w dół) i dodajemy jeden aby znać numer elementu ze środka przedziału.

echo "Jego wartość to `cat $1 | sort -n | sed -n "$b"p`" ### Rozpoczynam działania na pliku który podałem podczas uruchomienia skryptu (przykładowe wywołanie skryptu "./skrypt.sh lista.txt"), sortuje po numerach liczby umieszczone w pliku lista.txt i wyświetlam za pomocą sed zawartość środkowego wiersza z pliku. Ta dam i mamy medianę :).

c=`expr $a / 2` ### Tworze dwie zmienne odpowiadające elementom listy najbliżej środka ( np. dla listy 1 2 3 4, będzie to 2 i 3)
d=`expr $a / 2 + 1`


cc=`cat $1 | sort -n | sed -n "$c"p` ### Przypisuję wartości dla elementów najbliżej środka przedziału
dd=`cat $1 | sort -n | sed -n "$d"p`

ee=`expr $cc + $dd` ### Dodaję wartości obu zmiennych


echo "`echo $ee 2 | awk '{print $1/$2}'`" ### Ten fragment jest trochę przekombinowany dlatego, że expr nie chciał podawać wyników z dokładnością do dwóch miejsc po przecinku. Przekazałem więc dwa argumenty do programu awk i je przez siebie podzieliłem.

Zawartość przykładowych plików na których testowałem skrypt:

cat lista.txt
1
7
3
5
8

cat lista2.txt
1
3
5
6
10
8

Wynik wykonania skryptu na obu listach:
pawel@debian:~/mediana$ ./skrypt.sh lista.txt
Lista składa się się z 5 elementów
5 jest nieparzystą liczbą elementów
Element, którego wartości poszukuję to 3
Jego wartość to 5

pawel@debian:~/mediana$ ./skrypt.sh lista2.txt
Lista składa się się z 6 elementów
6 jest parzystą liczbą elementów
Poszukiwane są wartości elemntu 3 oraz 4
Które mają nastepujące wartości 5 oraz 6
Wynik dla parzystej ilości liczb wynosi:
5.5

Zdaję sobie sprawę z tego, że wykonywanie obliczeń statystycznych w bashu trochę mija się z celem ale i tak postanowiłem ten skrypt opublikować.
Może komuś przyda się, któraś z metod np. wyświetlanie wiersza o specyficznym numerze za pomocą sed.







Brak komentarzy:

Prześlij komentarz