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 MBObwohl 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
74Schauen 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 MBWie 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 . - , — .
