40 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.]]

Litsents

Icon for the Creative Commons Attribution 4.0 International License

Tarkvaraarendus. 2. trükk on loodud Eno Tõnisson, Tauno Palts, Kaarel Tõnisson, Heidi Meier, Merilin Säde, Ago Luberg, Birgy Lorenz, Einar Kivisalu, Meelis Antoi, ja Säde Mai Krusberg poolt Creative Commons Attribution 4.0 International License litsentsi alusel, kui pole teisiti märgitud.

Jaga seda raamatut