43 CSV faili lugemine ja kirjutamine
CSV failist lugemine
Andmetöötluses on eelnevalt vaja tabel failist sisse lugeda, mis on tihti CSV formaadis. NumPyga saab kasutada funktsiooni genfromtxt. Funktsiooni sulgudesse tuleb lisada faili nimi, delimiter ehk eraldaja väärtus, mis eraldab andmeid teineteisest, ja parameeter names=True, mille abil saab veeru pealkirja kasutades väga lihtsalt tabelist terve veeru. Näiteks tabel["sugu"] tagastab kõik väärtused, mis asuvad veerus pealkirjaga "sugu". Populaarsemad eraldajad on näiteks tühik, koma või semikoolon. Vaatame näidet. Olgu CSV faili sisu on selline:
Esimene;Teine;Kolmas 1;11;21 2;12;22 3;13;23 4;14;24
! CSV failis ei tohi olla veeru nimedes tühikuid, need võib asendada _ -ga (alakriipsuga). Näiteks Keskmine hinne → Keskmine_hinne.
# CSV faili sisselugemine
import numpy as np
csv = np.genfromtxt('fail.csv', delimiter=";", names=True, encoding = 'UTF-8')
# Terve tabeli väljastamine
print(csv)
>>> %Run guido.py [(1., 11., 21.) (2., 12., 22.) (3., 13., 23.) (4., 14., 24.)]
# Väljastame esimese veeru
print("Esimene veerg: ", csv["Esimene"])
>>> %Run guido.py Esimene veerg: [1. 2. 3. 4.]
# Väljastame teise rea
print("Teine rida: ", csv[1])
>>> %Run guido.py Teine rida: (2., 12., 22.)
Näeme, et väljund ei ole tüüpilisel Numpy kahemõõtmelise järjendi kujul, sest elementideks oleks justkui ennikud. Tegelikult on tegemist record array tüüpi järjendiga, mis üks Numpy järjendi tüüpidest, mis lubabki veeru eralda, selle nime järgi. Proovi ära võtta names = True argument ja väljasta kogu tabel. Mis juhtub? Kas tulemus oli midagi sellist?
[[nan nan nan] [ 1. 11. 21.] [ 2. 12. 22.] [ 3. 13. 23.] [ 4. 14. 24.]]
Nimelt on võib Numpy üheks puuduseks pidada seda, et tabelis olevad väärtused peavad olema sama tüüpi. Vaikimisi on failist loetud tabel alati ujukomaarvu tüüpi ja kui tabelis on ka teksti, siis need on Numpy jaoks tundmatud, mis tähistatakse nan (not a number, tundmatu).
Juhul kui on vaja analüüsida tabelit, kus on erinevat tüüpi andmeid, siis on kolm võimalust, kuidas ikkagi andmeid sobilikul kujul kasutada. Esimene võimalus on failist lugemisel määrata ära iga veeru andmetüüp.
Olgu meil järgmised andmed.
Nimi;Vanus;Punktid Tiina;11;21 Kalle;12;42 Kustav;13;23 Salme;14;34 Örli;11;23
Näeme, et esimese veeru andmed on sõned ja teise ning kolmanda veerud andmed on täisarvud.
Loeme andmed, kasutades eelnevalt demonstreeritud funktsiooni genfromtxt. Erinevalt eelmisest näitest, lisame juurde ka dtype argumendi, mille väärtuseks on järjend, kus iga element tähistab veeru tüüpi, kasutades tüüpide koode. Tekstina esitatud nimed määrame tabelis UNICODE sõne tüüpi. Me ei kasuta tavalist sõne tüüpi (str või “S”), sest faili kodeering on UTF-8, siis selleks, et NumPy oskaks kuvada failis olevaid nimesid õigesti, tuleb kasutada UNICODE sõne tüüpi.
csv = np.genfromtxt('fail.csv', delimiter=";", encoding = 'UTF-8', dtype=["U25", "i4", "i4"], names=True)
print(csv["Nimi"])
print(csv["Vanus"])
>>> %Run guido.py ['Tiina' 'Kalle' 'Kustav' 'Salme' 'Örli'] [11 12 13 14 11]
Teine võimalus on muuta kogu tabel sõne tüüpi. Selleks määrame parameetri dtype väärtuseks srt. Samuti lisame parameetri skip_header, mille väärtuseks on 1. Selle tulemusel ei ole tabelis enam veeru pealkirjade rida.
csv = np.genfromtxt('fail.csv', delimiter=";", encoding = 'UTF-8', dtype=str, skip_header=1)
# Terve tabeli väljastamine
print(csv)
>>> %Run guido.py [['Tiina' '11' '21'] ['Kalle' '12' '42'] ['Kustav' '13' '23'] ['Salme' '14' '34'] ['Örli' '11' '23']]
Nüüd kui soovime leida näiteks keskmist vanust, tuleks kasutada tükeldamist ja saadud veeru tüüp teisendada ujukomaarvuks.
teine_veerg = csv[:, 1]
print(teine_veerg)
vanus = teine_veerg.astype(float)
print("Keskmine vanus:", np.mean(vanus))
>>> %Run guido.py ['11' '12' '13' '14' '11'] Keskmine vanus: 12.2
Kolmas võimalus on kasutada Pandase moodulit (loe lisa Pandase kohta peatükist Pandas) CSV failide lugemiseks, sest sel juhul ei ole vaja muretseda, et andmed on tabelis erinevat tüüpi. See on väga hea viis kasutada ära mõlema mooduli head küljed. Esmalt tuleb aga Pandase moodul importida.
import pandas as pd
Loeme andmed failist kasutades Pandase read_csv funktsiooni.
x = pd.read_csv("fail.csv", sep=";").values
print(x)
>>> %Run guido.py [['Tiina' 11 21] ['Kalle' 12 42] ['Kustav' 13 23] ['Salme' 14 34] ['Örli' 11 23]]
Andmed võib lugeda ka veebist. Lisades juurde mooduli URLLib, millega saab faile veebist lugeda ning kasutada veebilinki, kus andmed asuvad.
from urllib.request import urlopen # Andmed url = 'http://kodu.ut.ee/~merka123/plotly/haigusjuhtumid.csv' andmed = urlopen(url) csv = np.genfromtxt(andmed, delimiter=";", names=True, encoding = 'UTF-8', dtype=['U20', 'i4', 'i4', 'i4', 'i4','i4'])
CSV faili salvestamine
NumPyga saab salvestada informatsiooni tekstifaili vaid ühe reaga. Selle jaoks on olemas funktsioon: np.savetxt(fail, sisu, eraldaja). Vaatame näidet, kus salvestame kahemõõtmelise järjendi faili ning seejärel avame selle faili ning väljastame sisu.
# Tekstifaili salvestamine ja selle sisu väljastamine
import numpy as np
# Loome ühe kahemõõtmelise järjendi
sisu = np.array([[1, 11, 21],[2, 12, 22],[3, 13, 23],[4, 14, 24]])
# Salvestame sisu faili fail.csv, eraldajaks määrame semikooloni
np.savetxt('fail.csv', sisu, delimiter=';')
# Nüüd avame faili fail.txt
fail = np.genfromtxt('fail.csv', delimiter=";", encoding = 'UTF-8')
# Väljastame sisu
print(fail)
>>> %Run guido.py [[ 1. 11. 21.] [ 2. 12. 22.] [ 3. 13. 23.] [ 4. 14. 24.]]