In [1]:
import warnings
import warnings
warnings.filterwarnings('ignore')
import sqlite3
import os
import numpy as np
import pandas as pd
os.chdir('/home/jarekj/Dropbox/dydaktyka/programowanie4/powiatData')

Pandas - zarządzanie danymi

Pandas to biblioteka zarządzania danymi uporządkowanymi w założeniu przypominająca działanie struktury danych dataFrame znanej z języka R i innych systemów obliczeniowych. Z założenia pandas umożliwia w prosty sposób bezpośrednie pobieranie danych z różnych źródeł, w tym:

  • plików tekstowych różnego typu (csv, json)
  • binarnych formatów danych: Excel, SAS
  • HDF5
  • baz danych SQL

Możliwe jest również przekształcenie do formatu dataFrame z innych struktur danych języka Python: słowników oraz macierzy numpy. Ta druga metoda może być wykorzystana do poboru dowolnego typu danych które można w wyniku przekształcić do formatu tabelarycznego. To drugie rozwiązanie zostanie wykorzystane do importu danych rastrowych do formatu DataFreame poprzez interface GDAL.

Dane tekstowe lub strukturyzowane dane binarne jak na przykład arkusz Excela importowane są w całości odpowiednim pleceniem: pd.read_csv() lub read_excel()co może być problemem w przypadku dużych zbiorów danych, jeżeli nie potrzebujemy ich w całości. W przypadku importu danych SQL możemy importować wyniki zapytań SQL co oznacza że już na etapie importu możemy wybrać jakie kolumny i rekordy zostaną zaimportowane a nawet łączyć dane z różych tabel przy pomocy odpowiednich klauzul SQL. Import danych z bazy danych wymaga załadowania odpowiedniego sterownika dostępu do danego silnika. Popularne formaty takie jak SQLite, MySQL, MSSQL są dostępne z poziomu biblioteki standardowej.

Import danych z pliku geoprzestrzennego

W analizie danych interesują nas wyłącznie atrybuty (część nieprzestrzenna) pliku wektorowego. Z tego powodu możemy uprościć proces importu danych potraktowanie pliku geoprzestrzennego jako zwykłej bazy danych. W ramach przykładu zaimportujemy dane pochodzace z pliku wektorowego przechowywanego w formacie SQLite/Spatialite. Niestety język Python nie wspiera komunikacji z plikami dbf. Z tego powodu należy unikać stosowania formatu shapefile. Również istnieją problemy z zarządzaniem (modyfikowaniem) plików w formacie Geospatial Package - gpkg. Do analizy dużych zbiorów danych najlepiej stosować dane w formacie postgreSQL/Postgis, lub - jeżeli zależny nam na niezależności od serwera bazodanowego z formatu SQLite/Spatialite. W ramach kursu będziemy korzystać z formatu SQlite, który jest obsługiwany przez bibliotekę standardową Pythona oraz nie wymaga stosowania żadnych dodatkowych narzedzi (serwera SQL)

Po załadowaniu biblioteki sqlite3 oraz ustawieniu katalogu roboczego, proces importu obejmuje następujące kroki:

  1. Wskazanie bazy danych (pliku SQlite o rozszerzeniu sqlite lub db) oraz tabeli z której zamierzamy importować dane
  2. Nawiązanie połączenia z bazą danych i utworzenie kursora (struktury pozwalającej przemieszczanie się po rekordach)
  3. Zbudowanie zapytania SQL - w formie łańcucha tekstowego
  4. Wykonanie zapytania przy pomocy funkcji pandas.read_sql()

Baza danych znajduje się w pliku database.db a tabela zawierająca dane ma nazwę centroids.

In [2]:
database = 'database.db' #1A
table = 'centroids' #1B
conn=sqlite3.connect(database) #2A
cur = conn.cursor() #2B
query = "SELECT * FROM {0};".format(table)#3
data = pd.read_sql_query(query,conn)#4

Po wykonaniu funkcji zostanie utworzona struktura danych DataFrame, która jest natywnym rozwiązaniem biblioteki pandas. Struktura jest wzorowana na modelu danych języka R i porządkuje dane w kolumnach - każda określonego typu oraz rekordach zawierających wartości dla każdej kolumny. Strukturę danych można podejrzeć wypisując po prostu nazwę DataFrame, a w celu ograniczenia ilości wierszy możemy wywołać funkcję .head, która zwróci nam ograniczoną liczbę wierszy.

In [3]:
data.head(10)
Out[3]:
ogc_fid fid powiat woj m k aprod prod pprod malzenstwa przyrost GEOMETRY klasa results
0 1 1 złotoryjski 2 22059 22997 6451 31248 7357 4.6 -2.3 b'\x00\x01\x84\x08\x00\x00O\x1b\xe7$0/\x11A\x8... 1 0
1 2 2 Legnica 2 48273 53719 13691 68317 19984 4.4 -2.3 b'\x00\x01\x84\x08\x00\x00\xdd\x86\xc9\xe9\x9c... 3 9
2 3 3 jeleniogórski 2 31460 33711 8696 44540 11935 3.9 -4.4 b'\x00\x01\x84\x08\x00\x00\xb2\x0f\xc5%\xf6Q\x... 1 4
3 4 4 górowski 2 17989 18402 5855 24457 6079 5.3 -0.7 b'\x00\x01\x84\x08\x00\x00NGhG\xb40\x14A\xe7\x... 2 0
4 5 5 oleśnicki 2 51929 54159 16488 71646 17954 4.7 0.3 b'\x00\x01\x84\x08\x00\x00\xf1\x9b+\xddZ+\x18A... 1 3
5 6 6 bolesławiecki 2 43962 46344 13496 61039 15771 4.9 -0.6 b'\x00\x01\x84\x08\x00\x00\xc2:+\x1d\x91\x99\x... 1 4
6 7 7 Jelenia Góra 2 38235 43750 9601 53424 18960 3.9 -4.5 b'\x00\x01\x84\x08\x00\x00\xb0\xaf\x9d\xe2\xa9... 3 6
7 8 8 kłodzki 2 79465 85215 21381 109961 33338 4.5 -4.4 b"\x00\x01\x84\x08\x00\x00'f\xd1\xdf_*\x14A\xb... 3 9
8 9 9 lubański 2 27287 28830 7741 38035 10341 4.4 -3.7 b'\x00\x01\x84\x08\x00\x00\x9e\t\x1e\xc2\xba;\... 1 9
9 10 10 wałbrzyski 2 27855 29979 7682 38781 11371 4.0 -5.0 b'\x00\x01\x84\x08\x00\x00L\xe1\x06|\xbd\xb7\x... 3 4

Do opisu dataFrame mozna wykorzystać też inne funkcje:

df.head() # pierwsze 5 wierszy df.tail() # ostatnie pięć wierszy df.sample(5) # pięć losowych wierszy df.shape # liczba wierszy i kolumn w formie krotki (rows,cols) df.describe() # podstawowe miary dataFrame df.info() # informacje o typach danych i zajmowanej pamięci

In [4]:
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 380 entries, 0 to 379
Data columns (total 14 columns):
ogc_fid       380 non-null int64
fid           380 non-null int64
powiat        380 non-null object
woj           380 non-null int64
m             380 non-null int64
k             380 non-null int64
aprod         380 non-null int64
prod          380 non-null int64
pprod         380 non-null int64
malzenstwa    380 non-null float64
przyrost      380 non-null float64
GEOMETRY      380 non-null object
klasa         380 non-null int64
results       380 non-null int64
dtypes: float64(2), int64(10), object(2)
memory usage: 41.6+ KB
In [5]:
data.describe()
Out[5]:
ogc_fid fid woj m k aprod prod pprod malzenstwa przyrost klasa results
count 380.000000 380.000000 380.000000 380.000000 380.000000 380.000000 3.800000e+02 380.000000 380.000000 380.000000 380.000000 380.000000
mean 190.500000 190.500000 17.000000 49025.092105 52279.273684 15187.963158 6.748969e+04 18626.713158 4.789474 -0.567632 2.905263 4.678947
std 109.840794 109.840794 9.408355 54071.151053 62957.693696 16076.697485 7.546731e+04 25847.026779 0.453127 2.354097 1.467852 2.948472
min 1.000000 1.000000 2.000000 10425.000000 10466.000000 3000.000000 1.377200e+04 3468.000000 3.700000 -9.000000 1.000000 0.000000
25% 95.750000 95.750000 10.000000 27243.000000 28115.500000 8421.750000 3.710025e+04 9327.250000 4.500000 -2.200000 2.000000 2.000000
50% 190.500000 190.500000 16.000000 37322.000000 39210.500000 11903.500000 5.143150e+04 13262.000000 4.800000 -0.600000 3.000000 5.000000
75% 285.250000 285.250000 24.000000 54781.250000 57544.250000 16943.250000 7.498150e+04 19723.500000 5.100000 1.100000 4.000000 7.000000
max 380.000000 380.000000 32.000000 791207.000000 933197.000000 240280.000000 1.097522e+06 386602.000000 6.100000 7.700000 5.000000 9.000000

Przegląd struktury ramki danych wskazuje że w danych znajduje się kolumna GEOMETRY, która zawiera dane binarne, do których nie mamy dostępu na tym etapie. Są one nieprzydatne w analizie i w przypadku dużego zbioru danych mogą zajmować duży obszar pamięci i długi czas importu. W związku z typ proces importu należy ograniczyć jedynie do danych atrybutowych.

Niestety, język SQL uniemożliwia wskazania negatywnej listy kolumn, kolumny które chcemy importować należy wymienić jawnie. Przy dużej liczbie kolumn może to być jednak kłopotliwe. Z tego powodu usunięcie kolumny geometrii z importu wymaga kilku nietrywialnych kroków:

  1. Wykonanie zapytania wyświetlającego listę kolumn otrzymamy listę krotek, każda zawierająca nazwę kolumny i jej atrybuty
  2. Odwrócenie listy wyników do listy krotek, (funkcja zip) która każda zawiera typ atrybutu. Druga krotka zawiera listę kolumn
  3. Usunięcie kolumny geometry z listy i dodanie listy kolumn do zapytania SQL i import danych
In [6]:
cur = conn.cursor()
cl = cur.execute("PRAGMA table_info('%s')" % table).fetchall() #1
cl 
Out[6]:
[(0, 'ogc_fid', 'INTEGER', 0, None, 0),
 (1, 'fid', 'BIGINT', 0, None, 0),
 (2, 'powiat', 'VARCHAR(254)', 0, None, 0),
 (3, 'woj', 'BIGINT', 0, None, 0),
 (4, 'm', 'BIGINT', 0, None, 0),
 (5, 'k', 'BIGINT', 0, None, 0),
 (6, 'aprod', 'BIGINT', 0, None, 0),
 (7, 'prod', 'BIGINT', 0, None, 0),
 (8, 'pprod', 'BIGINT', 0, None, 0),
 (9, 'malzenstwa', 'FLOAT', 0, None, 0),
 (10, 'przyrost', 'FLOAT', 0, None, 0),
 (11, 'GEOMETRY', 'POINT', 0, None, 0),
 (12, 'klasa', 'INTEGER', 0, None, 0),
 (13, 'results', 'integer', 0, None, 0)]
In [7]:
cl = list(zip(*cl))[1] #2
columns = list(cl) # konwersja z krotki na listę
columns.remove('GEOMETRY') # usunięcie geometrii
columns
Out[7]:
['ogc_fid',
 'fid',
 'powiat',
 'woj',
 'm',
 'k',
 'aprod',
 'prod',
 'pprod',
 'malzenstwa',
 'przyrost',
 'klasa',
 'results']
In [8]:
query = "SELECT {0} FROM {1};".format(",".join(columns),table) #3
query
Out[8]:
'SELECT ogc_fid,fid,powiat,woj,m,k,aprod,prod,pprod,malzenstwa,przyrost,klasa,results FROM centroids;'

Tk zdefiniowany zestaw poleceń zamknąć w postaci pojedynczej funkcji. Funkcja dodatkowo spraawdza czy podana tabel znajdue się w bazie danych, oraz sprawdza czy kolumna geometrii znajduje się w bazie danych.

In [9]:
def importSQliteAttributes(conn,table,geom='GEOMETRY'):
    cur = conn.cursor()
    result = cur.execute("SELECT name FROM sqlite_master WHERE type='table';").fetchall() # sprawdzenie czy podana tabela znajduje się w bazie danych
    all_tables = list(zip(*result))[0]
    if not table in all_tables:
        return None
    cl = cur.execute("PRAGMA table_info('%s')" % table).fetchall()
    cl = list(zip(*cl))
    cl = list(cl[1])
    columns = cl
    if geom in columns:
        columns.remove(geom)

    query = "SELECT {0} FROM {1};".format(",".join(columns),table)
    data = pd.read_sql_query(query,conn)
    return data

conn=sqlite3.connect(database)
data = importSQliteAttributes(conn,table)
data.head()
Out[9]:
ogc_fid fid powiat woj m k aprod prod pprod malzenstwa przyrost klasa results
0 1 1 złotoryjski 2 22059 22997 6451 31248 7357 4.6 -2.3 1 0
1 2 2 Legnica 2 48273 53719 13691 68317 19984 4.4 -2.3 3 9
2 3 3 jeleniogórski 2 31460 33711 8696 44540 11935 3.9 -4.4 1 4
3 4 4 górowski 2 17989 18402 5855 24457 6079 5.3 -0.7 2 0
4 5 5 oleśnicki 2 51929 54159 16488 71646 17954 4.7 0.3 1 3

Dodawanie kolumn do bazy danych

Dodawanie kolumn do bazy danych jest o tyle skomplikowane, że musimy zmodyfikować posiadaną tabelę zawierającą geometrię. Poprzez interface pandas nie jest możliwe dodanie kolumny bezpośrednio. Procedura ta jest niezbędna, gdyż wyniki przetwarzania danych chcemy wykorzystywać w systemach informacji geograficznej.

Do bazy danych dodamy kolumnę zawierającą wartości losowe, wygenerowane przy pomocy funkcji np.random.randomint o długości równej liczbie wierszy dataFrame (#1). Następnie z tej tabeli wyodrębniamy dwie kolumny: dodaną kolumnę oraz kolumnę _gisfid

In [10]:
data.shape
data['result'] = np.random.randint(0,10,size=data.shape[0])
results = data[['ogc_fid','result']] 
results.head()
Out[10]:
ogc_fid result
0 1 9
1 2 9
2 3 7
3 4 5
4 5 6

Procedura ta wymaga jednak kilku nietrywialnych kroków. Na tym etapie jedynie zostanie przedstawiona mechanika dodawania kolumn, która będzie następnie wykorzystywana do prezentacji wyników zaawansowanego przetwarzania danych.

  1. Przesłanie do bazy danych tymczasowej tabeli zawierającej dodawaną kolumnę, wraz z kolumną zawierającą klucz podstawowy tabeli główej (tu ogc_fid)
  2. Zmodyfikowanie tabeli głównej poprzez dodanie dodatkowej kolumny
  3. aktualizację dodanej kolumny przy pomocy specjalnego zapytania SQL. To zapytanie aktualizuje dodaną kolumnę wartościami z tymczasowej tabeli z rekordu o takim samej wartości klucza podstawowego.
  4. Usunięcie tabeli tymczasowej
In [11]:
results.to_sql('tmp', conn, if_exists='replace', index=True) #1
conn.execute('ALTER TABLE centroids ADD COLUMN results integer') #2A
query = 'UPDATE centroids SET results = (SELECT result FROM tmp WHERE tmp.ogc_fid = centroids.ogc_fid) WHERE results IS NULL'
conn.execute(query) #3
conn.commit() #3 każda transakcja zmieniająca zawartość tabeli wymaga zamknięcia transkacji
conn.execute('drop table tmp') #4
Out[11]:
<sqlite3.Cursor at 0x7ff479b345e0>

Całość też można zamknąć w formie funkcji o dość skomplikowanycm nagłówku (cztery obowiązkowe pola)

In [12]:
def addColumn(frame,column,dbase,table,datatype='integer',fid='ogc_fid'):
    tmp = frame[[fid,column]] # tabela tymczasowa
    conn=sqlite3.connect(dbase)
    frame.to_sql('tmp', conn, if_exists='replace', index=True) #1
    conn.execute('ALTER TABLE {0} ADD COLUMN {1} {2}'.format(table,column,datatype)) #2
    query = 'UPDATE {0} SET {1} = (SELECT {1} FROM tmp WHERE tmp.{2} = centroids.{2}) WHERE {1} IS NULL'.format(table,column,fid)
    conn.execute(query) #3
    conn.commit() #3 
    conn.execute('drop table tmp') #4

Wybrane narzędzia i metody biblioteki pandas

W poniższej części zostaną przedstawione wybrane funkcje biblioteki pandas, które będą wykorzystywane w dalszej części kursu. Biblioteka jest bardzo złożona i rozbudowana, szczegółowy opis funkcji biblioteki znajduje się w dokumentacji i licznych podręcznikach.

In [13]:
import sqlite3
os.chdir('/home/jarekj/Dropbox/dydaktyka/programowanie4/powiatData')
database = 'database.db' #1A
table = 'centroids' #1B
conn=sqlite3.connect(database) #2A
cur = conn.cursor() #2B
query = "SELECT * FROM {0};".format(table)#3
dt = pd.read_sql_query(query,conn)#4

Wybór kolumn i wierszy na podstawie nazwy i kryterium statystycznego

Jeżeli chcemy wybrać niektóre kolumny w podstaci nowej dataFrame używamy listy kolumn, które chcemy wybrać. Selekcję wierszy na postawie kryterium wykonujemy przy pomocy kryterium można wykonać na zasadzie porównania zwracającego serię True/False, a następnie użycie takiego wektora jako selekcji. Alternatywnie można zastosować metodę query().

In [14]:
selector = dt['aprod']>50000
dt[['powiat','aprod']][selector]
dt[['powiat','aprod']].query('aprod>50000')
Out[14]:
powiat aprod
27 Wrocław 80241
60 Łódź 84224
134 Kraków 99691
143 Warszawa 240280
239 Gdańsk 62473
337 poznański 65984
346 Poznań 72194
363 Szczecin 52423

Alternatywnie, jeżeli chcemy usunąć pojedyncze kolumny z wielu, możemy użyć metody drop(), wskazując jednoczesnie axis=1, jako informację że usuwamy kolumny. Zarówno selekcja jak i usuwanie ma charakter tymczasowy, jeżeli wyników nie zapiszemy w nowej dataFrame. Należy zaznaczyć, że kwestia ekstrakcji części danych (selekcja/usuwanie) nie jest gramatycznie spójna.

In [15]:
dt.drop(['aprod','prod','pprod'],axis=1)
Out[15]:
ogc_fid fid powiat woj m k malzenstwa przyrost GEOMETRY klasa results
0 1 1 złotoryjski 2 22059 22997 4.6 -2.3 b'\x00\x01\x84\x08\x00\x00O\x1b\xe7$0/\x11A\x8... 1 0
1 2 2 Legnica 2 48273 53719 4.4 -2.3 b'\x00\x01\x84\x08\x00\x00\xdd\x86\xc9\xe9\x9c... 3 9
2 3 3 jeleniogórski 2 31460 33711 3.9 -4.4 b'\x00\x01\x84\x08\x00\x00\xb2\x0f\xc5%\xf6Q\x... 1 4
3 4 4 górowski 2 17989 18402 5.3 -0.7 b'\x00\x01\x84\x08\x00\x00NGhG\xb40\x14A\xe7\x... 2 0
4 5 5 oleśnicki 2 51929 54159 4.7 0.3 b'\x00\x01\x84\x08\x00\x00\xf1\x9b+\xddZ+\x18A... 1 3
5 6 6 bolesławiecki 2 43962 46344 4.9 -0.6 b'\x00\x01\x84\x08\x00\x00\xc2:+\x1d\x91\x99\x... 1 4
6 7 7 Jelenia Góra 2 38235 43750 3.9 -4.5 b'\x00\x01\x84\x08\x00\x00\xb0\xaf\x9d\xe2\xa9... 3 6
7 8 8 kłodzki 2 79465 85215 4.5 -4.4 b"\x00\x01\x84\x08\x00\x00'f\xd1\xdf_*\x14A\xb... 3 9
8 9 9 lubański 2 27287 28830 4.4 -3.7 b'\x00\x01\x84\x08\x00\x00\x9e\t\x1e\xc2\xba;\... 1 9
9 10 10 wałbrzyski 2 27855 29979 4.0 -5.0 b'\x00\x01\x84\x08\x00\x00L\xe1\x06|\xbd\xb7\x... 3 4
10 11 11 dzierżoniowski 2 49805 54808 4.3 -4.4 b'\x00\x01\x84\x08\x00\x00DB\x0c\x1d\x02\x9f\x... 3 0
11 12 12 trzebnicki 2 40735 42306 4.2 0.2 b'\x00\x01\x84\x08\x00\x00\xcd\xf3\x0e\xbft\x0... 5 5
12 13 13 głogowski 2 43979 46323 5.1 0.9 b'\x00\x01\x84\x08\x00\x00G\x8f$\xef\xf6/\x12A... 1 3
13 14 14 Wałbrzych 2 55642 62284 3.7 -6.1 b'\x00\x01\x84\x08\x00\x00x\xba\x97\x9f\xc4\xd... 3 2
14 15 15 wołowski 2 23268 24301 4.9 -0.8 b'\x00\x01\x84\x08\x00\x00\t\xb2\xc7+\xefe\x14... 1 2
15 16 16 zgorzelecki 2 45397 47761 4.5 -2.5 b'\x00\x01\x84\x08\x00\x00\xd3\xf5\xe5!E\xb2\x... 1 7
16 17 17 wrocławski 2 62739 65157 4.2 3.4 b'\x00\x01\x84\x08\x00\x00\xd8<\xb52\x89\xd8\x... 5 4
17 18 18 ząbkowicki 2 33009 34866 4.2 -4.0 b'\x00\x01\x84\x08\x00\x00\x91Kn\x05\xfeY\x15A... 1 3
18 19 19 oławski 2 37065 38728 4.4 1.0 b'\x00\x01\x84\x08\x00\x00$\x89\xce\xfe`C\x17A... 5 3
19 20 20 polkowicki 2 31311 31929 5.2 2.2 b'\x00\x01\x84\x08\x00\x004\xa6|\xe5J\xca\x11A... 2 8
20 21 21 średzki 2 25890 26555 4.1 0.1 b'\x00\x01\x84\x08\x00\x00\xd1~?\x94\x95]\x14A... 5 8
21 22 22 jaworski 2 25554 26516 4.8 -2.8 b'\x00\x01\x84\x08\x00\x00\xf9\xf3\x168\xcbV\x... 1 9
22 23 23 milicki 2 18481 18839 4.7 0.9 b'\x00\x01\x84\x08\x00\x00\xa8\xb3\xeaG\xdce\x... 5 9
23 24 24 kamiennogórski 2 22017 23022 4.4 -5.0 b'\x00\x01\x84\x08\x00\x00\xb7I\xba\xe8\x86\x9... 4 3
24 25 25 strzeliński 2 21973 22420 4.4 -2.3 b'\x00\x01\x84\x08\x00\x006*\x12E\x8dO\x16A\xf... 1 2
25 26 26 świdnicki 2 77677 83255 4.5 -1.8 b'\x00\x01\x84\x08\x00\x00\xee\x7f\xa5\xaf\x8d... 1 9
26 27 27 legnicki 2 26854 28015 4.8 -2.5 b'\x00\x01\x84\x08\x00\x00W*\x98\x03\x18Y\x12A... 1 9
27 28 28 Wrocław 2 294662 337405 4.2 -0.7 b'\x00\x01\x84\x08\x00\x00\xe6$\xfc\x009\xf6\x... 3 4
28 29 29 lubiński 2 51809 54703 5.1 0.3 b'\x00\x01\x84\x08\x00\x00\x83\xca\xc7\xaf\xeb... 1 0
29 30 30 lwówecki 2 23109 24208 4.8 -3.7 b'\x00\x01\x84\x08\x00\x00\xb7\xad4\xe2\xc1U\x... 1 1
... ... ... ... ... ... ... ... ... ... ... ...
350 351 351 kaliski 30 40560 42025 4.8 0.5 b'\x00\x01\x84\x08\x00\x00\x86\x96\xab\xb7\xd0... 5 0
351 352 352 średzki 30 27975 28950 5.3 2.5 b'\x00\x01\x84\x08\x00\x005\x852\xfdD\x80\x17A... 2 2
352 353 353 śremski 30 29908 30817 5.1 1.9 b'\x00\x01\x84\x08\x00\x00\xdf\x93\xf4\xfd\xb3... 2 6
353 354 354 Kalisz 30 48376 55621 4.1 -2.8 b'\x00\x01\x84\x08\x00\x00\x12\xda\xa3\xcf\x1b... 3 7
354 355 355 Konin 30 36698 40526 4.9 -1.0 b'\x00\x01\x84\x08\x00\x00\x1c\x17\x12\x1e\xd6... 3 6
355 356 356 chodzieski 30 23432 24207 4.5 -0.3 b"\x00\x01\x84\x08\x00\x00#\x19\x08t\x91I\x16A... 5 1
356 357 357 gostyński 30 37699 38540 5.4 1.1 b'\x00\x01\x84\x08\x00\x00{\xc6=\xee\xb1^\x16A... 2 9
357 358 358 ostrzeszowski 30 27441 28013 5.0 0.3 b'\x00\x01\x84\x08\x00\x002mQsna\x1aA\xdax\xae... 2 7
358 359 359 Leszno 30 30877 33712 4.7 2.1 b'\x00\x01\x84\x08\x00\x00B\x8fFC\xfaU\x14A\xf... 1 8
359 360 360 gryfiński 32 41655 42225 4.6 -0.5 b'\x00\x01\x84\x08\x00\x00\xbf\xb2thp3\x08A8\x... 5 1
360 361 361 policki 32 36697 37786 4.2 4.2 b'\x00\x01\x84\x08\x00\x00\x0f\xa5\x7fJ\xbf\x1... 5 7
361 362 362 kołobrzeski 32 38298 41326 4.6 -0.6 b'\x00\x01\x84\x08\x00\x00\x99\n*@\x98\xf3\x10... 1 1
362 363 363 Koszalin 32 51619 57551 4.2 -1.7 b'\x00\x01\x84\x08\x00\x00\xbd:\xa1D\xeee\x13A... 3 6
363 364 364 Szczecin 32 194002 214170 4.1 -2.2 b'\x00\x01\x84\x08\x00\x00\xa3i\xa3\x0fq|\tA \... 3 3
364 365 365 wałecki 32 26625 27972 4.7 -1.3 b'\x00\x01\x84\x08\x00\x00_\xbb\xb3\xcc i\x13A... 1 5
365 366 366 łobeski 32 18846 19120 5.1 -1.9 b'\x00\x01\x84\x08\x00\x00\xb6\xdfX\xf9+W\x10A... 1 4
366 367 367 Świnoujście 32 20003 21368 4.0 -4.1 b'\x00\x01\x84\x08\x00\x00\xb5\x10\xd77\xad\x8... 3 8
367 368 368 pyrzycki 32 20287 20245 4.5 -0.1 b'\x00\x01\x84\x08\x00\x00K\xabH7\x9e\xda\x0bA... 5 1
368 369 369 sławieński 32 28503 29352 4.7 -0.1 b'\x00\x01\x84\x08\x00\x00\xe2x\x95\x86 \xfa\x... 5 4
369 370 370 szczecinecki 32 38559 40545 4.9 -0.8 b'\x00\x01\x84\x08\x00\x00~q\x14tD\xc8\x14A7`\... 1 0
370 371 371 świdwiński 32 23988 24594 4.8 -1.9 b'\x00\x01\x84\x08\x00\x00\xe6\xf0>3\xcc\xfa\x... 1 7
371 372 372 stargardzki 32 59235 61491 4.8 0.3 b'\x00\x01\x84\x08\x00\x00\x80>\x9b]\xa0R\x0eA... 1 6
372 373 373 koszaliński 32 32952 33029 4.8 0.5 b'\x00\x01\x84\x08\x00\x00\xd4\x1f\xadD|\r\x14... 5 2
373 374 374 białogardzki 32 24020 24879 4.4 -1.5 b'\x00\x01\x84\x08\x00\x00X\xba\xc4\n\xf8\xc0\... 1 8
374 375 375 choszczeński 32 24913 25016 4.8 -0.5 b'\x00\x01\x84\x08\x00\x00E\xba.\xddT\x91\x10A... 5 3
375 376 376 goleniowski 32 40603 41667 5.1 0.8 b'\x00\x01\x84\x08\x00\x00\x89?\x18\xbc\xba\xd... 2 0
376 377 377 drawski 32 28642 29761 4.2 -0.8 b'\x00\x01\x84\x08\x00\x00\x11p\xd9\xc6\xa7V\x... 5 7
377 378 378 gryficki 32 30510 31162 4.7 -0.6 b'\x00\x01\x84\x08\x00\x00\xe0\x15?\x97\xf9\xd... 5 8
378 379 379 kamieński 32 23583 24364 4.5 -2.0 b'\x00\x01\x84\x08\x00\x00\xc8\xe9\xcd\xbf\x0f... 1 9
379 380 380 myśliborski 32 33413 34285 4.6 -1.1 b'\x00\x01\x84\x08\x00\x00\xdfz\xbd\x0fR7\x0bA... 1 9

380 rows × 11 columns

Wybór kolumn i wierszy na podstawie pozycji

Jeżeli do wyboru wierszy i kolumn chcemy użyć informacji o ich pozycji musimy zastosować operator iloc, na pierwszym miejscu podajemy listę lub przedział wierszy a następnie listę lub przedział kolumn. Jeżeli dla jednej z osi chcemy pobrać cały zakres używamy operatora zasięgu [;].

In [16]:
dt.iloc[2:21,[1,3,7]]
Out[16]:
fid woj prod
2 3 2 44540
3 4 2 24457
4 5 2 71646
5 6 2 61039
6 7 2 53424
7 8 2 109961
8 9 2 38035
9 10 2 38781
10 11 2 69663
11 12 2 56580
12 13 2 61102
13 14 2 77848
14 15 2 32413
15 16 2 63098
16 17 2 87571
17 18 2 45811
18 19 2 50919
19 20 2 43297
20 21 2 36159

Wartości unikalne i sortowanie

Pozyskanie wartości unikalnych dla danej kolumny odbywa się za pomocą funkcji drop_duplicates(). W przypadku większej ilości kolumn usuwane będą duplikaty połączeń a nie pojedynczych wartości. Do posortowania wartości w data.frame służy metoda sort_values(). Wymaga wskazania kolumn według których wykonywane jest sortwanie i jego kierunek. W poniższym przykładzie połączono usuwanie duplikatów i sortowanie danych.

In [17]:
dt['woj'].drop_duplicates().sort_values()
Out[17]:
0       2
30      4
77      6
101     8
53     10
115    12
137    14
179    16
191    18
216    20
233    22
253    24
289    26
303    28
324    30
359    32
Name: woj, dtype: int64

Selekcja danych na podstawie funkcji języka Python

W przypadku, gdy zadanie nie jest możliwe do zrealizowania na podstawie dialektu SQL, można do wykonania selekcji zastosować bezpośrednio funkcje języka Python. Na przykład w celu wyboru powiatów miejskich - których nazwy zaczynają się z dużej litery, można zamienić nazwę powiatu "jak w tytule" a następnie porównać z oryginalną nazwą. W ten sposób wybierzemy tylko te, których nazwy piasane są z wielkiej litery. Tak utworzony selector (True/False) można wykorzystać do wyboru wierszy z data.frame.

In [18]:
selector = dt.powiat.str.title()==dt.powiat
dt.loc[selector,'powiat']
Out[18]:
1                   Legnica
6              Jelenia Góra
13                Wałbrzych
27                  Wrocław
30                Grudziądz
31                    Toruń
32                Włocławek
51                Bydgoszcz
60                     Łódź
61     Piotrków Trybunalski
62             Skierniewice
95           Biała Podlaska
98                   Lublin
99                    Chełm
100                  Zamość
103            Zielona Góra
104     Gorzów Wielkopolski
132                  Tarnów
134                  Kraków
135               Nowy Sącz
138                   Radom
142               Ostrołęka
143                Warszawa
156                 Siedlce
165                   Płock
182                   Opole
200                  Krosno
201                 Rzeszów
202                Przemyśl
203              Tarnobrzeg
               ...         
243                  Słupsk
253               Sosnowiec
259    Siemianowice Śląskie
261          Świętochłowice
263                   Tychy
265                  Zabrze
266                    Żory
274             Ruda Śląska
276        Jastrzębie-Zdrój
277                 Chorzów
278           Bielsko-Biała
279                   Bytom
281        Dąbrowa Górnicza
282             Częstochowa
283                 Gliwice
284         Piekary Śląskie
285                Katowice
286                Jaworzno
287               Mysłowice
288                  Rybnik
293                  Kielce
310                  Elbląg
311                 Olsztyn
346                  Poznań
353                  Kalisz
354                   Konin
358                  Leszno
362                Koszalin
363                Szczecin
366             Świnoujście
Name: powiat, Length: 66, dtype: object

Dodanie kolumny i tymczasowe dodanie kolumny

Jeżeli chcemy wybrać kolumnę poprzez nazwę wystarczy podać jej nazwę w nawiasach kwadratowych. Jeżeli do kolumny przypiszemy nową wartość, serię danych lub tablicę numpy o długości równej kolumnie jej wartość zostanie zastąpiona. Jeżeli kolumna nie istnieje zostanie utworzona. Typ danych zostanie wybrany automatycznie na podstawie przypisanej wartości. Poprzez metodę assign() można tymczasowo dodać kolumnę na czas wykonywania obliczeń. Jeżeli dodaną tę metodę kolumnę chcemy zachować, należy utworzyć nową dataFrame lub nadpisać istniejącą.

In [19]:
dt.assign(ludnosc=dt.aprod + dt['prod'] + dt.pprod).head(10)
dt['ludnosc'] = (dt.aprod + dt['prod'] + dt.pprod)

Grupowanie i statystki podsumowujące

Pandas umożliwia wyliczanie statystyk grupujących na podstawie kolumn zawierających nieunikalne wartości (kategoryzacyjne). Służą do tego dwie metody: groupby(), która wskazuje kolumnę grupującą oraz metody agg() wskazująca jakie funkcje statystyczne będą wyliczane dla grup. Jeżli wynik grupowania chcemy ograniczyć do wybranych kolumn należy użyć słownika zawierającą nazwę kolumny i wyliczane funkcje.

In [20]:
dt.groupby('woj').agg(['mean','std'])
dt.groupby('woj').agg({'aprod':['mean','std']})
Out[20]:
aprod
mean std
woj
2 13529.333333 13490.122178
4 13838.826087 9210.654609
6 13400.083333 8516.073217
8 11100.571429 3876.752680
10 14630.791667 15593.957252
12 24161.954545 19696.694300
14 19647.761905 35826.474100
16 11093.666667 4197.146874
18 13238.040000 6453.533015
20 10206.235294 8866.964690
22 18691.850000 13567.085147
24 17859.888889 6813.525652
26 12676.714286 7883.008713
28 10718.571429 5420.562033
30 15878.400000 13996.226496
32 11888.238095 9826.944433

Zmodyfikowanie zawartości kolumny

Jeżeli chcemy zmodyfikować zawartość kolumny jest to połączone najczęściej ze zmianą jej typu. W poniższym przykładzie...

In [21]:
wojs = {16:'OPOLSKIE', 
26:'ŚWIĘTOKRZYSKIE',
4:'KUJAWSKO-POMORSKIE',
14:'MAZOWIECKIE',
22:'POMORSKIE',
24:'ŚLĄSKIE',
28:'WARMIŃSKO-MAZURSKIE',
32:'ZACHODNIOPOMORSKIE',
2:'DOLNOŚLĄSKIE',
30:'WIELKOPOLSKIE',
10:'ŁÓDZKIE',
20:'PODLASKIE',
12:'MAŁOPOLSKIE',
8:'LUBUSKIE',
18:'PODKARPACKIE',
6:'LUBELSKIE'}

dt['nazwoj'] = 't'
for key in wojs:
   dt.loc[dt.woj==key,'nazwoj'] =wojs[key]
    
dt = dt.drop(['woj','GEOMETRY'],axis=1)   
dt.rename(columns={'nazwoj':'woj'},inplace=True)

Co to jest pickle czy warto stosować różnice z Python2

In [22]:
#import pickle
#pickle.dump(dt,open("dta.p","wb+"))