Logowanie pandas – pandas-log

TLDR: pandas-log umożliwia logowanie, przydatne zwłaszcza w długich łańcuchach operacji w pandas

Autorka zdjęcia: https://www.pexels.com/@rethaferguson

Pandas to wspaniała biblioteka, zwłaszcza dla osób, które miały doświadczenie w SQLu i chcą je wykorzystać, pracując z danymi w Pythonie. Pozwala na pracę na tabelarycznych danych w wygodny sposób.

Podobnie jednak jak w SQLu, czasami przychodzi moment, gdy podczas przetwarzania dzieje się coś dziwnego i nie do końca wiadomo, co poszło źle.

Załóżmy że pracujemy na tym samym datasecie graczy NBA z tego sezonu co w poprzednim wpisie i chcemy znaleźć drużynę, której pozycja centra jest najsilniej obsadzona.

import pandas as pd
from basketball_reference_web_scraper import client

players = pd.DataFrame(client.players_season_totals(season_end_year=2020))
players['team'] = players['team'].astype(str).str[5:].str.replace("_", " ")
players['positions'] = players['positions'].astype(str).str.extract("'([^']*)'")

columns = ['made_field_goals', 'attempted_field_goals', 'made_three_point_field_goals',
       'attempted_three_point_field_goals', 'made_free_throws',
       'attempted_free_throws', 'offensive_rebounds', 'defensive_rebounds',
       'assists', 'steals', 'blocks', 'turnovers', 'personal_fouls', 'points']

for stat in columns:
  players[stat+"_per_game"] = players[stat] / players["games_played"]

for stat in columns:
  players[stat+"_per_36"] = players[stat] / players["minutes_played"] * 36.

Mając przygotowany dataset, chcemy przeprowadzić kilka operacji:
– wybrać graczy, którzy są centrami
– odfiltrować graczy, którzy rozegrali mniej niż 15 spotkań (gracze, ze „zbyt małą próbką”, aby coś o nich powiedzieć)
– wybrać 30 graczy z największą liczbą punktów na 36 minut
– policzyć w których zespołach znajdują się tacy zawodnicy
– uszeregować zespoły według ich liczby
Na podstawie tych kryteriów przygotowujemy sobie kod:

teams = players.copy()\
               .query("positions=='center'")\
               .query("games_played>15")\
               .nlargest(30, "points_per_36")\
               .groupby("team")["points_per_36"]\
               .count()\
               .sort_values(ascending = False)

i… okazuje się, że tak przygotowany kod zwraca nam pusty zbiór. Możemy oczywiście rozbijać i analizować każdą z operacji, ale możemy wykorzystać pakiet pandas-log, który nam w tym wydatnie pomoże

!pip install pandas_log
import pandas_log

with pandas_log.enable():
    teams = players.copy()\
                   .query("positions=='center'")\
                   .query("games_played>15")\
                   .nlargest(30, "points_per_36")\
                   .groupby("team")["points_per_36"]\
                   .count()\
                   .sort_values(ascending = False)

Wywołanie przygotowanego przez nas polecenia „z” pandas_log.enable() pokaże nam co się tam właściwie stało:

1) query(expr="positions=='center'", inplace=False):
	Metadata:
	* Removed 589 rows (100.0%), 0 rows remaining.
	Execution Stats:
	* Execution time: Step Took 0.006072 seconds.

2) query(expr="games_played>15", inplace=False):
	Metadata:
	* No change in number of rows of input df.
	Execution Stats:
	* Execution time: Step Took 0.005762 seconds.
	Tips:
	* Number of rows didn't change, if you are working on the entire dataset you can remove this operation.

3) nlargest(n=30, columns="points_per_36", keep='first'):
	Metadata:
	* Picked 30 largest rows by columns (points_per_36).
	Execution Stats:
	* Execution time: Step Took 0.008734 seconds.
	Tips:
	* Number of rows didn't change, if you are working on the entire dataset you can remove this operation.

4) groupby(by="team", axis=0, level=None, as_index:bool=True, sort:bool=True, group_keys:bool=True, squeeze:bool=False, observed:bool=False):
	Metadata:
	* Grouping by team resulted in 0 groups like ,
	  and more.
	Execution Stats:
	* Execution time: Step Took 0.001026 seconds.

Jak widać, już w pierwszym poleceniu było coś nie tak (0 rows remaining). Po dokładniejszym przyjrzeniu się okazuje się, że wpisaliśmy nazwę pozycji używając małych liter.

Poprawienie tego błędu:

with pandas_log.enable():
    teams = players.copy()\
                   .query("positions=='CENTER'")\
                   .query("games_played>15")\
                   .nlargest(30, "points_per_36")\
                   .groupby("team")["points_per_36"]\
                   .count()\
                   .sort_values(ascending = False)

co w logach wygląda to już na poprawne:

1) query(expr="positions=='CENTER'", inplace=False):
	Metadata:
	* Removed 485 rows (82.34295415959252%), 104 rows remaining.
	Execution Stats:
	* Execution time: Step Took 0.007955 seconds.

2) query(expr="games_played>15", inplace=False):
	Metadata:
	* Removed 18 rows (17.307692307692307%), 86 rows remaining.
	Execution Stats:
	* Execution time: Step Took 0.007225 seconds.

3) nlargest(n=30, columns="points_per_36", keep='first'):
	Metadata:
	* Picked 30 largest rows by columns (points_per_36).
	Execution Stats:
	* Execution time: Step Took 0.006591 seconds.

4) groupby(by="team", axis=0, level=None, as_index:bool=True, sort:bool=True, group_keys:bool=True, squeeze:bool=False, observed:bool=False):
	Metadata:
	* Grouping by team resulted in 20 groups like 
		ATLANTA HAWKS,
		BOSTON CELTICS,
		CHARLOTTE HORNETS,
		DALLAS MAVERICKS,
		DENVER NUGGETS,
	  and more.
	Execution Stats:
	* Execution time: Step Took 0.001055 seconds.

Możemy więc zobaczyć upragnioną listę:

team count
0 PHOENIX SUNS 4
1 MINNESOTA TIMBERWOLVES 3
2 NEW ORLEANS PELICANS 2
3 CHARLOTTE HORNETS 2
4 LOS ANGELES CLIPPERS 2
5 MEMPHIS GRIZZLIES 2
6 WASHINGTON WIZARDS 2
7 ORLANDO MAGIC 1
8 NEW YORK KNICKS 1
9 PHILADELPHIA 76ERS 1
10 UTAH JAZZ 1
11 PORTLAND TRAIL BLAZERS 1
12 SAN ANTONIO SPURS 1
13 INDIANA PACERS 1
14 DETROIT PISTONS 1
15 DENVER NUGGETS 1
16 DALLAS MAVERICKS 1
17 TORONTO RAPTORS 1
18 BOSTON CELTICS 1
19 ATLANTA HAWKS 1

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *