Czytanie danych zawierających ciągi znaków NaN

NaN to oznaczenie ,,Not a Number'' które może pojawić się (na wydrukach z programu komputerowego) gdy procesor wykona jakąś operację ,,niedozwoloną''.

Dzielenie przez zero wykonywane jest przez współczesne bez problemów, generując jako wynik wartość ,,nieskończoność'' (która podczas wyprowdzania oznaczona będzie Inf albo -Inf). Procesor poprawnie wykonuje proste operacje na nieskończonościach, na przykłąd Inf + 1 to będzie Inf. Natomiast próba dodawania $-\infty + \infty$ wygeneruje wynik NaN.

Dygresja: przykład NaNów i nieskończoności

In [1]:
duze = 1e300
male = 1e-300
dzielenie = duze/male
In [2]:
dzielenie
Out[2]:
inf
In [3]:
dzielenie +5
Out[3]:
inf
In [4]:
dzielenie - dzielenie
Out[4]:
nan

Koniec dygresji

Dane generowane przez RRDB będą zawierały takie znaczniki wszędzie tam, gdzie z jakichś powodów, nie udało się dokonać pomiarów. Na przykład plik AVERAGE86400.dat zawiera takie wartości

In [5]:
import numpy as np
import numpy.ma as ma
In [6]:
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = (12,9) # Tu definiujemy rozmiary wykresu. 
# Standardowo wydaje się być zbyt mały.

Funkcja genfromtext() pozwala takie dane importować (ale zachowując wartości nan w wybranych punktach. Sprawdźmy co się dzieje w 19 wierszu pliku AVERAGE86400.dat?

In [7]:
np.genfromtxt('AVERAGE86400.dat')[19,:]
Out[7]:
array([  1.45575360e+09,              nan])
In [8]:
np.isnan(np.genfromtxt('AVERAGE86400.dat')[19,1])
Out[8]:
True
In [9]:
np.isnan(np.genfromtxt('AVERAGE86400.dat')[19,0])
Out[9]:
False

Funkcja np.isnan() pozwala sprawdzić czy zmienna przyjmuje wartośc NaN.

Zatem, wydaje się, że można tu użyć metody maskowania tablic opisanej gdzie indziej używając funkcji masked_invalid lub masked_where.

Odrzucenie NaNów

In [10]:
dane = np.genfromtxt('AVERAGE1800.dat')
In [11]:
temperatura = ma.masked_invalid(dane)
In [12]:
plt.plot(dane[:,0],dane[:,1],'.');
plt.show()

Odrzucenie wartości błędnych

Okazuje się, że dane ciągle są nieprawdopodobne (zawierają błędne wartości). Zatem trzeba je filtrować ze względu na te wartości i NaN-y. Przyjmijmy, że temperatury większe od $55^o$ i mniejsze od $-25^o$ są nieprawdopodobne.

Można to zapewne zrobić na wiele sposobów: albo stworzyć dwie maski i połączyć je operatorem OR, albo spróbować od razu stworzyć maskę na podstawie złożonego warunku. Skorzystamy z funkcji np.logical_or, która pozwala wykonywać operacje logiczne na elemantach całych tablic.

In [13]:
temp = dane[:,1]
temp = ma.masked_where(np.logical_or(np.isnan(temp), np.logical_or(temp < -25, temp > 55)), temp)
czas = ma.masked_array(dane[:,0], mask=temp.mask)
In [14]:
temp[~temp.mask].data
Out[14]:
array([-0.9689304 , -0.9689304 , -0.9689304 , -0.9689304 , -0.9689304 ,
       -0.9689304 , -0.9689304 , -0.9689304 , -0.9689304 , -0.9689304 ,
       -0.9689304 , -0.9689304 , -0.9689304 , -0.9689304 , -0.9689304 ,
       -0.9689304 , -0.97132976, -0.99075683, -0.83426618, -0.59789995,
       -0.30984787,  0.06529007,  0.55961978,  1.01605712,  1.49648211,
        2.02862636,  2.38894571,  2.54215373,  2.94817462,  3.58848959,
        4.11365971,  4.39019901,  3.46231264,  1.9996722 ,  1.3706712 ,
        1.02434473,  0.77193505,  0.76138098,  0.57264191,  0.32903536,
        0.01951746, -0.27134013, -0.39613435, -0.50011568, -0.67656486,
       -0.8681121 , -1.08714175, -1.18525492, -1.28565313, -1.24108625,
       -1.04606541, -1.08572976, -1.33585592, -1.60743693, -1.85790117,
       -2.08819171, -2.28403202, -2.53051551, -2.75360595, -2.85811913,
       -2.88870606, -2.99370083, -3.19580117, -3.15671801, -2.74186134,
       -2.28816073, -1.69171359, -1.02051107, -0.10649571,  0.55675271,
        0.91734664,  1.60928682,  1.96775816,  2.12463078,  1.88444471,
        1.74624109,  2.0028115 ,  2.2746414 ,  2.55890763,  2.50252571,
        1.62599862,  0.26635421, -0.50358427, -0.98479002, -1.40007052,
       -1.67309828, -1.90303818, -2.17718339, -2.45854333, -2.69389698,
       -2.9804397 , -3.21216814, -3.37002201, -3.63892863, -3.9121131 ,
       -3.44242109, -3.32476335, -3.32476335, -3.32476335, -3.32476335,
       -3.32476335, -3.32476335, -3.32476335, -3.32476335, -3.32476335,
       -3.32476335, -3.32476335, -3.32476335, -3.32476335, -3.37142357,
       -3.51366715, -3.50871543, -3.37796034, -3.39046239, -3.10425686,
       -3.01528678, -2.8449735 , -2.52775352, -2.33099223, -2.16743083,
       -2.03021482, -2.02666353, -1.92039705, -2.04087834, -2.07338505,
       -2.05382725, -2.09138797, -1.95651813, -1.58986749, -1.50969829,
       -1.62039588, -1.50575258, -1.43236731, -1.44103041, -1.42939079,
       -1.4403857 , -1.39900864, -1.3637495 , -1.3426858 , -1.31601555,
       -1.34638328, -1.37973848, -1.34939139, -1.34372559, -1.3643624 ,
       -1.37567732, -1.31649507, -1.19616073, -1.21003961, -1.16580865,
       -0.92419366, -0.63649917, -0.25912707, -0.02178627,  0.40563403,
        0.67488825,  0.90885667,  1.0746237 ,  1.44658929,  1.43713447,
        1.16494032,  0.98375386,  0.95851094,  1.00751924,  1.01762468,
        0.81774303,  0.83232619,  0.83442293,  0.87528381,  0.87258487,
        0.90223848,  0.95190633,  1.19057823,  1.19491369,  1.29377344,
        1.45033463,  1.66096858,  1.60056966,  1.47780845,  1.44014506,
        1.48641699,  1.54128472,  1.59428292,  1.63644973,  1.59387903,
        1.60590574,  1.6078418 ,  1.61382814,  1.59810428,  1.55617152,
        1.49411195,  1.46681   ,  1.39870236,  1.36176584,  1.35547927,
        1.36792649,  1.34065474,  1.45063501,  1.68485833,  1.98857957,
        2.59823112,  3.2125596 ,  3.59828842,  3.55584554,  3.89884217,
        4.58764428,  4.46150343,  4.1222205 ,  4.08124526,  4.07453335,
        3.83789119,  3.57128158,  3.39105607,  2.6732194 ,  1.9263623 ,
        1.3903127 ,  1.06576122,  0.9290621 ,  0.85108892,  0.71472104,
        0.46200946,  0.28961528,  0.05223433, -0.13159077, -0.24962034,
       -0.40931991, -0.56371217, -0.64236233, -0.79759883, -1.21674488,
       -1.41533718, -1.43377337, -1.49950171, -1.61631932, -1.7912667 ,
       -2.01220944, -2.17647829, -2.40088592, -2.41749333, -2.38312776,
       -2.47694158, -2.73418817, -3.03867776, -3.20700884, -3.37558817,
       -3.25663012, -2.75923466, -2.10442443, -1.50824765, -0.89508019,
       -0.12260412,  0.59729491,  1.14321798,  1.6565934 ,  2.37697939,
        2.51685072,  2.71776486,  3.16102275,  3.73784785,  4.43235326,
        4.98068583,  4.52359916,  2.81570992,  1.59045274,  0.84730032,
        0.40442651,  0.13273876, -0.11150835, -0.21906938, -0.46069369,
       -0.7553974 , -0.99919286, -1.22781625, -1.49587517, -1.80696982,
       -2.1868429 , -2.5097996 , -2.80082943, -3.05553462, -3.1488235 ,
       -3.31342747, -3.44290583, -3.61827553, -3.77604984, -4.04064642,
       -4.26817368, -4.47379896, -4.77481949, -4.98215301, -5.04947649,
       -5.06595574, -5.08041844, -4.96337389, -4.63365679, -4.10623   ,
       -3.61442886, -3.04414281, -2.38571858, -1.74436319, -0.96228349,
       -0.58046793, -0.04615267,  0.47187252,  0.82347588,  1.07181179,
        1.36185046, -1.01576326, -1.80014157, -2.26408023, -2.7430987 ,
       -3.09067551, -3.25374566, -3.50369328, -3.85212776, -4.02239798,
       -4.31083983, -4.55850166, -4.78828468, -4.95656198, -5.10658656])
In [15]:
czas = czas[~czas.mask].data
temp = temp[~temp.mask].data
In [16]:
plt.plot(czas, temp, '.')
plt.show()

Teraz powinniśmy jeszcze zastąpić czymś odrzucone wartości. Można, w tym celu, posłużyć sę interpolacją jak to opisano w innym notatniku. 9Nie trzeba — choć można — robić resamplingu, wystarczy użyć interpolacji aby zastąpić „puste miejsca” na wykresie danymi z interpolacji.

Opis osi X

Unix timestamp może jest i wygodny, ale trudno zorientować się jakiego okresu dotyczy powyższy wykres. Chcielibyśmy mieś os X opisaną jako daty.

W tym celu należy (niestety) skonwertować timestamp do postaci zrozumiałej dla oprogramowania. Służy do tego funkcja fromtimestamp

In [17]:
import matplotlib.dates as md
import datetime as dt
In [18]:
dates=[dt.datetime.fromtimestamp(ts) for ts in czas]
In [19]:
plt.xticks( rotation=25 )
ax = plt.gca()
xfmt = md.DateFormatter('%Y-%m-%d')
ax.xaxis.set_major_formatter(xfmt)
plt.plot(dates, temp, '.')
plt.show()

Czasami będziemy potrzebowali aby zastąpić czymś wartości w odrzuconych punktach. Można wówczas posłużyć się interpolacją w sposób opisany gdzie indziej.