Wenn Sie die Pandas-Bibliothek zum Analysieren kleiner Datensätze verwenden, deren Größe 100 Megabyte nicht überschreitet, wird die Leistung selten zum Problem. Wenn es jedoch um die Untersuchung von Datensätzen geht, deren Größe mehrere Gigabyte erreichen kann, können Leistungsprobleme zu einer signifikanten Verlängerung der Datenanalysedauer führen und sogar dazu, dass aufgrund von Speichermangel keine Analyse durchgeführt werden kann.
Während Tools wie Spark große Datenmengen (von Hunderten von Gigabyte bis zu mehreren Terabyte) effizient verarbeiten können, benötigen Sie normalerweise recht leistungsstarke und teure Hardware, um ihre Funktionen voll auszuschöpfen. Und im Vergleich zu Pandas unterscheiden sie sich nicht in umfangreichen Werkzeugen für eine qualitativ hochwertige Reinigung, Forschung und Datenanalyse. Bei mittelgroßen Datensätzen ist es am besten, Pandas effizienter einzusetzen, anstatt zu anderen Tools zu wechseln.

In dem Material, das wir heute übersetzen, werden wir über die Funktionen der Arbeit mit Speicher bei der Verwendung von Pandas sprechen und darüber, wie der Speicherverbrauch einfach um fast 90% reduziert werden kann, indem einfach die entsprechenden Datentypen ausgewählt werden, die in den Spalten der Tabellendatenstrukturen des
DataFrame
.
Arbeiten mit Daten zu Baseballspielen
Wir werden mit Daten zu Baseballspielen der Major League arbeiten, die über 130 Jahre gesammelt und aus
Retrosheet entnommen wurden.
Ursprünglich wurden diese Daten als 127 CSV-Dateien dargestellt, aber wir haben sie mit
csvkit zu einem Datensatz
zusammengefasst und als erste Zeile der resultierenden Tabelle eine Zeile mit Spaltennamen hinzugefügt. Wenn Sie möchten, können Sie
unsere Version dieser Daten herunterladen und damit experimentieren, indem Sie den Artikel lesen.
Beginnen wir mit dem Importieren eines Datensatzes und werfen einen Blick auf die ersten fünf Zeilen. Sie finden sie in
dieser Tabelle im
.
import pandas as pd gl = pd.read_csv('game_logs.csv') gl.head()
Nachfolgend finden Sie Informationen zu den wichtigsten Spalten der Tabelle mit diesen Daten. Wenn Sie die Erklärungen für alle Spalten lesen möchten,
finden Sie hier ein Datenwörterbuch für den gesamten Datensatz.
date
- Datum des Spiels.v_name
- Der Name des Gastteams.v_league
- Liga der Gastmannschaft.h_name
- Der Name der Heimmannschaft.h_league
- Die Liga der Heimmannschaft.v_score
- Punkte von der Auswärtsmannschaft.h_score
- Punkte der Heimmannschaft.v_line_score
- Eine Zusammenfassung der Punkte des Gastteams, zum Beispiel - 010000(10)00
.h_line_score
- Eine Zusammenfassung der Punkte der Heimmannschaft, zum Beispiel - 010000(10)0X
.park_id
- Die Kennung des Feldes, auf dem das Spiel gespielt wurde.attendance
- Die Anzahl der Zuschauer.
Um allgemeine Informationen zum
DataFrame
Objekt zu erhalten, können Sie die
DataFrame.info () -Methode verwenden. Dank dieser Methode können Sie Informationen zur Größe eines Objekts, zu Datentypen und zur Speichernutzung erhalten.
Standardmäßig
DataFrame
ungefähre Informationen zur Speichernutzung durch den
DataFrame
. Wir sind an genauen Informationen interessiert, daher setzen wir den Parameter
memory_usage
auf
'deep'
.
gl.info(memory_usage='deep')
Hier sind die Informationen, die wir erhalten haben:
<class 'pandas.core.frame.DataFrame'> RangeIndex: 171907 entries, 0 to 171906 Columns: 161 entries, date to acquisition_info dtypes: float64(77), int64(6), object(78) memory usage: 861.6 MB
Wie sich herausstellte, haben wir 171.907 Zeilen und 161 Spalten. Die Pandas-Bibliothek hat Datentypen automatisch erkannt. Es gibt 83 Spalten mit numerischen Daten und 78 Spalten mit Objekten. Objektspalten werden zum Speichern von Zeichenfolgendaten verwendet, und in Fällen, in denen die Spalte Daten unterschiedlichen Typs enthält.
Um besser zu verstehen, wie Sie die Speichernutzung mit diesem
DataFrame
optimieren
DataFrame
, sprechen wir nun darüber, wie Pandas Daten im Speicher speichert.
Interne Ansicht eines DataFrame
Innerhalb von Pandas werden Datenspalten in Blöcken mit Werten des gleichen Typs gruppiert. Hier ist ein Beispiel dafür, wie die ersten 12 Spalten eines
DataFrame
in Pandas gespeichert werden.
Interne Darstellung verschiedener Datentypen in PandasMöglicherweise stellen Sie fest, dass Blöcke keine Spaltennameninformationen speichern. Dies liegt daran, dass die Blöcke zum Speichern der in den Tabellenzellen des
DataFrame
Objekts verfügbaren Werte optimiert sind. Die
BlockManager
Klasse ist dafür verantwortlich, Informationen über die Entsprechung zwischen den Zeilen- und Spaltenindizes des Datensatzes und darüber zu speichern, was in Blöcken desselben Datentyps gespeichert ist. Es spielt die Rolle einer API, die den Zugriff auf Basisdaten ermöglicht. Wenn wir Werte lesen, bearbeiten oder löschen, interagiert die
BlockManager
Klasse mit der
BlockManager
Klasse, um unsere Anforderungen in Funktions- und Methodenaufrufe zu konvertieren.
Jeder Datentyp verfügt über eine spezielle Klasse im Modul
pandas.core.internals
. Pandas verwendet beispielsweise die
ObjectBlock
Klasse, um Blöcke mit Zeichenfolgenspalten
FloatBlock
, und die
FloatBlock
Klasse, um Blöcke mit Spalten darzustellen,
FloatBlock
Gleitkommazahlen enthalten. Bei Blöcken, die numerische Werte darstellen, die wie Ganzzahlen oder Gleitkommazahlen aussehen, kombiniert pandas die Spalten und speichert sie als
ndarray
Datenstruktur der NumPy-Bibliothek. Diese Datenstruktur basiert auf dem Array C, die Werte werden in einem kontinuierlichen Speicherblock gespeichert. Dank dieses Datenspeicherungsschemas ist der Zugriff auf Datenfragmente sehr schnell.
Da Daten unterschiedlicher Typen separat gespeichert werden, untersuchen wir die Speichernutzung verschiedener Datentypen. Beginnen wir mit der durchschnittlichen Speichernutzung für verschiedene Datentypen.
for dtype in ['float','int','object']: selected_dtype = gl.select_dtypes(include=[dtype]) mean_usage_b = selected_dtype.memory_usage(deep=True).mean() mean_usage_mb = mean_usage_b / 1024 ** 2 print("Average memory usage for {} columns: {:03.2f} MB".format(dtype,mean_usage_mb))
Infolgedessen stellt sich heraus, dass die durchschnittlichen Indikatoren für die Speichernutzung für Daten verschiedener Typen folgendermaßen aussehen:
Average memory usage for float columns: 1.29 MB Average memory usage for int columns: 1.12 MB Average memory usage for object columns: 9.53 MB
Diese Informationen machen uns verständlich, dass der größte Teil des Speichers für 78 Spalten zum Speichern von Objektwerten verwendet wird. Wir werden später mehr darüber sprechen, aber jetzt überlegen wir, ob wir die Speichernutzung mit Spalten verbessern können, in denen numerische Daten gespeichert sind.
Untertypen
Wie bereits erwähnt, stellen Pandas numerische Werte als
ndarray
NumPy-Datenstrukturen dar und speichern sie in zusammenhängenden Speicherblöcken. Mit diesem Datenspeichermodell können Sie Speicherplatz sparen und schnell auf Werte zugreifen. Da Pandas jeden Wert desselben Typs mit derselben Anzahl von Bytes darstellen und
ndarray
Strukturen Informationen über die Anzahl der Werte speichern, können Pandas schnell und genau Informationen über den Speicherbedarf von Spalten anzeigen, in denen numerische Werte gespeichert sind.
Viele Datentypen in Pandas haben viele Untertypen, die weniger Bytes verwenden können, um jeden Wert darzustellen. Der
float
Typ hat beispielsweise die Untertypen
float16
,
float32
und
float64
. Die Zahl im Typnamen gibt die Anzahl der Bits an, die der Subtyp zur Darstellung der Werte verwendet. Beispielsweise werden in den gerade aufgelisteten Untertypen 2, 4, 8 und 16 Bytes jeweils zur Datenspeicherung verwendet. Die folgende Tabelle zeigt die Untertypen der am häufigsten verwendeten Datentypen in Pandas.
Speichernutzung, Bytes
| Gleitkommazahl
| Ganze Zahl
| Ganzzahl ohne Vorzeichen
| Datum und Uhrzeit
| Boolescher Wert
| Objekt
|
1
| | int8
| uint8
| | Bool
| |
2
| float16
| int16
| uint16
| | | |
4
| float32
| int32
| uint32
| | | |
8
| float64
| int64
| uint64
| datetime64
| | |
Variable Speicherkapazität
| | | | | | Objekt
|
Ein Wert vom Typ
int8
verwendet 1 Byte (8 Bit) zum Speichern einer Zahl und kann 256 Binärwerte (2 bis 8 Potenzen) darstellen. Dies bedeutet, dass dieser Subtyp zum Speichern von Werten im Bereich von -128 bis 127 (einschließlich 0) verwendet werden kann.
Mit der Methode
numpy.iinfo()
können Sie die für die Speicherung geeigneten Mindest- und Höchstwerte für jeden Ganzzahl-Subtyp
numpy.iinfo()
. Betrachten Sie ein Beispiel:
import numpy as np int_types = ["uint8", "int8", "int16"] for it in int_types: print(np.iinfo(it))
Durch Ausführen dieses Codes erhalten wir die folgenden Daten:
Machine parameters for uint8 --------------------------------------------------------------- min = 0 max = 255 --------------------------------------------------------------- Machine parameters for int8 --------------------------------------------------------------- min = -128 max = 127 --------------------------------------------------------------- Machine parameters for int16 --------------------------------------------------------------- min = -32768 max = 32767 ---------------------------------------------------------------
Hier können Sie auf den Unterschied zwischen den Typen
uint
(vorzeichenlose Ganzzahl) und
int
(vorzeichenbehaftete Ganzzahl)
uint
. Beide Typen haben die gleiche Kapazität, aber wenn nur positive Werte in Spalten gespeichert werden, ermöglichen vorzeichenlose Typen eine effizientere Speichernutzung.
Optimierung der Speicherung numerischer Daten mithilfe von Untertypen
Mit der Funktion
pd.to_numeric()
können numerische Typen
pd.to_numeric()
werden. Um ganzzahlige Spalten auszuwählen, verwenden wir die Methode
DataFrame.select_dtypes()
. Anschließend optimieren wir sie und vergleichen die Speichernutzung vor und nach der Optimierung.
# , , # , . def mem_usage(pandas_obj): if isinstance(pandas_obj,pd.DataFrame): usage_b = pandas_obj.memory_usage(deep=True).sum() else: # , DataFrame, Series usage_b = pandas_obj.memory_usage(deep=True) usage_mb = usage_b / 1024 ** 2 # return "{:03.2f} MB".format(usage_mb) gl_int = gl.select_dtypes(include=['int']) converted_int = gl_int.apply(pd.to_numeric,downcast='unsigned') print(mem_usage(gl_int)) print(mem_usage(converted_int)) compare_ints = pd.concat([gl_int.dtypes,converted_int.dtypes],axis=1) compare_ints.columns = ['before','after'] compare_ints.apply(pd.Series.value_counts)
Hier ist das Ergebnis einer Studie zum Speicherverbrauch:
7.87 MB
1.48 MB
| Zu
| Nachher
|
uint8
| NaN
| 5.0
|
uint32
| NaN
| 1.0
|
int64
| 6.0
| NaN
|
Infolgedessen ist ein Rückgang der Speichernutzung von 7,9 auf 1,5 Megabyte zu verzeichnen, dh wir haben den Speicherverbrauch um mehr als 80% reduziert. Die Gesamtauswirkung dieser Optimierung auf den ursprünglichen
DataFrame
ist jedoch nicht besonders stark, da nur sehr wenige ganzzahlige Spalten vorhanden sind.
Machen wir dasselbe mit Spalten, die Gleitkommazahlen enthalten.
gl_float = gl.select_dtypes(include=['float']) converted_float = gl_float.apply(pd.to_numeric,downcast='float') print(mem_usage(gl_float)) print(mem_usage(converted_float)) compare_floats = pd.concat([gl_float.dtypes,converted_float.dtypes],axis=1) compare_floats.columns = ['before','after'] compare_floats.apply(pd.Series.value_counts)
Das Ergebnis ist folgendes:
100.99 MB
50.49 MB
| Zu
| Nachher
|
float32
| NaN
| 77,0
|
float64
| 77,0
| NaN
|
Infolgedessen speichern alle Spalten, in denen Gleitkommazahlen mit dem Datentyp
float64
jetzt Nummern vom Typ
float32
, wodurch die Speichernutzung um 50% reduziert wurde.
Erstellen Sie eine Kopie des ursprünglichen
DataFrame
, verwenden Sie diese optimierten numerischen Spalten anstelle der ursprünglich darin enthaltenen und
DataFrame
Sie die gesamte Speichernutzung nach der Optimierung.
optimized_gl = gl.copy() optimized_gl[converted_int.columns] = converted_int optimized_gl[converted_float.columns] = converted_float print(mem_usage(gl)) print(mem_usage(optimized_gl))
Folgendes haben wir:
861.57 MB
804.69 MB
Obwohl wir den Speicherverbrauch durch Spalten, in denen numerische Daten gespeichert sind, im gesamten
DataFrame
erheblich reduziert haben, verringerte sich der Speicherverbrauch im Allgemeinen nur um 7%. Die Optimierung der Speicherung von Objekttypen kann zu einer viel ernsthafteren Verbesserung einer Situation führen.
Bevor wir diese Optimierung durchführen, werden wir uns genauer ansehen, wie Zeichenfolgen in Pandas gespeichert werden, und dies mit der Art und Weise vergleichen, wie Zahlen hier gespeichert werden.
Vergleich der Mechanismen zum Speichern von Zahlen und Zeichenfolgen
Der
object
repräsentiert Werte unter Verwendung von Python-String-Objekten. Dies liegt teilweise daran, dass NumPy die Darstellung fehlender Zeichenfolgenwerte nicht unterstützt. Da Python eine hochinterpretierte Sprache ist, bietet es dem Programmierer keine Tools zur Feinabstimmung der Speicherung von Daten im Speicher.
Diese Einschränkung führt dazu, dass Zeichenfolgen nicht in zusammenhängenden Speicherfragmenten gespeichert werden, sondern dass ihre Darstellung im Speicher fragmentiert ist. Dies führt zu einer Erhöhung des Speicherverbrauchs und zu einer Verlangsamung der Arbeitsgeschwindigkeit mit Zeichenfolgenwerten. Tatsächlich ist jedes Element in der Spalte, in dem der Objektdatentyp gespeichert ist, ein Zeiger, der die „Adresse“ enthält, an der sich der tatsächliche Wert im Speicher befindet.
Das folgende Diagramm basiert auf
diesem Material und vergleicht das Speichern numerischer Daten mit NumPy-Datentypen und das Speichern von Zeichenfolgen mit den in Python integrierten Datentypen.
Speichern von numerischen Daten und ZeichenfolgendatenHier können Sie sich daran erinnern, dass in einer der obigen Tabellen gezeigt wurde, dass eine variable Speichermenge zum Speichern von Daten von Objekttypen verwendet wird. Obwohl jeder Zeiger 1 Byte Speicher belegt, belegt jeder bestimmte Zeichenfolgenwert dieselbe Speichermenge, die zum Speichern einer einzelnen Zeichenfolge in Python verwendet werden würde. Um dies zu bestätigen, verwenden wir die Methode
sys.getsizeof()
. Schauen Sie sich zuerst die einzelnen Zeilen und dann das
Series
pandas-Objekt an, in dem die Zeichenfolgendaten gespeichert sind.
Also untersuchen wir zuerst die üblichen Zeilen:
from sys import getsizeof s1 = 'working out' s2 = 'memory usage for' s3 = 'strings in python is fun!' s4 = 'strings in python is fun!' for s in [s1, s2, s3, s4]: print(getsizeof(s))
Hier sehen die Speichernutzungsdaten folgendermaßen aus:
60
65
74
74
Schauen wir uns nun an, wie die Verwendung von Zeichenfolgen im
Series
Objekt aussieht:
obj_series = pd.Series(['working out', 'memory usage for', 'strings in python is fun!', 'strings in python is fun!']) obj_series.apply(getsizeof)
Hier bekommen wir folgendes:
0 60 1 65 2 74 3 74 dtype: int64
Hier können Sie sehen, dass die Größen der in
Series
Pandas-Objekten gespeicherten Linien ihren Größen ähnlich sind, wenn Sie mit ihnen in Python arbeiten und sie als separate Entitäten darstellen.
Optimierung der Speicherung von Objekttypdaten unter Verwendung kategorialer Variablen
Kategoriale Variablen erschienen in Pandas Version 0.15. Der entsprechende Typ,
category
, verwendet in seinen internen Mechanismen ganzzahlige Werte anstelle der ursprünglichen Werte, die in den Tabellenspalten gespeichert sind. Pandas verwendet ein separates Wörterbuch, das die Entsprechung von Ganzzahl- und Anfangswerten festlegt. Dieser Ansatz ist nützlich, wenn die Spalten Werte aus einer begrenzten Menge enthalten. Wenn die in einer Spalte gespeicherten Daten in den
category
konvertiert werden, verwendet pandas den Untertyp
int
, der die effizienteste Speichernutzung ermöglicht und alle in der Spalte gefundenen eindeutigen Werte darstellen kann.
Quelldaten und kategoriale Daten unter Verwendung des Untertyps int8Um genau zu verstehen, wo wir kategoriale Daten verwenden können, um den Speicherverbrauch zu reduzieren, ermitteln wir die Anzahl der eindeutigen Werte in den Spalten, in denen die Werte der Objekttypen gespeichert sind:
gl_obj = gl.select_dtypes(include=['object']).copy() gl_obj.describe()
Was wir in
dieser Tabelle haben, finden Sie auf dem Blatt
.
In der Spalte
day_of_week
, dem Wochentag, an dem das Spiel gespielt wurde, befinden sich beispielsweise 171907 Werte. Unter ihnen sind nur 7 einzigartig. Insgesamt reicht ein Blick auf diesen Bericht aus, um zu verstehen, dass in vielen Spalten einige eindeutige Werte verwendet werden, um die Daten von ungefähr 172.000 Spielen darzustellen.
Bevor wir eine vollständige Optimierung durchführen, wählen wir eine Spalte aus, in der Objektdaten gespeichert sind, mindestens
day_of_week
, und sehen, was im Programm passiert, wenn es in einen kategorialen Typ konvertiert wird.
Wie bereits erwähnt, enthält diese Spalte nur 7 eindeutige Werte. Um es in einen kategorialen Typ zu konvertieren, verwenden wir die Methode
.astype()
.
dow = gl_obj.day_of_week print(dow.head()) dow_cat = dow.astype('category') print(dow_cat.head())
Folgendes haben wir:
0 Thu 1 Fri 2 Sat 3 Mon 4 Tue Name: day_of_week, dtype: object 0 Thu 1 Fri 2 Sat 3 Mon 4 Tue Name: day_of_week, dtype: category Categories (7, object): [Fri, Mon, Sat, Sun, Thu, Tue, Wed]
Wie Sie sehen können, sehen die darin gespeicherten Daten wie zuvor aus, obwohl sich der Typ der Spalte geändert hat. Schauen wir uns nun an, was im Programm passiert.
Im folgenden Code verwenden wir das Attribut
Series.cat.codes
, um herauszufinden, welche ganzzahligen Werte der
category
für jeden Wochentag verwendet:
dow_cat.head().cat.codes
Es gelingt uns Folgendes herauszufinden:
0 4 1 0 2 2 3 1 4 5 dtype: int8
Hier können Sie sehen, dass jedem eindeutigen Wert ein ganzzahliger Wert zugewiesen ist und dass die Spalte jetzt vom Typ
int8
. Es fehlen keine Werte, aber wenn dies der Fall wäre, würde -1 verwendet, um solche Werte anzuzeigen.
Vergleichen wir nun den Speicherverbrauch vor und nach der Konvertierung der Spalte
day_of_week
in den
category
.
print(mem_usage(dow)) print(mem_usage(dow_cat))
Hier ist das Ergebnis:
9.84 MB
0.16 MB
Wie Sie sehen, wurden zunächst 9,84 Megabyte Speicher verbraucht und nach der Optimierung nur 0,16 Megabyte, was einer 98% igen Verbesserung dieses Indikators entspricht. Bitte beachten Sie, dass die Arbeit mit dieser Spalte wahrscheinlich eines der rentabelsten Optimierungsszenarien darstellt, wenn in einer Spalte mit ungefähr 172.000 Elementen nur 7 eindeutige Werte verwendet werden.
Obwohl die Idee, alle Spalten in diesen Datentyp zu konvertieren, attraktiv erscheint, sollten Sie zuvor die negativen Nebenwirkungen einer solchen Konvertierung berücksichtigen. Das schwerwiegendste Minus dieser Transformation ist also die Unmöglichkeit, arithmetische Operationen an kategorialen Daten durchzuführen. Dies gilt auch für gewöhnliche arithmetische Operationen und die Verwendung von Methoden wie
Series.min()
und
Series.max()
ohne zuvor die Daten in einen reellen
Series.max()
zu konvertieren.
Wir sollten die Verwendung des
category
auf hauptsächlich Spalten beschränken, in denen Daten vom Typ
object
gespeichert sind, in denen weniger als 50% der Werte eindeutig sind. Wenn alle Werte in einer Spalte eindeutig sind, erhöht die Verwendung des
category
die Speichernutzung. Dies liegt daran, dass Sie im Speicher zusätzlich zu den numerischen Kategoriecodes die ursprünglichen Zeichenfolgenwerte speichern müssen. Details zu Einschränkungen des
category
finden Sie in der Pandas-
Dokumentation .
Erstellen Sie eine Schleife, die alle Spalten durchläuft, in denen Daten vom Typ
object
gespeichert sind, ermittelt, ob die Anzahl der eindeutigen Werte in den Spalten 50% überschreitet, und konvertiert sie in die
category
.
converted_obj = pd.DataFrame() for col in gl_obj.columns: num_unique_values = len(gl_obj[col].unique()) num_total_values = len(gl_obj[col]) if num_unique_values / num_total_values < 0.5: converted_obj.loc[:,col] = gl_obj[col].astype('category') else: converted_obj.loc[:,col] = gl_obj[col]
Vergleichen Sie nun, was nach der Optimierung passiert ist, mit dem, was vorher passiert ist:
print(mem_usage(gl_obj)) print(mem_usage(converted_obj)) compare_obj = pd.concat([gl_obj.dtypes,converted_obj.dtypes],axis=1) compare_obj.columns = ['before','after'] compare_obj.apply(pd.Series.value_counts)
Wir bekommen folgendes:
752.72 MB
51.67 MB
| Zu
| Nachher
|
Objekt
| 78,0
| NaN
|
Kategorie
| NaN
| 78,0
|
category
, , , , , , , , .
, , ,
object
, 752 52 , 93%. , . , , , , 891 .
optimized_gl[converted_obj.columns] = converted_obj mem_usage(optimized_gl)
:
'103.64 MB'
. - . ,
datetime
, , , .
date = optimized_gl.date print(mem_usage(date)) date.head()
:
0.66 MB
:
0 18710504 1 18710505 2 18710506 3 18710508 4 18710509 Name: date, dtype: uint32
,
uint32
. -
datetime
, 64 .
datetime
, , , .
to_datetime()
,
format
,
YYYY-MM-DD
.
optimized_gl['date'] = pd.to_datetime(date,format='%Y%m%d') print(mem_usage(optimized_gl)) optimized_gl.date.head()
:
104.29 MB
:
0 1871-05-04 1 1871-05-05 2 1871-05-06 3 1871-05-08 4 1871-05-09 Name: date, dtype: datetime64[ns]
DataFrame
. , , , , , , , . , . , , , . , ,
DataFrame
, .
, .
pandas.read_csv() , . ,
dtype
, , , , — NumPy.
, , . , .
dtypes = optimized_gl.drop('date',axis=1).dtypes dtypes_col = dtypes.index dtypes_type = [i.name for i in dtypes.values] column_types = dict(zip(dtypes_col, dtypes_type)) # 161 , # 10 / # preview = first2pairs = {key:value for key,value in list(column_types.items())[:10]} import pprint pp = pp = pprint.PrettyPrinter(indent=4) pp.pprint(preview) : { 'acquisition_info': 'category', 'h_caught_stealing': 'float32', 'h_player_1_name': 'category', 'h_player_9_name': 'category', 'v_assists': 'float32', 'v_first_catcher_interference': 'float32', 'v_grounded_into_double': 'float32', 'v_player_1_id': 'category', 'v_player_3_id': 'category', 'v_player_5_id': 'category'}
, , .
- :
read_and_optimized = pd.read_csv('game_logs.csv',dtype=column_types,parse_dates=['date'],infer_datetime_format=True) print(mem_usage(read_and_optimized)) read_and_optimized.head()
:
104.28 MB
,
.
,
, , , . pandas 861.6 104.28 , 88% .
, , , . .
optimized_gl['year'] = optimized_gl.date.dt.year games_per_day = optimized_gl.pivot_table(index='year',columns='day_of_week',values='date',aggfunc=len) games_per_day = games_per_day.divide(games_per_day.sum(axis=1),axis=0) ax = games_per_day.plot(kind='area',stacked='true') ax.legend(loc='upper right') ax.set_ylim(0,1) plt.show()
,, 1920- , , 50 , .
, , , 50 , .
, .
game_lengths = optimized_gl.pivot_table(index='year', values='length_minutes') game_lengths.reset_index().plot.scatter('year','length_minutes') plt.show()
, 1940- .
Zusammenfassung
pandas, ,
DataFrame
, 90%. :
, , , , , , pandas, , .
Liebe Leser! eugene_bb . - , — .
