2023-programowanie-w-pythonie/zajecia2/data_analysis.ipynb
Jakub Pokrywka 31dffb89ba add zajecia2
2023-11-18 10:24:03 +01:00

236 KiB
Raw Blame History

Analiza Danych w Pythonie: pandas

pandas

Biblioteka pandas jest podstawowym narzędziem w ekosystemie Pythona do analizy danych:

  • dostarcza dwa podstawowe typy danych:
    • Series (szereg, 1D)
    • DataFrame (ramka danych, 2D)
  • operacje na tych obiektach: obsługa brakujących wartości, łączenie danych;
  • obsługuje dane różnego typu, np. szeregi czasowe;
  • biblioteka bazuje na numpy -- bibliotece do obliczeń numerycznych;
  • pozwala też na prostą wizualizację danych;
  • ETL: extract, transform, load.

Żeby zaimportowąc bibliotekę pandas wystarczy:

import pandas as pd

Zadanie 0: sprawdź, czy masz zainstalowaną bibliotekę pandas.

Szeregi (pd.Series)

Szereg reprezentuje jednorodne dane jednowymiarowe - jest odpowiednikiem wektora w R.

  • Szeregi możemy tworzyć na różne sposoby (więcej za chwilę), np. z obiektów tj. listy i słowniki.

  • Dane muszą być jednorodne. W przeciwnym przypadku nastąpi automatyczna konwersja.

  • Podczas tworzenia szeregu musimy podać jeden obowiązkowy argument data - dane.

  • Ponadto możemy podać też indeks (index), typ danych (dtype) lub nazwę (name).

    class pandas.Series(data=None, index=None, dtype=None, name=None)
    

Podczas tworzenie szeregu mozemy podać dane w formacie listy lub słownika.

Poniżej jest przykład przedstawiający tworzenie szeregu z danych, które są zawarte w liście:


data = [211819, 682758, 737011, 779511, 673790, 673790, 444177, 136791]

s = pd.Series(data)

s
0    211819
1    682758
2    737011
3    779511
4    673790
5    673790
6    444177
7    136791
dtype: int64

W przypadku, gdy dane pochodzą z listy i nie podaliśmy indeksu, pandas doda automatyczny indeks liczbowy zaczynający się od 0.

W przypadku przekazania słownika jako danych do szeregu, pandas wykorzysta klucze do stworzenia indeksu:

members = {'April': 211819,'May': 682758, 'June': 737011, 'July': 779511}

s = pd.Series(members)

s
April    211819
May      682758
June     737011
July     779511
dtype: int64

Podczas tworzenia szeregu możemy zdefiniować indeks, jak i nazwę szeregu:

months = ['April', 'May', 'June', 'July']

data = [211819, 682758, 737011, 779511]

s = pd.Series(data=data, index=months, dtype=float, name='Rides')

s
April    211819.0
May      682758.0
June     737011.0
July     779511.0
Name: Rides, dtype: float64

Odwołanie się do poszczególnego elementu odbywa się przy pomocy klucza z indeksu.

members = {'April': 211819,'May': 682758, 'June': 737011, 'July': 779511}

s = pd.Series(members)

print(s['April'])

s['August'] = 673790
s
211819
April     211819
May       682758
June      737011
July      779511
August    673790
dtype: int64

Dodanie elementu do szeregu odbywa się poprzez definiowanie nowego klucza:

members = {'April': 211819,'May': 682758, 'June': 737011, 'July': 779511}

s = pd.Series(members)

s['August'] = 673790

s
April     211819
May       682758
June      737011
July      779511
August    673790
dtype: int64

Więcej nt. indeksowania w szeregach w dalszej części kursu.

Podstawowa cechą szeregu jest wykonywanie operacji w sposób wektorowy. Działa to w następujący sposób:

  • gdy w obu szeregach jest zawarty ten sam klucz, to są sumowane ich wartości;
  • w przeciwnym przypadku wartość klucza w wynikowym szeregu to pd.NaN.
  • Równoważnie możemy wykorzystać metodę pandas.Series.add. W tym przypadku możemy podać domyślną wartość w przypadku braku klucza.
members = pd.Series({'May': 682758, 'June': 737011,  'August': 673790, 'July': 779511,
'September': 673790, 'October': 444177})

occasionals = pd.Series({'May': 147898, 'June': 171494, 'July': 194316, 'August': 206809,
'September': 140492})

all_data = members + occasionals
# Równoważnie
all_data = members.add(occasionals)
all_data
August       880599.0
July         973827.0
June         908505.0
May          830656.0
October           NaN
September    814282.0
dtype: float64

Możemy wykonać operacje arytmetyczne na szeregu:

members = pd.Series({'May': 682758, 'June': 737011, 'July': 779511, 'August': 673790,
'September': 673790, 'October': 444177})

members += 1000

members
May          683758
June         738011
July         780511
August       674790
September    674790
October      445177
dtype: int64

Podsumowanie

  • Szeregi działają podobnie do słowników, z tą różnicą, że wartości muszą być jednorodne (tego samego typu).
  • Odwołanie do poszczególnych elementów odbywa się poprzez nawiasy [] i podanie klucza.
  • W przeciwieństwie do słowników, możemy w prosty sposób wykonywać operacje arytmetyczne.

Zadanie 1

  • Stwórz szereg n, który będzie zawierać liczby od 0 do 10 (włącznie).
  • Stwórz szereg n2, który będzie zawierać kwadraty liczb od 0 do 10 (włącznie).
  • Następnie stwórz szereg trojkatne, który będzie sumą powyższych szeregów podzieloną przez 2.

Ramka danych (pd.DataFrame)

Ramka danych jest podstawową strukturą danych w bibliotece pandas, która pozwala na trzymanie i reprezentowanie danych tabelarycznych (dwuwymiarowych).

  • Posiada kolumny (cechy) i wiersze (obserwacje, przykłady).
  • Możemy też patrzeć na nią jak na słownik, którego wartościami są szeregi.
class pandas.DataFrame(data=None, index=None, columns=None, dtype=None)

Ramkę danych możemy stworzyć na różne sposoby.

Pierwszy z nich ("kolumnowy") polega na zdefiniowaniu ramki poprzez podanie szeregów jako kolumn:

members = pd.Series({'May': 682758, 'June': 737011, 'July': 779511})
occasionals = pd.Series({'May': 147898, 'June': 171494, 'July': 194316})

df = pd.DataFrame({'members': members, 'occasionals': occasionals})
df
members occasionals
May 682758 147898
June 737011 171494
July 779511 194316

Drugim popularnym sposobem jest przekazanie listy słowników. Wtedy pandas zinterpretuje to jako listę przykładów:

data = [
    {'members': 682758, 'occasionals': 147898},
    {'occasionals': 171494,'members': 737011},
    {'members': 779511, 'occasionals': 194316},
]

df = pd.DataFrame(data)

df
members occasionals
0 682758 147898
1 737011 171494
2 779511 194316

Możemy też wykorzystać metodę from_dict (doc), która pozwala zdefiniować czy podane dane są w podane w postaci kolumnowej lub wierszowej:

data = {
    'May': {'members': 682758, 'occasionals': 147898},
    'June': {'members': 737011, 'occasionals': 171494},
    'July': {'members': 779511, 'occasionals': 194316}
}

df = pd.DataFrame.from_dict(data, orient='index')
print('index\n', df)
print()
df = pd.DataFrame.from_dict(data, orient='columns')
print('columns\n', df)
index
       members  occasionals
May    682758       147898
June   737011       171494
July   779511       194316

columns
                 May    June    July
members      682758  737011  779511
occasionals  147898  171494  194316

Wczytywanie danych

Biblioteka pandas pozwala na wczytanie i zapis danych z różnych formatów:

  • formaty tekstowe, np. csv, json
  • pliki arkuszy kalkulacyjnych: Excel (xls, xlsx)
  • bazy danych
  • inne: sas spss

Efektem wczytania danych jest odpowiednio stworzona ramka danych (DataFrame).

Jednym z najprostszych formatów danych jest format csv, gdzie kolejne wartości są rozdzielone przecinkiem.

Żeby wczytać dane w takim formacie należy użyć funkcji pandas.read_csv.

Pandas pozwala na ustawienie wielu parametrów (np. separator, cudzysłowy). Więcej na ten temat w dokumentacji.

df = pd.read_csv('gapminder.csv')

df
Country female_BMI male_BMI gdp population under5mortality life_expectancy fertility
0 Afghanistan 21.07402 20.62058 1311.0 26528741.0 110.4 52.8 6.20
1 Albania 25.65726 26.44657 8644.0 2968026.0 17.9 76.8 1.76
2 Algeria 26.36841 24.59620 12314.0 34811059.0 29.5 75.5 2.73
3 Angola 23.48431 22.25083 7103.0 19842251.0 192.0 56.7 6.43
4 Antigua and Barbuda 27.50545 25.76602 25736.0 85350.0 10.9 75.5 2.16
... ... ... ... ... ... ... ... ...
170 Venezuela 28.13408 27.44500 17911.0 28116716.0 17.1 74.2 2.53
171 Vietnam 21.06500 20.91630 4085.0 86589342.0 26.2 74.1 1.86
172 Palestine 29.02643 26.57750 3564.0 3854667.0 24.7 74.1 4.38
173 Zambia 23.05436 20.68321 3039.0 13114579.0 94.9 51.1 5.88
174 Zimbabwe 24.64522 22.02660 1286.0 13495462.0 98.3 47.3 3.85

175 rows × 8 columns

df = pd.read_csv('./titanic_train.tsv', delimiter='\t', index_col=0, nrows=5)
df
Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
PassengerId
1 0 3 Braund\t Mr. Owen Harris male 22 1 0 A/5 21171 7.2500 NaN S
2 1 1 Cumings\t Mrs. John Bradley (Florence Briggs T... female 38 1 0 PC 17599 71.2833 C85 C
3 1 3 Heikkinen\t Miss. Laina female 26 0 0 STON/O2. 3101282 7.9250 NaN S
4 1 1 Futrelle\t Mrs. Jacques Heath (Lily May Peel) female 35 1 0 113803 53.1000 C123 S
5 0 3 Allen\t Mr. William Henry male 35 0 0 373450 8.0500 NaN S

Do wczytania danych z arkusza kalkulacyjnego służy funkcja pandas.read_excel. Do otworzenia pliku xlsx może być koniecnze ustawienie parametru: engine='openpyxl. Więcej opcji w dokumentacji.

df = pd.read_excel('./bikes.xlsx', engine='openpyxl', nrows=5)
df
start_date start_station_code end_date end_station_code duration_sec is_member
0 2019-04-14 07:55:22 6001 2019-04-14 08:07:16 6132 713 1
1 2019-04-14 07:59:31 6411 2019-04-14 08:09:18 6411 587 1
2 2019-04-14 07:59:55 6097 2019-04-14 08:12:11 6036 736 1
3 2019-04-14 07:59:57 6310 2019-04-14 08:27:58 6345 1680 1
4 2019-04-14 08:00:37 7029 2019-04-14 08:14:12 6250 814 0

Innym ważnym źródłem informacji są bazy danych. Pandas potrafi komunikować się z bazą danych za pomocą biblioteki SQLAlchemy i dostarcza odpowiedną funkcję:

  • pandas.read_sql - wczytanie całej tabeli lub zapytania do bazy danych
df = pd.read_sql('Album', con='sqlite:///Chinook.sqlite', index_col='AlbumId')

df
Title ArtistId
AlbumId
1 For Those About To Rock We Salute You 1
2 Balls to the Wall 2
3 Restless and Wild 2
4 Let There Be Rock 1
5 Big Ones 3
... ... ...
343 Respighi:Pines of Rome 226
344 Schubert: The Late String Quartets & String Qu... 272
345 Monteverdi: L'Orfeo 273
346 Mozart: Chamber Music 274
347 Koyaanisqatsi (Soundtrack from the Motion Pict... 275

347 rows × 2 columns

import sqlalchemy

engine = sqlalchemy.create_engine('sqlite:///Chinook.sqlite', echo=True)
connection  = engine.raw_connection()

df = pd.read_sql('SELECT * FROM Album', con='sqlite:///Chinook.sqlite', index_col='AlbumId')
df
2023-11-17 15:53:28,542 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
2023-11-17 15:53:28,543 INFO sqlalchemy.engine.base.Engine ()
2023-11-17 15:53:28,544 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
2023-11-17 15:53:28,545 INFO sqlalchemy.engine.base.Engine ()
Title ArtistId
AlbumId
1 For Those About To Rock We Salute You 1
2 Balls to the Wall 2
3 Restless and Wild 2
4 Let There Be Rock 1
5 Big Ones 3
... ... ...
343 Respighi:Pines of Rome 226
344 Schubert: The Late String Quartets & String Qu... 272
345 Monteverdi: L'Orfeo 273
346 Mozart: Chamber Music 274
347 Koyaanisqatsi (Soundtrack from the Motion Pict... 275

347 rows × 2 columns

Podsumowanie

  • Biblioteka pandas wspiera pobieranie danych z różnych formatów i źródeł.
  • Każda funkcja ma listę argumentów, które pozwalają na ustawić poszczególne parametry (np. read_csv).

Zapis i eksport danych

Pandas pozwala w prosty sposób na zapisywanie ramki danych do pliku.

members = pd.Series({'May': 682758, 'June': 737011, 'July': 779511})
occasionals = pd.Series({'May': 147898, 'June': 171494, 'July': 194316})

df = pd.DataFrame({'members': members, 'occasionals': occasionals})
# zapis do formatu CSV
df.to_csv('tmp.csv')
# zapis do arkusza kalkulacyjnego 
df.to_excel('tmp.xlsx')

Ponadto możemy przekonwertować ramkę danych do JSONa lub Pythonowego słownika:

print(df.to_json())
{"members":{"May":682758,"June":737011,"July":779511},"occasionals":{"May":147898,"June":171494,"July":194316}}
print(df.to_dict())
{'members': {'May': 682758, 'June': 737011, 'July': 779511}, 'occasionals': {'May': 147898, 'June': 171494, 'July': 194316}}

Lub przekopiować dane do schowka:

df.to_clipboard()

Zadanie

  • Przekonwertuj tabele Customer z bazy Chinook.sqlite do arkusza kalkulacyjnego. Plik wynikowy nazwij customers.xlsx.
  • Tabela Employee zawiera informacje o pracownikach firmy Chinook. Wyswietl dane na ekranie i podaj miasta, w których mieszkają pracownicy.
  • Tabela Invoice zawiera informacje o fakturach. Przekonwertuj kolumnę BillingCountry do pythonowego słownika, a następnie podaj najcześciej występującą wartość. Ile razy pojawiła się?

Ramka danych - podstawy

Kolumny

Na ramkę danych możemy patrzeć jak na swego rodzaju słownik, którego wartościami są szeregi. Pozwoli to na uzyskanie lepszej intuicji.

df = pd.read_csv('./gapminder.csv', index_col='Country', nrows=8, usecols=['Country', 'gdp', 'population','life_expectancy'])

df
gdp population life_expectancy
Country
Afghanistan 1311.0 26528741.0 52.8
Albania 8644.0 2968026.0 76.8
Algeria 12314.0 34811059.0 75.5
Angola 7103.0 19842251.0 56.7
Antigua and Barbuda 25736.0 85350.0 75.5
Argentina 14646.0 40381860.0 75.4
Armenia 7383.0 2975029.0 72.3
Australia 41312.0 21370348.0 81.6

Dostęp do poszczególnej kolumny możemy uzystać na dwa sposoby:

# notacja z kropką
df.population
Country
Afghanistan            26528741.0
Albania                 2968026.0
Algeria                34811059.0
Angola                 19842251.0
Antigua and Barbuda       85350.0
Argentina              40381860.0
Armenia                 2975029.0
Australia              21370348.0
Name: population, dtype: float64
# Operator []
df['population']
Country
Afghanistan            26528741.0
Albania                 2968026.0
Algeria                34811059.0
Angola                 19842251.0
Antigua and Barbuda       85350.0
Argentina              40381860.0
Armenia                 2975029.0
Australia              21370348.0
Name: population, dtype: float64

Do operatora [] możemy też podać listę nazw kolumn:

df[['gdp','population']]
gdp population
Country
Afghanistan 1311.0 26528741.0
Albania 8644.0 2968026.0
Algeria 12314.0 34811059.0
Angola 7103.0 19842251.0
Antigua and Barbuda 25736.0 85350.0
Argentina 14646.0 40381860.0
Armenia 7383.0 2975029.0
Australia 41312.0 21370348.0

Listę kolumn możemy pobrać za pomocą:

df.columns
Index(['gdp', 'population', 'life_expectancy'], dtype='object')
df.columns = ['PKB', 'Populacja', 'ODŻ']

df
PKB Populacja ODŻ
Country
Afghanistan 1311.0 26528741.0 52.8
Albania 8644.0 2968026.0 76.8
Algeria 12314.0 34811059.0 75.5
Angola 7103.0 19842251.0 56.7
Antigua and Barbuda 25736.0 85350.0 75.5
Argentina 14646.0 40381860.0 75.4
Armenia 7383.0 2975029.0 72.3
Australia 41312.0 21370348.0 81.6

Żeby odwołać się do poszczególnych wierszy należy wykorzystać metodę loc:

df.loc['Argentina']
PKB             14646.0
Populacja    40381860.0
ODŻ                75.4
Name: Argentina, dtype: float64

Metoda loc również może przyjąć listę wierszy:

df.loc[['Albania', 'Angola']]
PKB Populacja ODŻ
Country
Albania 8644.0 2968026.0 76.8
Angola 7103.0 19842251.0 56.7

Możemy również podać drugi parametr: nazwy kolumn:

df2 = df.loc[['Albania', 'Angola'], ['PKB', 'Populacja']]

df2
PKB Populacja
Country
Albania 8644.0 2968026.0
Angola 7103.0 19842251.0

Albo wykorzystać tzw. _slicing, cyzli operator ::

df.loc['Albania': 'Angola', 'PKB': 'ODŻ']
PKB Populacja ODŻ
Country
Albania 8644.0 2968026.0 76.8
Algeria 12314.0 34811059.0 75.5
Angola 7103.0 19842251.0 56.7

Żeby odwołać się do pojedyńczej wartości możemy użyć metody at:

df.at['Angola', 'PKB']
7103.0

Dostęp do indeksu:

df.index
Index(['Afghanistan', 'Albania', 'Algeria', 'Angola', 'Antigua and Barbuda',
       'Argentina', 'Armenia', 'Australia'],
      dtype='object', name='Country')

Podstawowe metody pd.Series i pd.DataFrame

members = pd.Series({'May': 682758, 'June': 737011, 'July': 779511, 'August': 673790,
'September': 673790, 'October': 444177})

occasionals = pd.Series({'May': 147898, 'June': 171494, 'July': 194316, 'August': 206809,
'September': 140492, 'October': 53596})

df = pd.DataFrame({'members': members, 'occasionals': occasionals})

df
members occasionals
May 682758 147898
June 737011 171494
July 779511 194316
August 673790 206809
September 673790 140492
October 444177 53596

Metoda head pozwala tworzy nową ramkę danych z pierwszymi 5 przykładami:

df.head()
members occasionals
May 682758 147898
June 737011 171494
July 779511 194316
August 673790 206809
September 673790 140492

Metoda tail robi to samo, ale z 5 ostatnymi przykładami:

df.tail()
members occasionals
June 737011 171494
July 779511 194316
August 673790 206809
September 673790 140492
October 444177 53596

Metoda sample pozwala na stworzenie nowej ramki danych z wylosowanymi n przykładami:

df.sample(3)
members occasionals
October 444177 53596
June 737011 171494
May 682758 147898

Metoda describe zwraca podstawowe statystyki m.in.: liczebność, średnią, wartości skrajne:

df.describe()
members occasionals
count 6.000000 6.000000
mean 665172.833333 152434.166667
std 116216.045456 54783.506738
min 444177.000000 53596.000000
25% 673790.000000 142343.500000
50% 678274.000000 159696.000000
75% 723447.750000 188610.500000
max 779511.000000 206809.000000

Metoda info zwraca informacje techniczne o kolumnach: np. typ danych:

df.info()
<class 'pandas.core.frame.DataFrame'>
Index: 6 entries, May to October
Data columns (total 2 columns):
 #   Column       Non-Null Count  Dtype
---  ------       --------------  -----
 0   members      6 non-null      int64
 1   occasionals  6 non-null      int64
dtypes: int64(2)
memory usage: 144.0+ bytes

Podstawową informacją o ramce danych to liczba przykładów w ramce danych. Możemy wykorzystać to tego funkcję len:

len(df)
6

Natomiast atrybut shape zwraca nam krotkę z liczbą przykładów i liczbą kolumn:

df.shape
(6, 2)

Operacja arytmetyczne

  • max, idxmax
  • min, idxmin
  • mean
  • count
df.mean()
members        665172.833333
occasionals    152434.166667
dtype: float64

Zbiór wartości i zliczanie wartości:

dane = pd.Series([1, 3, 2, 3, 1, 1, 2, 3, 2, 3])

print(dane.unique())

dane = pd.Series([1, 3, 2, 3, 1, 1, 2, 3, 2, 3])

print(dane.value_counts())
[1 3 2]
3    4
1    3
2    3
dtype: int64

Sprawdzanie czy brakuje danych:

df = pd.read_csv('./titanic_train.tsv', sep='\t', index_col='PassengerId')
df.Age.isnull()
PassengerId
1      False
2      False
3      False
4      False
5      False
       ...  
887    False
888    False
889     True
890    False
891    False
Name: Age, Length: 891, dtype: bool

Dodawanie i modyfikowanie danych

df = pd.read_csv('./gapminder.csv', index_col='Country', nrows=5)

df
female_BMI male_BMI gdp population under5mortality life_expectancy fertility
Country
Afghanistan 21.07402 20.62058 1311.0 26528741.0 110.4 52.8 6.20
Albania 25.65726 26.44657 8644.0 2968026.0 17.9 76.8 1.76
Algeria 26.36841 24.59620 12314.0 34811059.0 29.5 75.5 2.73
Angola 23.48431 22.25083 7103.0 19842251.0 192.0 56.7 6.43
Antigua and Barbuda 27.50545 25.76602 25736.0 85350.0 10.9 75.5 2.16
conts = pd.Series({
    'Afghanistan': 'Asia', 'Albania': 'Europe', 'Algeria':' Africa', 'Angola': 'Africa', 'Antigua and Barbuda': 'Americas'})

df['continent'] = conts

df['tmp'] = 1

df
female_BMI male_BMI gdp population under5mortality life_expectancy fertility continent tmp
Country
Afghanistan 21.07402 20.62058 1311.0 26528741.0 110.4 52.8 6.20 Asia 1
Albania 25.65726 26.44657 8644.0 2968026.0 17.9 76.8 1.76 Europe 1
Algeria 26.36841 24.59620 12314.0 34811059.0 29.5 75.5 2.73 Africa 1
Angola 23.48431 22.25083 7103.0 19842251.0 192.0 56.7 6.43 Africa 1
Antigua and Barbuda 27.50545 25.76602 25736.0 85350.0 10.9 75.5 2.16 Americas 1
df.loc['Argentina'] = {
    'female_BMI': 27.46523,
    'male_BMI': 27.5017,
    'gdp': 14646.0,
    'population': 40381860.0,
    'under5mortality': 15.4,
    'life_expectancy': 75.4,
    'fertility': 2.24
}
df
female_BMI male_BMI gdp population under5mortality life_expectancy fertility continent tmp
Country
Afghanistan 21.07402 20.62058 1311.0 26528741.0 110.4 52.8 6.20 Asia 1.0
Albania 25.65726 26.44657 8644.0 2968026.0 17.9 76.8 1.76 Europe 1.0
Algeria 26.36841 24.59620 12314.0 34811059.0 29.5 75.5 2.73 Africa 1.0
Angola 23.48431 22.25083 7103.0 19842251.0 192.0 56.7 6.43 Africa 1.0
Antigua and Barbuda 27.50545 25.76602 25736.0 85350.0 10.9 75.5 2.16 Americas 1.0
Argentina 27.46523 27.50170 14646.0 40381860.0 15.4 75.4 2.24 NaN NaN
df.drop('gdp', axis='columns')
female_BMI male_BMI population under5mortality life_expectancy fertility continent tmp
Country
Afghanistan 21.07402 20.62058 26528741.0 110.4 52.8 6.20 Asia 1.0
Albania 25.65726 26.44657 2968026.0 17.9 76.8 1.76 Europe 1.0
Algeria 26.36841 24.59620 34811059.0 29.5 75.5 2.73 Africa 1.0
Angola 23.48431 22.25083 19842251.0 192.0 56.7 6.43 Africa 1.0
Antigua and Barbuda 27.50545 25.76602 85350.0 10.9 75.5 2.16 Americas 1.0
Argentina 27.46523 27.50170 40381860.0 15.4 75.4 2.24 NaN NaN

Filtrowanie danych

Biblioteka pandas posiada 2 sposoby na filtrowanie danych zawartych w ramce danych:

  • operator [] -- najbardziej rozpowszechniony;
  • metoda query(). Oba sposoby mają różną składnię.
df = pd.read_csv('./titanic_train.tsv', sep='\t', index_col='PassengerId')

df.head()
Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
PassengerId
1 0 3 Braund\t Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
2 1 1 Cumings\t Mrs. John Bradley (Florence Briggs T... female 38.0 1 0 PC 17599 71.2833 C85 C
3 1 3 Heikkinen\t Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
4 1 1 Futrelle\t Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
5 0 3 Allen\t Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S
df['Survived']
PassengerId
1      0
2      1
3      1
4      1
5      0
      ..
887    0
888    1
889    0
890    1
891    0
Name: Survived, Length: 891, dtype: int64
df['Survived'] == 1
PassengerId
1      False
2       True
3       True
4       True
5      False
       ...  
887    False
888     True
889    False
890     True
891    False
Name: Survived, Length: 891, dtype: bool
df[df['Pclass'] == 1]
Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
PassengerId
2 1 1 Cumings\t Mrs. John Bradley (Florence Briggs T... female 38.0 1 0 PC 17599 71.2833 C85 C
4 1 1 Futrelle\t Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
7 0 1 McCarthy\t Mr. Timothy J male 54.0 0 0 17463 51.8625 E46 S
12 1 1 Bonnell\t Miss. Elizabeth female 58.0 0 0 113783 26.5500 C103 S
24 1 1 Sloper\t Mr. William Thompson male 28.0 0 0 113788 35.5000 A6 S
... ... ... ... ... ... ... ... ... ... ... ...
872 1 1 Beckwith\t Mrs. Richard Leonard (Sallie Monypeny) female 47.0 1 1 11751 52.5542 D35 S
873 0 1 Carlsson\t Mr. Frans Olof male 33.0 0 0 695 5.0000 B51 B53 B55 S
880 1 1 Potter\t Mrs. Thomas Jr (Lily Alexenia Wilson) female 56.0 0 1 11767 83.1583 C50 C
888 1 1 Graham\t Miss. Margaret Edith female 19.0 0 0 112053 30.0000 B42 S
890 1 1 Behr\t Mr. Karl Howell male 26.0 0 0 111369 30.0000 C148 C

216 rows × 11 columns

Operatory

  • & - koniukcja (i)
  • | - alternatywa (lub)
  • ~ - negacja (nie)
  • () - jeżeli mamy kilka warunków to warto je uporządkować w nawiasy
pierwsza_klasa = df['Pclass'] == 1
kobiety = df['Sex'] == 'female'

df[pierwsza_klasa & kobiety]
Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
PassengerId
2 1 1 Cumings\t Mrs. John Bradley (Florence Briggs T... female 38.0 1 0 PC 17599 71.2833 C85 C
4 1 1 Futrelle\t Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
12 1 1 Bonnell\t Miss. Elizabeth female 58.0 0 0 113783 26.5500 C103 S
32 1 1 Spencer\t Mrs. William Augustus (Marie Eugenie) female NaN 1 0 PC 17569 146.5208 B78 C
53 1 1 Harper\t Mrs. Henry Sleeper (Myna Haxtun) female 49.0 1 0 PC 17572 76.7292 D33 C
... ... ... ... ... ... ... ... ... ... ... ...
857 1 1 Wick\t Mrs. George Dennick (Mary Hitchcock) female 45.0 1 1 36928 164.8667 NaN S
863 1 1 Swift\t Mrs. Frederick Joel (Margaret Welles B... female 48.0 0 0 17466 25.9292 D17 S
872 1 1 Beckwith\t Mrs. Richard Leonard (Sallie Monypeny) female 47.0 1 1 11751 52.5542 D35 S
880 1 1 Potter\t Mrs. Thomas Jr (Lily Alexenia Wilson) female 56.0 0 1 11767 83.1583 C50 C
888 1 1 Graham\t Miss. Margaret Edith female 19.0 0 0 112053 30.0000 B42 S

94 rows × 11 columns


df[df['SibSp'] > df['Parch']]
Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
PassengerId
1 0 3 Braund\t Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
2 1 1 Cumings\t Mrs. John Bradley (Florence Briggs T... female 38.0 1 0 PC 17599 71.2833 C85 C
4 1 1 Futrelle\t Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
8 0 3 Palsson\t Master. Gosta Leonard male 2.0 3 1 349909 21.0750 NaN S
10 1 2 Nasser\t Mrs. Nicholas (Adele Achem) female 14.0 1 0 237736 30.0708 NaN C
... ... ... ... ... ... ... ... ... ... ... ...
861 0 3 Hansen\t Mr. Claus Peter male 41.0 2 0 350026 14.1083 NaN S
862 0 2 Giles\t Mr. Frederick Edward male 21.0 1 0 28134 11.5000 NaN S
864 0 3 Sage\t Miss. Dorothy Edith "Dolly" female NaN 8 2 CA. 2343 69.5500 NaN S
867 1 2 Duran y More\t Miss. Asuncion female 27.0 1 0 SC/PARIS 2149 13.8583 NaN C
875 1 2 Abelson\t Mrs. Samuel (Hannah Wizosky) female 28.0 1 0 P/PP 3381 24.0000 NaN C

192 rows × 11 columns

pd.DataFrame.query

Innym sposobem na filtrowanie danych jest metoda query, która jako argument przyjmuje wyrażenie:

df.query('Pclass == 1').head()
Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
PassengerId
2 1 1 Cumings\t Mrs. John Bradley (Florence Briggs T... female 38.0 1 0 PC 17599 71.2833 C85 C
4 1 1 Futrelle\t Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
7 0 1 McCarthy\t Mr. Timothy J male 54.0 0 0 17463 51.8625 E46 S
12 1 1 Bonnell\t Miss. Elizabeth female 58.0 0 0 113783 26.5500 C103 S
24 1 1 Sloper\t Mr. William Thompson male 28.0 0 0 113788 35.5000 A6 S
df.query('(Pclass == 1) and (Sex == "female")').head()
Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
PassengerId
2 1 1 Cumings\t Mrs. John Bradley (Florence Briggs T... female 38.0 1 0 PC 17599 71.2833 C85 C
4 1 1 Futrelle\t Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
12 1 1 Bonnell\t Miss. Elizabeth female 58.0 0 0 113783 26.5500 C103 S
32 1 1 Spencer\t Mrs. William Augustus (Marie Eugenie) female NaN 1 0 PC 17569 146.5208 B78 C
53 1 1 Harper\t Mrs. Henry Sleeper (Myna Haxtun) female 49.0 1 0 PC 17572 76.7292 D33 C
df.query('SibSp > Parch')
Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
PassengerId
1 0 3 Braund\t Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
2 1 1 Cumings\t Mrs. John Bradley (Florence Briggs T... female 38.0 1 0 PC 17599 71.2833 C85 C
4 1 1 Futrelle\t Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
8 0 3 Palsson\t Master. Gosta Leonard male 2.0 3 1 349909 21.0750 NaN S
10 1 2 Nasser\t Mrs. Nicholas (Adele Achem) female 14.0 1 0 237736 30.0708 NaN C
... ... ... ... ... ... ... ... ... ... ... ...
861 0 3 Hansen\t Mr. Claus Peter male 41.0 2 0 350026 14.1083 NaN S
862 0 2 Giles\t Mr. Frederick Edward male 21.0 1 0 28134 11.5000 NaN S
864 0 3 Sage\t Miss. Dorothy Edith "Dolly" female NaN 8 2 CA. 2343 69.5500 NaN S
867 1 2 Duran y More\t Miss. Asuncion female 27.0 1 0 SC/PARIS 2149 13.8583 NaN C
875 1 2 Abelson\t Mrs. Samuel (Hannah Wizosky) female 28.0 1 0 P/PP 3381 24.0000 NaN C

192 rows × 11 columns

young = 18
df.query('Age < @young').shape
(113, 11)

Zadanie

Operacje na wierszach i kolumnach

df = pd.read_csv('./gapminder.csv', index_col='Country', nrows=5)

df
female_BMI male_BMI gdp population under5mortality life_expectancy fertility
Country
Afghanistan 21.07402 20.62058 1311.0 26528741.0 110.4 52.8 6.20
Albania 25.65726 26.44657 8644.0 2968026.0 17.9 76.8 1.76
Algeria 26.36841 24.59620 12314.0 34811059.0 29.5 75.5 2.73
Angola 23.48431 22.25083 7103.0 19842251.0 192.0 56.7 6.43
Antigua and Barbuda 27.50545 25.76602 25736.0 85350.0 10.9 75.5 2.16

Iterowanie po ramce danych oznacza oznacza przejście po nazwach kolumn:

for column_name in df:
    print(column_name)
female_BMI
male_BMI
gdp
population
under5mortality
life_expectancy
fertility
for col_name, series in df.items():
    print(col_name, series)
    break
female_BMI Country
Afghanistan            21.07402
Albania                25.65726
Algeria                26.36841
Angola                 23.48431
Antigua and Barbuda    27.50545
Name: female_BMI, dtype: float64
for idx, row in df.iterrows():
    print(idx, '\n', row)
    break
Afghanistan 
 female_BMI         2.107402e+01
male_BMI           2.062058e+01
gdp                1.311000e+03
population         2.652874e+07
under5mortality    1.104000e+02
life_expectancy    5.280000e+01
fertility          6.200000e+00
Name: Afghanistan, dtype: float64
def bmi_level(bmi):
    if bmi <= 18.5:
        level =  'underweight'
    elif bmi < 25:
        level =  'normal'
    elif bmi < 30:
        level =  'overweight'
    else:
        level = 'obese'
    return level

s = df['male_BMI'].map(bmi_level)
    
s
Country
Afghanistan                normal
Albania                overweight
Algeria                    normal
Angola                     normal
Antigua and Barbuda    overweight
Name: male_BMI, dtype: object
def bmi_level(row_data):
    bmi = row_data['male_BMI']
    if bmi <= 18.5:
        return 'underweight'
    elif bmi < 25:
        return 'normal'
    elif bmi < 30:
        return 'overweight'
    return  'obese'

df.apply(bmi_level, axis=1)
Country
Afghanistan                normal
Albania                overweight
Algeria                    normal
Angola                     normal
Antigua and Barbuda    overweight
dtype: object
df.transpose()
Country Afghanistan Albania Algeria Angola Antigua and Barbuda
female_BMI 2.107402e+01 2.565726e+01 2.636841e+01 2.348431e+01 27.50545
male_BMI 2.062058e+01 2.644657e+01 2.459620e+01 2.225083e+01 25.76602
gdp 1.311000e+03 8.644000e+03 1.231400e+04 7.103000e+03 25736.00000
population 2.652874e+07 2.968026e+06 3.481106e+07 1.984225e+07 85350.00000
under5mortality 1.104000e+02 1.790000e+01 2.950000e+01 1.920000e+02 10.90000
life_expectancy 5.280000e+01 7.680000e+01 7.550000e+01 5.670000e+01 75.50000
fertility 6.200000e+00 1.760000e+00 2.730000e+00 6.430000e+00 2.16000

Zadanie

Grupowanie (groupby)

Często zdarza się, gdy potrzebujemy podzielić dane ze względu na wartości w zadanej kolumnie, a następnie obliczenie zebranie danych w każdej z grup. Do tego służy metody groupby.

import pandas as pd

df = pd.read_csv('./nba.csv')

df.sample(5)
Name Team Number Position Age Height Weight College Salary
401 Tyus Jones Minnesota Timberwolves 1.0 PG 20.0 6-2 195.0 Duke 1282080.0
342 Gerald Green Miami Heat 14.0 SF 30.0 6-7 205.0 NaN 947276.0
143 DeMarcus Cousins Sacramento Kings 15.0 C 25.0 6-11 270.0 Kentucky 15851950.0
267 P.J. Hairston Memphis Grizzlies 19.0 SF 23.0 6-6 230.0 North Carolina 1201440.0
335 Jeremy Lin Charlotte Hornets 7.0 PG 27.0 6-3 200.0 Harvard 2139000.0

_Przykład: chcemy obliczyć średnią wypłatę dla każdej z drużyn.

df[['Team', 'Salary']].groupby('Team').mean().head()
Salary
Team
Atlanta Hawks 4.860197e+06
Boston Celtics 4.181505e+06
Brooklyn Nets 3.501898e+06
Charlotte Hornets 5.222728e+06
Chicago Bulls 5.785559e+06

Możemy też podać listę nazw kolumn. Wtedy wartości zostaną obliczone dla każdej z wytworzonych grup:

df.groupby(['Team', 'Position'])['Salary'].mean()
Team                Position
Atlanta Hawks       C           7.585417e+06
                    PF          5.988067e+06
                    PG          4.881700e+06
                    SF          3.000000e+06
                    SG          2.607758e+06
                                    ...     
Washington Wizards  C           8.163476e+06
                    PF          5.650000e+06
                    PG          9.011208e+06
                    SF          2.789700e+06
                    SG          2.839248e+06
Name: Salary, Length: 149, dtype: float64
  • sum()
  • min()
  • max()
  • mean()
  • size()
  • describe()
  • first()
  • last()
  • count()
  • std()
  • var()
  • sem()
df[['Position', 'Salary']].groupby('Position').agg(['mean', 'std', 'count'])
Salary
mean std count
Position
C 5.967052e+06 5.787989e+06 78
PF 4.562483e+06 4.800054e+06 97
PG 5.077829e+06 5.051809e+06 88
SF 4.857393e+06 6.011889e+06 84
SG 4.009861e+06 4.491609e+06 99
def group_range(x):
    return x.max() - x.min()

df[['Position', 'Salary']].groupby('Position').apply(group_range)
Salary
Position
C 22275967.0
PF 22081286.0
PG 21412973.0
SF 24969112.0
SG 19944278.0
gb = df.groupby(['Position'])

print('Liczba grup:', gb.ngroups)
print(gb.groups.keys())

print(gb.get_group('C').head())
Liczba grup: 5
dict_keys(['C', 'PF', 'PG', 'SF', 'SG'])
               Name            Team  Number Position   Age Height  Weight  \
7      Kelly Olynyk  Boston Celtics    41.0        C  25.0    7-0   238.0   
10  Jared Sullinger  Boston Celtics     7.0        C  24.0    6-9   260.0   
14     Tyler Zeller  Boston Celtics    44.0        C  26.0    7-0   253.0   
23      Brook Lopez   Brooklyn Nets    11.0        C  28.0    7-0   275.0   
27       Henry Sims   Brooklyn Nets    14.0        C  26.0   6-10   248.0   

           College      Salary  
7          Gonzaga   2165160.0  
10      Ohio State   2569260.0  
14  North Carolina   2616975.0  
23        Stanford  19689000.0  
27      Georgetown    947276.0  

df.Height.str.split('-').str[0].astype('Int64') * 2.56
0      15.36
1      15.36
2      15.36
3      15.36
4      15.36
       ...  
453    15.36
454    15.36
455    17.92
456    17.92
457     <NA>
Name: Height, Length: 458, dtype: Float64

Pivot

Metoda pivot pozwala na stworzenie nowej ramki danych, gdzie indeks i nazwy kolumn są wartościami początkowej ranki danych.

_Przykład: zobaczmy na poniższą ramkę danych, która zawiera informacje o jakości tłumaczenia dla pary językowej hausa-angielski. Kolumna system zawiera nazwę systemu, kolumna metric - nazwę metryki, zaś kolumna score- wartość metryki. Chcemy przedstawić te dane w następujący sposób: jako klucz chcemy mieć nazwę systemu, zaś jako kolumny - metryki. Możemy wykorzystać do tego metodę pivot, gdzie musimy podać 3 argumenty:

  • index: nazwę kolumny, na podstawie której zostanie stworzony indeks;
  • columns: nazwa kolumny, które zawiera nazwy kolumn dla nowej ramki danych;
  • values: nazwa kolumny, która zawiera interesujące nas dane.
df = pd.read_csv('https://raw.githubusercontent.com/wmt-conference/wmt21-news-systems/main/scores/automatic-scores.tsv', sep='\t')
df = df[df.pair == 'ha-en']
df
pair system id is_constrained metric score
1214 ha-en NiuTrans 382 True bleu-all 16.512243
1215 ha-en NiuTrans 382 True chrf-all 44.724766
1216 ha-en NiuTrans 382 True bleu-A 16.512243
1217 ha-en NiuTrans 382 True chrf-A 44.724766
1218 ha-en Facebook-AI 181 False bleu-all 20.982704
1219 ha-en Facebook-AI 181 False chrf-all 48.653770
1220 ha-en Facebook-AI 181 False bleu-A 20.982704
1221 ha-en Facebook-AI 181 False chrf-A 48.653770
1222 ha-en TRANSSION 336 False bleu-all 18.834851
1223 ha-en TRANSSION 336 False chrf-all 47.238279
1224 ha-en TRANSSION 336 False bleu-A 18.834851
1225 ha-en TRANSSION 336 False chrf-A 47.238279
1226 ha-en AMU 628 True bleu-all 14.132845
1227 ha-en AMU 628 True chrf-all 41.256570
1228 ha-en AMU 628 True bleu-A 14.132845
1229 ha-en AMU 628 True chrf-A 41.256570
1230 ha-en P3AI 715 True bleu-all 17.793617
1231 ha-en P3AI 715 True chrf-all 46.307402
1232 ha-en P3AI 715 True bleu-A 17.793617
1233 ha-en P3AI 715 True chrf-A 46.307402
1234 ha-en Online-B 1356 False bleu-all 18.655658
1235 ha-en Online-B 1356 False chrf-all 46.658216
1236 ha-en Online-B 1356 False bleu-A 18.655658
1237 ha-en Online-B 1356 False chrf-A 46.658216
1238 ha-en TWB 1335 False bleu-all 12.326443
1239 ha-en TWB 1335 False chrf-all 40.282629
1240 ha-en TWB 1335 False bleu-A 12.326443
1241 ha-en TWB 1335 False chrf-A 40.282629
1242 ha-en ZMT 553 False bleu-all 18.837023
1243 ha-en ZMT 553 False chrf-all 47.231474
1244 ha-en ZMT 553 False bleu-A 18.837023
1245 ha-en ZMT 553 False chrf-A 47.231474
1246 ha-en Manifold 437 True bleu-all 16.943915
1247 ha-en Manifold 437 True chrf-all 45.638356
1248 ha-en Manifold 437 True bleu-A 16.943915
1249 ha-en Manifold 437 True chrf-A 45.638356
1250 ha-en Online-Y 1374 False bleu-all 13.898531
1251 ha-en Online-Y 1374 False chrf-all 44.842874
1252 ha-en Online-Y 1374 False bleu-A 13.898531
1253 ha-en Online-Y 1374 False chrf-A 44.842874
1254 ha-en HuaweiTSC 758 True bleu-all 17.492440
1255 ha-en HuaweiTSC 758 True chrf-all 46.795737
1256 ha-en HuaweiTSC 758 True bleu-A 17.492440
1257 ha-en HuaweiTSC 758 True chrf-A 46.795737
1258 ha-en MS-EgDC 896 True bleu-all 17.133350
1259 ha-en MS-EgDC 896 True chrf-all 45.266274
1260 ha-en MS-EgDC 896 True bleu-A 17.133350
1261 ha-en MS-EgDC 896 True chrf-A 45.266274
1262 ha-en GTCOM 1298 False bleu-all 17.794272
1263 ha-en GTCOM 1298 False chrf-all 46.714831
1264 ha-en GTCOM 1298 False bleu-A 17.794272
1265 ha-en GTCOM 1298 False chrf-A 46.714831
1266 ha-en UEdin 1149 True bleu-all 14.887836
1267 ha-en UEdin 1149 True chrf-all 42.247415
1268 ha-en UEdin 1149 True bleu-A 14.887836
1269 ha-en UEdin 1149 True chrf-A 42.247415
df.pivot(index='system', columns='metric', values='score')
metric bleu-A bleu-all chrf-A chrf-all
system
AMU 14.132845 14.132845 41.256570 41.256570
Facebook-AI 20.982704 20.982704 48.653770 48.653770
GTCOM 17.794272 17.794272 46.714831 46.714831
HuaweiTSC 17.492440 17.492440 46.795737 46.795737
MS-EgDC 17.133350 17.133350 45.266274 45.266274
Manifold 16.943915 16.943915 45.638356 45.638356
NiuTrans 16.512243 16.512243 44.724766 44.724766
Online-B 18.655658 18.655658 46.658216 46.658216
Online-Y 13.898531 13.898531 44.842874 44.842874
P3AI 17.793617 17.793617 46.307402 46.307402
TRANSSION 18.834851 18.834851 47.238279 47.238279
TWB 12.326443 12.326443 40.282629 40.282629
UEdin 14.887836 14.887836 42.247415 42.247415
ZMT 18.837023 18.837023 47.231474 47.231474

Zadanie

Dane tekstowe

pandas posiada udogodnienia do pracy z wartościami tekstowymi:

  • dostęp następuje przez atrybut str;
  • funkcje:
    • formatujące: lower(), upper();
    • wyrażenia regularne: contains(), match();
    • inne: split()
df = pd.read_csv('./titanic_train.tsv', sep='\t', index_col='PassengerId')

df.head()
Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
PassengerId
1 0 3 Braund\t Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
2 1 1 Cumings\t Mrs. John Bradley (Florence Briggs T... female 38.0 1 0 PC 17599 71.2833 C85 C
3 1 3 Heikkinen\t Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
4 1 1 Futrelle\t Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
5 0 3 Allen\t Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S
df.Name.str.upper()
PassengerId
1                               BRAUND\t MR. OWEN HARRIS
2      CUMINGS\t MRS. JOHN BRADLEY (FLORENCE BRIGGS T...
3                                HEIKKINEN\t MISS. LAINA
4          FUTRELLE\t MRS. JACQUES HEATH (LILY MAY PEEL)
5                              ALLEN\t MR. WILLIAM HENRY
                             ...                        
887                               MONTVILA\t REV. JUOZAS
888                        GRAHAM\t MISS. MARGARET EDITH
889            JOHNSTON\t MISS. CATHERINE HELEN "CARRIE"
890                               BEHR\t MR. KARL HOWELL
891                                 DOOLEY\t MR. PATRICK
Name: Name, Length: 891, dtype: object
print(df.Name.head())
df.Name.str.contains('Miss|Mrs').head()
PassengerId
1                             Braund\t Mr. Owen Harris
2    Cumings\t Mrs. John Bradley (Florence Briggs T...
3                              Heikkinen\t Miss. Laina
4        Futrelle\t Mrs. Jacques Heath (Lily May Peel)
5                            Allen\t Mr. William Henry
Name: Name, dtype: object
PassengerId
1    False
2     True
3     True
4     True
5    False
Name: Name, dtype: bool
df.Name.str.split('\t', expand=True)
0 1
PassengerId
1 Braund Mr. Owen Harris
2 Cumings Mrs. John Bradley (Florence Briggs Thayer)
3 Heikkinen Miss. Laina
4 Futrelle Mrs. Jacques Heath (Lily May Peel)
5 Allen Mr. William Henry
... ... ...
887 Montvila Rev. Juozas
888 Graham Miss. Margaret Edith
889 Johnston Miss. Catherine Helen "Carrie"
890 Behr Mr. Karl Howell
891 Dooley Mr. Patrick

891 rows × 2 columns

df.Name.str.split('\t')
PassengerId
1                             [Braund,  Mr. Owen Harris]
2      [Cumings,  Mrs. John Bradley (Florence Briggs ...
3                              [Heikkinen,  Miss. Laina]
4        [Futrelle,  Mrs. Jacques Heath (Lily May Peel)]
5                            [Allen,  Mr. William Henry]
                             ...                        
887                             [Montvila,  Rev. Juozas]
888                      [Graham,  Miss. Margaret Edith]
889          [Johnston,  Miss. Catherine Helen "Carrie"]
890                             [Behr,  Mr. Karl Howell]
891                               [Dooley,  Mr. Patrick]
Name: Name, Length: 891, dtype: object
df.Name.str.split('\t').str[1]
PassengerId
1                                  Mr. Owen Harris
2       Mrs. John Bradley (Florence Briggs Thayer)
3                                      Miss. Laina
4               Mrs. Jacques Heath (Lily May Peel)
5                                Mr. William Henry
                          ...                     
887                                    Rev. Juozas
888                           Miss. Margaret Edith
889                 Miss. Catherine Helen "Carrie"
890                                Mr. Karl Howell
891                                    Mr. Patrick
Name: Name, Length: 891, dtype: object
df.Name.str.split('\t').str[1].str.strip().str.split(' ').str[0]
PassengerId
1        Mr.
2       Mrs.
3      Miss.
4       Mrs.
5        Mr.
       ...  
887     Rev.
888    Miss.
889    Miss.
890      Mr.
891      Mr.
Name: Name, Length: 891, dtype: object

Zadanie

Zestaw nba.csv zawiera informaję o wysokości zawodników. Oblicz wzrost każdego z zawodników w systemie metrycznym przyjmując, że stop to 30.48 cm., a cal to 2.54 cm.