[PYTHON] Eine kleine Überprüfung von Pandas 1.0 und Dask

Hintergrund

Pandas 1.0.0 wurde am 29. Januar 2020 veröffentlicht! Geknister Ab dem 14.02.2020 ist es 1.0.1.

Persönlich denke ich, dass die folgenden Änderungen wichtige Punkte sind. --pandas original NA

Gut.

Bei der Analyse verwende ich häufig die folgenden Bibliotheken und Pandas zusammen.

Insbesondere möchte ich den Status der Unterstützung von Dask für Pandas 1.0 und andere detaillierte Verhaltensweisen klären. Die Version von dask ist 2.10.1 vom 14.02.2020.

In Bezug auf die Aufnahme denke ich, dass es kein Problem gibt, wenn dask es unterstützt. (Es gibt auch eine Zeit, in der die Wartezeit für die Verarbeitung von dask frei ist.)

スクリーンショット 2020-02-14 午前11.20.52.png

Was Sie interessiert

-Kann dask pandas.NA richtig benutzen? (Bezogen auf Version 1.0)

Tom Augspurger scheint Pandas 1.0 wie einen Dämon zu unterstützen, und ich habe bisher hohe Erwartungen. スクリーンショット 2020-02-14 午後2.26.08.png

Ergebnis

Für diejenigen, die nur das Ergebnis wissen wollen.

--Dask kann vier Regeln und Zeichenfolgenoperationen ausführen, selbst wenn es "pandas.NA" enthält. --dask kann nicht mit benutzerdefinierten Typen wie "Int64", "String" -Typ "set_index" sein

Aufbau der Vermessungsumgebung

Bereiten Sie vorerst eine saubere Verifizierungsumgebung vor. Das Betriebssystem ist macOS Catalina 10.15.2.

In Bezug auf die Python-Version legt pandas nur das Minimum fest, und dask scheint [python3.8-kompatibel] zu sagen (https://docs.dask.org/en/latest/changelog.html#id6), also Wenn es 3.7.4 ist, gibt es kein Problem.

Geben Sie für Abhängigkeiten [Mindestversionen für Abhängigkeiten] an (https://pandas.pydata.org/docs/whatsnew/v1.0.0.html#increased-minimum-versions-for-dependencies). Fastparquet und pyArrow können jedoch nicht auf Mac Problem existieren, daher sollte pyArrow nicht nur für den Fall enthalten sein. Ich benutze es nicht.

Überprüfungsarbeiten werden an jupyterlab durchgeführt.

pyenv virtualenv 3.7.4 pandas100
pyenv shell pandas100
pip install -r requirements.txt

requirements.txt


pandas==1.0.1
dask[complete]==2.10.1
fastparquet==0.3.3

jupyterlab==1.2.6

numpy==1.18.1
pytz==2019.3
python-dateutil==2.8.1
numexpr==2.7.1
beautifulsoup4==4.8.2
gcsfs==0.6.0
lxml==4.5.0
matplotlib==3.1.3
numba==0.48.0
openpyxl==3.0.3
pymysql==0.9.3
tables==3.6.1
s3fs==0.4.0
scipy==1.4.1
sqlalchemy==1.3.13
xarray==0.15.0
xlrd==1.2.0
xlsxwriter==1.2.7
xlwt==1.3.0

dask vs pandas1.0

Überprüfen Sie zunächst pd.NA.

Überprüfen Sie jeweils das Verhalten von pd.NA.

s=... type(s.loc[3])
pandas.Series([1,2,3,None], dtype='int') TypeError
pandas.Series([1,2,3,pandas.NA], dtype='int') TypeError
pandas.Series([1,2,3,None], dtype='Int64') pandas._libs.missing.NAType
pandas.Series([1,2,3,None], dtype='float') numpy.float64
pandas.Series([1,2,3,pandas.NA], dtype='float') TypeError
pandas.Series([1,2,3,None], dtype='Int64').astype('float') numpy.float64
pandas.Series(['a', 'b', 'c' ,None], dtype='string') pandas._libs.missing.NAType
pandas.Series(['a', 'b', 'c' ,None], dtype='object').astype('string') pandas._libs.missing.NAType
pandas.Series([True, False, True ,None], dtype='boolean') pandas._libs.missing.NAType
pandas.Series([1, 0, 1 ,None], dtype='float').astype('boolean') pandas._libs.missing.NAType
pandas.Series(pandas.to_datetime(['2020-01-01', '2020-01-02', '2020-01-03', None])) pandas._libs.tslibs.nattype.NaTType
pandas.Series(pandas.to_timedelta(['00:00:01', '00:00:02', '00:00:03', None])) pandas._libs.tslibs.nattype.NaTType
pandas.Series([object(), object(), object(), None], dtype='object') NoneType
pandas.Series([object(), object(), object(), pandas.NA], dtype='object') pandas.Series([object(), object(), object(), pandas.NA], dtype='object')

Zusammenfassung,

--dtype int wird nicht zu pandas.NA (TypeError wie es ist) --dtype Int64, string, boolean wird zu "pandas.NA". --dtype float wird zu numpy.NaN --dtype datetime64, timedelta64 wird zu NAT --dtype Objekt konvertiert None nicht automatisch in pandas.NA

Untersuchen Sie, was passiert, wenn dies "dask.dataframe.from_pandas" ist.

>>> import pandas
>>> import dask.dataframe

>>> df = pandas.DataFrame({'i': [1,2,3,4], 
...                        'i64': pandas.Series([1,2,3,None], dtype='Int64'), 
...                        's': pandas.Series(['a', 'b', 'c' ,None], dtype='string'), 
...                        'f': pandas.Series([1,2,3,None], dtype='Int64').astype('float')})

>>> ddf = dask.dataframe.from_pandas(df, npartitions=1)
>>> df
	i	i64	s	f
0	1	1	a	1.0
1	2	2	b	2.0
2	3	3	c	3.0
3	4	<NA>	<NA>	NaN

>>> ddf
Dask DataFrame Structure:
	i	i64	s	f
npartitions=1				
0	int64	Int64	string	float64
3	...	...	...	...

In der Tat ist "Int64" auch "Int64" auf demk. Gleiches gilt für string.

>>> #(Integer) Operation auf Int64
>>> df.i64 * 2
0       2
1       4
2       6
3    <NA>
Name: i64, dtype: Int64

>>> (ddf.i64 * 2).compute()
0       2
1       4
2       6
3    <NA>
Name: i64, dtype: Int64

Int64-> Int64-Verarbeitung funktioniert einwandfrei.

>>> #Berechnung (Floating Minority Score) für Int64
>>> df.i64 - df.f
0    0.0
1    0.0
2    0.0
3    NaN
dtype: float64

>>> (ddf.i64 - ddf.f).compute()
0    0.0
1    0.0
2    0.0
3    NaN
dtype: float64

Die Int64-> float64-Verarbeitung funktioniert ebenfalls ordnungsgemäß.

>>> # pandas.In der Int64-Spalte mit NA festlegen_index
>>> df.set_index('i64')
	i	s	f	i64_result	i64-f
i64					
1	1	a	1.0	2	0.0
2	2	b	2.0	4	0.0
3	3	c	3.0	6	0.0
NaN	4	<NA>	NaN	<NA>	NaN

>>> ddf.set_index('i64').compute()
TypeError: data type not understood

>>> # pandas.Was würde ohne NA passieren?
>>> ddf['i64_nonnull'] = ddf.i64.fillna(1)
... ddf.set_index('i64_nonnull').compute()
TypeError: data type not understood

Eh! Dask kann nicht "set_index" in der Spalte "Int64" setzen! Natürlich können Pandas.

>>> # pandas.In einer Zeichenfolgenspalte mit NA festlegen_index
>>> df.set_index('s')
	i	i64	f
s			
a	1	1	1.0
b	2	2	2.0
c	3	3	3.0
NaN	4	<NA>	NaN

>>> ddf.set_index('s').compute()
TypeError: Cannot perform reduction 'max' with string dtype

>>> # pandas.Was würde ohne NA passieren?
>>> ddf['s_nonnull'] = ddf.s.fillna('a')
... ddf.set_index('s_nonnull')
TypeError: Cannot perform reduction 'max' with string dtype

Ich kann auch keinen String machen. Dies kann noch nicht verwendet werden (in meiner Verwendung).

# .Probieren Sie die str-Funktion aus
>>> df.s.str.startswith('a')
0     True
1    False
2    False
3     <NA>
Name: s, dtype: boolean

>>> ddf.s.str.startswith('a').compute()
0     True
1    False
2    False
3     <NA>
Name: s, dtype: boolean

Hmmm, das funktioniert.

>>> # pandas.Filtern nach einer Booleschen Spalte, die NA enthält
>>> df[df.s.str.startswith('a')]
ValueError: cannot mask with array containing NA / NaN values

>>> # pandas.Ist NA schlecht?
>>> df['s_nonnull'] = df.s.fillna('a')
... df[df.s_nonnull.str.startswith('a')]
	i	i64	s	f	i64_nonnull	s_nonnull
0	1	1	a	1.0	1	a
3	4	<NA>	<NA>	NaN	1	a

>>> ddf[ddf.s.str.startswith('a')].compute()
ValueError: cannot mask with array containing NA / NaN values

>>> ddf['s_nonnull'] = ddf.s.fillna('a')
... ddf[ddf.s_nonnull.str.startswith('a')].compute()
	i	i64	s	f	i64_nonnull	s_nonnull
0	1	1	a	1.0	1	a
3	4	<NA>	<NA>	NaN	1	a
>>> ddf[ddf.s.str.startswith('a')].compute()

e! !! !! Kann nicht filtern, ob pandas.NA enthalten ist? Das ist nicht gut!

>>> #auf Meta anwenden='Int64'Versuchen Sie anzugeben
>>> ddf['i10'] = ddf.i.apply(lambda v: v * 10, meta='Int64')
>>> ddf
Dask DataFrame Structure:
	i	i64	s	f	i64_nonnull	s_nonnull	i10
npartitions=1							
0	int64	Int64	string	float64	Int64	string	int64
3	...	...	...	...	...	...	...

>>> #auf Meta anwenden='string'Versuchen Sie anzugeben
>>> ddf['s_double'] = ddf.s.apply(lambda v: v+v, meta='string')
Dask DataFrame Structure:
	i	i64	s	f	i64_nonnull	s_nonnull	i10	s_double
npartitions=1								
0	int64	Int64	string	float64	Int64	string	int64	object
3	...	...	...	...	...	...	...	...

>>> # astype('string')Versuchen
>>> ddf['s_double'] = ddf['s_double'].astype('string')
>>> ddf
Dask DataFrame Structure:
	i	i64	s	f	i64_nonnull	s_nonnull	i10	s_double
npartitions=1								
0	int64	Int64	string	float64	Int64	string	int64	string
3	...	...	...	...	...	...	...	...

Wenn Sie es mit meta = angeben, wird es nicht wiedergegeben? .. .. Es kann mit Astype wiederbelebt werden, aber es ist ein Ärger. .. ..

Ergebnis

dask vs pandas.Categorical

Um Categorical in Pandas zu untersuchen, verwenden wir diesmal die Methode mit Categorical Dtype. Die grundlegende Verwendung von Categorical Dtype ist

  1. Instanziieren Sie, indem Sie Kategorien angeben und bestellen
  2. Instanziieren Sie pandas.Series als dtype = CategoricalDtype-Instanz

Ich glaube, es ist. Unten Beispielcode

>>> #Erstellen Sie zunächst einen kategorialen D-Typ
>>> int_category = pandas.CategoricalDtype(categories=[1,2,3,4,5], 
...                                        ordered=True)
>>> int_category
CategoricalDtype(categories=[1, 2, 3, 4, 5], ordered=True)

>>> int_category.categories
Int64Index([1, 2, 3, 4, 5], dtype='int64')

>>> #Wie diese Pandas.Machen Sie eine Serie
>>> int_series = pandas.Series([1,2,3], dtype=int_category)
>>> int_series
0    1
1    2
2    3
dtype: category
Categories (5, int64): [1 < 2 < 3 < 4 < 5]

>>> #Zum Zeitpunkt der Generierung werden Werte, die nicht zur Kategorie gehören, in NaN konvertiert
>>> int_series = pandas.Series([1,2,3,6], dtype=int_category)
>>> int_series
0      1
1      2
2      3
3    NaN
dtype: category
Categories (5, int64): [1 < 2 < 3 < 4 < 5]

>>> #Werden Sie nach der Generation wütend
>>> int_series.loc[3] = 10
ValueError: Cannot setitem on a Categorical with a new category, set the categories first

Versuchen Sie als Nächstes, Categorical für dask zu verwenden.

>>> import pandas
>>> import dask.dataframe
>>> # pandas.Generieren Sie DataFrame
>>> df = pandas.DataFrame({'a': pandas.Series([1, 2, 3, 1, 2, 3], dtype=int_category), 
...                        'b': pandas.Series([1, 2, 3, 1, 2, 3], dtype='int64')})
>>> df
	a	b
0	1	1
1	2	2
2	3	3
3	1	1
4	2	2
5	3	3

>>> # dask.dataframe.In DataFrame konvertieren
>>> ddf = dask.dataframe.from_pandas(df, npartitions=1)
>>> ddf
Dask DataFrame Structure:
	a	b
npartitions=1		
0	category[known]	int64
5	...	...

Vorläufig konnte ich es so kategorisch machen, wie es kategorisch ist.

#Das Hinzufügen neuer Kategoriewerte ist bei Pandas legal
>>> df.loc[2, 'a'] = 30
ValueError: Cannot setitem on a Categorical with a new category, set the categories first

#In Dask kann es unabhängig von der Kategorie nicht in erster Linie zugewiesen werden
>>> ddf.loc['a', 3] = 10
TypeError: '_LocIndexer' object does not support item assignment

#Bei Pandas ist die Berechnung von Kategoriewerten ebenfalls legal
>>> df.a * 2
TypeError: unsupported operand type(s) for *: 'Categorical' and 'int'

#Auch mit dask ist die Berechnung von Kategoriewerten legal
>>> ddf.a * 2
TypeError: unsupported operand type(s) for *: 'Categorical' and 'int'

#Versuchen Sie, mit apply of dask als Meta anzugeben
>>> ddf['c'] = ddf.a.apply(lambda v: v, meta=int_category)
Dont know how to create metadata from category

#dask bewerben, meta='category'Wirst du dein Bestes geben, wenn du es tust?
>>> ddf['c'] = ddf.a.apply(lambda v: v, meta='category')
>>> ddf.dtypes
a    category
b       int64
c      object
dtype: object

>>> #Überprüfen Sie, ob es mit dem Inhalt übereinstimmt
>>> ddf.compute().dtypes
a    category
b       int64
c    category
dtype: object

>>> #versuchen Sie es mit Astype
>>> ddf['c'] = ddf.c.astype(int_category)
>>> ddf
Dask DataFrame Structure:
	a	b	c
npartitions=1			
0	category[known]	int64	category[known]
5	...	...	...

Das war's. Der Einschränkungsteil der Kategorie wird beibehalten, aber wenn Sie ".apply (meta =)" ausführen, ist die dtype-Verwaltung von dask fehlerhaft. Es ist möglich, es mit Astype wiederzubeleben, aber es ist ein Ärger. .. .. Ist es nicht möglich, nur Filter zu verwenden?

#Versuchen Sie zu aggregieren
>>> ddf.groupby('a').b.mean().compute()
a
1    1.0
2    2.0
3    3.0
4    NaN
5    NaN
Name: b, dtype: float64

#Wird der Typ nicht durch die Behandlung als Index unterbrochen?
Dask DataFrame Structure:
a	b
npartitions=1		
category[known]	float64
...	...
Dask Name: reset_index, 34 tasks

Hmmm, glauben Sie, dass es der Aggregation entspricht?

Ergebnis

to_parquet vs pandas1.0

>>> #Zuallererst Pandas.Generieren Sie DataFrame
>>> df = pandas.DataFrame(
    {
        'i64': pandas.Series([1, 2, 3,None], dtype='Int64'),
        'i64_nonnull': pandas.Series([1, 2, 3, 4], dtype='Int64'),
        's': pandas.Series(['a', 'b', 'c',None], dtype='string'),
        's_nonnull': pandas.Series(['a', 'b', 'c', 'd'], dtype='string'),
    }
)
>>> df
	i64	i64_nonnull	s	s_nonnull
0	1	1	a	a
1	2	2	b	b
2	3	3	c	c
3	<NA>	4	<NA>	d

>>> # dask.dataframe.In DataFrame konvertieren
>>> ddf = dask.dataframe.from_pandas(df, npartitions=1)
>>> ddf
Dask DataFrame Structure:
	i64	i64_nonnull	s	s_nonnull
npartitions=1				
0	Int64	Int64	string	string
3	...	...	...	...

Versuchen Sie vorerst to_parquet.

>>> ddf.to_parquet('test1', engine='fastparquet')
ValueError: Dont know how to convert data type: Int64

Ernsthaft. .. .. Ich habe es erwartet. .. .. Auch wenn Int64 nicht gut ist, ist möglicherweise eine Zeichenfolge möglich. .. ..

>>> ddf.to_parquet('test2', engine='fastparquet')
ValueError: Dont know how to convert data type: string

ich hab es nicht ausgearbeitet.

Ergebnis

--Int64 und String dürfen nicht to_parquet sein.

abschließend

Wie war das? Vielleicht hat niemand diesen Kommentar bis zum Ende gelesen. Sollte ich die Beiträge getrennt haben?

pandas 1.0 Ich hoffe, es hilft Menschen, die darüber nachdenken.

Bis bald.

Recommended Posts

Eine kleine Überprüfung von Pandas 1.0 und Dask
Eine kleine Nischenfunktion Einführung von Faiss
Ein grobes Verständnis von Python-Feuer und ein Memo
Verbinde viel Python oder und und
[Pandas_flavor] Fügen Sie eine Methode von Pandas DataFrame hinzu
Pandas: Ein sehr einfaches Beispiel für DataFrame.rolling ()
Ein Memorandum zum Studieren und Implementieren von Deep Learning
Berechnung der technischen Indikatoren durch TA-Lib und Pandas
Der Header ist falsch ausgerichtet mit read_csv () und read_table () von Pandas
[Python] Ein grobes Verständnis von Iterablen, Iteratoren und Generatoren
Berücksichtigung der Stärken und Schwächen von Python
Grundlegende Bedienung von Python Pandas Series und Dataframe (1)
Analyse von Finanzdaten durch Pandas und deren Visualisierung (2)
Analyse von Finanzdaten durch Pandas und deren Visualisierung (1)
Fügen Sie nach und nach eine Liste der Funktionen der Numpy-Bibliothek hinzu --a
Eine Geschichte über das Ausprobieren von pyenv, virtualenv und virtualenvwrapper
[PyTorch] Ein wenig Verständnis von CrossEntropyLoss mit mathematischen Formeln
Notieren Sie sich die Liste der grundlegenden Verwendungszwecke von Pandas
Ein schneller Vergleich der Testbibliotheken von Python und node.js.
Erstellen Sie einen Stapel von Bildern und blasen Sie sie mit ImageDataGenerator auf
[Python] [Gracenote Web API] Eine kleine Anpassung von Pygn
(Für mich) Flask_2 (Liste und für, erweitert und ein bisschen mehr)
Grundlegende Bedienung von Pandas
Pandas Index und Reindex
Grundlegende Bedienung von Pandas
Pandas resample und rollen
Pandas Mittelwertbildung und Auflistung
Fügen Sie nach und nach eine Liste der Funktionen der Numpy-Bibliothek hinzu --- b
Als Ergebnis der Montage und Abstimmung mit POH! Lite
Fügen Sie nach und nach eine Liste der Funktionen der Numpy-Bibliothek hinzu --c
Machen Sie die angegebene Anzahl von Sekunden zu Stunden, Minuten und Sekunden
Erkennen Sie mit Python Objekte einer bestimmten Farbe und Größe
Eine grobe Zusammenfassung der Unterschiede zwischen Windows und Linux
Python: Erstellen Sie ein Wörterbuch aus einer Liste von Schlüsseln und Werten
Ich habe ein wenig versucht, das Verhalten der Zip-Funktion
Pandas-Grundlagen für Anfänger ④ Umgang mit Datums- und Zeitangaben
Eine Sammlung von Methoden, die beim Aggregieren von Daten mit Pandas verwendet werden
Eine Geschichte über das Schreiben von AWS Lambda und ein wenig Abhängigkeit von den Standardwerten von Python-Argumenten