Categorías
Python

Limpiador de escritura Python código con pylint

 

Tabla de Contenidos

  • 1. configurar las opciones y configuración en intérprete de inicio
  • 2. Hacer Estructuras de datos juguete con pandas’ Módulo de pruebas
  • 3. Aproveche los métodos de acceso
  • 4. Cree un DatetimeIndex del componente Columnas
  • 5. uso de datos categóricos para ahorrar en tiempo y espacio
  • 6. Introspect GroupBy objetos a través de la iteración
  • 7. Usar este truco Mapeo de adhesión Agrupación
  • 8. Comprender la forma pandas Usos operadores booleanos
  • 9. carga de datos desde el portapapeles
  • 10. Escribe pandas objetos directamente en formato comprimido
  • desea agregar a esta lista? Háganos saber

Mira ahora Este tutorial tiene un vídeo relacionado curso creado por el equipo del Real Python. Mira que junto con el tutorial escrito para profundizar su comprensión: idiomático pandas: trucos y características que no puede saber

pandas es una biblioteca fundamental para el análisis, procesamiento de datos, y la ciencia de datos. Es un proyecto enorme con toneladas de opcionalidad y profundidad.

Este tutorial cubrirá algunas capacidades menos utilizadas pero idiomáticas pandas que se prestan su código de una mejor legibilidad, versatilidad y velocidad, a la la listicle Buzzfeed.

si se siente cómodo con los conceptos básicos de la biblioteca de Python pandas, esperamos que pueda encontrar un truco o dos en este artículo que no ha tropezado con anterioridad. (Si usted está empezando a cabo con la biblioteca, a 10 minutos de las pandas es un lugar bueno para comenzar.)

Nota : Los ejemplos de este artículo se prueban con las pandas versión 0.23.2 y Python 3.6.6. Sin embargo, también deben ser válidos en las versiones anteriores.

1. Opciones de configuración y ajustes en el intérprete de inicio

Puede haber ejecutado a través del sistema y la configuración de las opciones ricas pandas’ antes.

Es un gran ahorro de productividad para establecer las opciones personalizadas pandas en el arranque intérprete, especialmente si trabaja en un entorno de programación. Puede utilizar pd.set_option () para configurar el contenido de su corazón con un pitón o archivo IPython inicio.

Las opciones utilizan un punto de notación como pd.set_option ( ‘display.max_colwidth’, 25), que se presta bien a un diccionario anidada de opciones:

import pandas as pd

def start():
options = {
'display': {
'max_columns': None,
'max_colwidth': 25,
'expand_frame_repr': False, # Don't wrap to multiple pages
'max_rows': 14,
'max_seq_items': 50, # Max length of printed sequence
'precision': 4,
'show_dimensions': False
},
'mode': {
'chained_assignment': None # Controls SettingWithCopyWarning
}
}

for category, option in options.items():
for op, value in option.items():
pd.set_option(f'{category}.{op}', value) # Python 3.6+

if __name__ == '__main__':
start()
del start # Clean up namespace in the interpreter

Si inicia una sesión intérprete, verá que todo en el script de arranque ha sido ejecutada, y pandas se importa de forma automática con su conjunto de opciones: el uso de

>>> pd.__name__
'pandas'
>>> pd.get_option('display.max_rows')
14

Let algunos datos sobre el abulón organizada por la UCI Machine Learning repositorio para demostrar el formato que se encuentra en el archivo de inicio. Los datos truncará en 14 filas con 4 dígitos de precisión para objetos flotantes:

>>> url = ('https://archive.ics.uci.edu/ml/'
... 'machine-learning-databases/abalone/abalone.data')
>>> cols = ['sex', 'length', 'diam', 'height', 'weight', 'rings']
>>> abalone = pd.read_csv(url, usecols=[0, 1, 2, 3, 4, 8], names=cols)

>>> abalone
sex length diam height weight rings
0 M 0.455 0.365 0.095 0.5140 15
1 M 0.350 0.265 0.090 0.2255 7
2 F 0.530 0.420 0.135 0.6770 9
3 M 0.440 0.365 0.125 0.5160 10
4 I 0.330 0.255 0.080 0.2050 7
5 I 0.425 0.300 0.095 0.3515 8
6 F 0.530 0.415 0.150 0.7775 20
# ...
4170 M 0.550 0.430 0.130 0.8395 10
4171 M 0.560 0.430 0.155 0.8675 8
4172 F 0.565 0.450 0.165 0.8870 11
4173 M 0.590 0.440 0.135 0.9660 10
4174 M 0.600 0.475 0.205 1.1760 9
4175 F 0.625 0.485 0.150 1.0945 10
4176 M 0.710 0.555 0.195 1.9485 12

verá este conjunto de datos pop-up en otros ejemplos más adelante también.

2. Hacer Estructuras de Datos juguete con pandas’ manera Módulo de pruebas

sumergidas en medio de las pandas’ módulo de pruebas son una serie de funciones útiles para la construcción rápida de tramas de datos cuasi-realista de la serie y:

>>> import pandas.util.testing as tm
>>> tm.N, tm.K = 15, 3 # Module-level default rows/columns

>>> import numpy as np
>>> np.random.seed(444)

>>> tm.makeTimeDataFrame(freq='M').head()
A B C
2000-01-31 0.3574 -0.8804 0.2669
2000-02-29 0.3775 0.1526 -0.4803
2000-03-31 1.3823 0.2503 0.3008
2000-04-30 1.1755 0.0785 -0.1791
2000-05-31 -0.9393 -0.9039 1.1837

>>> tm.makeDataFrame().head()
A B C
nTLGGTiRHF -0.6228 0.6459 0.1251
WPBRn9jtsR -0.3187 -0.8091 1.1501
7B3wWfvuDA -1.9872 -1.0795 0.2987
yJ0BTjehH1 0.8802 0.7403 -1.2154
0luaYUYvy1 -0.9320 1.2912 -0.2907

Hay alrededor de 30 de estos, y se puede ver la lista completa llamando dir () en el objeto módulo. Éstos son algunos de ellos:

>>> [i for i in dir(tm) if i.startswith('make')]
['makeBoolIndex',
'makeCategoricalIndex',
'makeCustomDataframe',
'makeCustomIndex',
# ...,
'makeTimeSeries',
'makeTimedeltaIndex',
'makeUIntIndex',
'makeUnicodeIndex']

Estos pueden ser útiles para la evaluación comparativa, poniendo a prueba las afirmaciones, y experimentando con métodos pandas que están menos familiarizados con.

3. Aproveche los métodos de acceso

Tal vez usted ha escuchado del término de acceso , que es algo así como un captador (aunque captadores y definidores se utilizan con poca frecuencia en Python). Para nuestros propósitos, se puede pensar en un pandas de acceso como una propiedad que sirve como interfaz para métodos adicionales.

pandas serie tiene tres de ellos:

>>> pd.Series._accessors
{'cat', 'str', 'dt'}

Sí, esa definición anterior es un bocado, así que vamos a echar un vistazo a algunos ejemplos antes de discutir los elementos internos.

.cat es para los datos categóricos, .str es para datos de cadena (objeto), y .dt es para datetime-como de datos. Vamos a empezar con .str: imagine que usted tiene algunos datos de la ciudad / prima / Estado Código postal como un único campo dentro de una serie pandas. métodos de cadena

pandas son vectorizados, es decir, que operan en toda la matriz sin una explícita para-loop:

>>> addr = pd.Series([
... 'Washington, D.C. 20003',
... 'Brooklyn, NY 11211-1755',
... 'Omaha, NE 68154',
... 'Pittsburgh, PA 15211'
... ])

>>> addr.str.upper()
0 WASHINGTON, D.C. 20003
1 BROOKLYN, NY 11211-1755
2 OMAHA, NE 68154
3 PITTSBURGH, PA 15211
dtype: object

>>> addr.str.count(r'\d') # 5 or 9-digit zip?
0 5
1 9
2 5
3 5
dtype: int64

Para un ejemplo más complicado, digamos que desea separar las tres ciudades / Estado Código Postal componentes / limpiamente en campos de trama de datos.

Puede pasar una expresión regular para .str.extract () para piezas de “extraer” de cada célula en la serie. En .str.extract (), .str es el descriptor de acceso, y .str.extract () es un método de acceso:

>>> regex = (r'(?P[A-Za-z ]+), ' # One or more letters
... r'(?P[A-Z]{2}) ' # 2 capital letters
... r'(?P\d{5}(?:-\d{4})?)') # Optional 4-digit extension
...
>>> addr.str.replace('.', '').str.extract(regex)
city state zip
0 Washington DC 20003
1 Brooklyn NY 11211-1755
2 Omaha NE 68154
3 Pittsburgh PA 15211

Esto también ilustra lo que se conoce como el método de encadenamiento, donde .str.extract (regex) se llama en el resultado de addr.str.replace ( », »), que limpia el uso de los períodos de conseguir un buen estado de 2 caracteres abreviatura. de

Es útil saber un poquito acerca de cómo estos métodos de acceso funcionan como una razón para motivar por las que debe utilizar en primer lugar, en lugar de algo así como addr.apply (re.findall, …).

Cada descriptor de acceso es en sí misma una buena fe clase de Python:

  • .str asigna a StringMethods.
  • .Dt mapas a CombinedDatetimelikeProperties.
  • .cat rutas a CategoricalAccessor.

Estas clases independientes son entonces “unidos” a la clase utilizando una serie CachedAccessor. Es cuando las clases están envueltos en CachedAccessor que un poco de magia sucede.

CachedAccessor está inspirado en un diseño de “propiedad caché”: una propiedad sólo se calcula una vez por instancia y luego reemplazado por un atributo común. Para ello, la sobrecarga del método de obtener .__ __ (), que es parte del protocolo de descriptor de Python.

Nota : Si desea obtener más información sobre el funcionamiento interno de cómo esto funciona, observa el descriptor de Python COMO y este post en el diseño de la propiedad en caché. Python 3 también introduce functools.lru_cache (), que ofrece una funcionalidad similar. Hay ejemplos por todo el lugar de este patrón, como por ejemplo en el paquete aiohttp.

El segundo descriptor de acceso, .dt, es para datetime-como de datos. Es técnicamente pertenece a pandas’ DatetimeIndex, y si se llama en una serie, que se convierte en una primera DatetimeIndex:

>>> daterng = pd.Series(pd.date_range('2017', periods=9, freq='Q'))
>>> daterng
0 2017-03-31
1 2017-06-30
2 2017-09-30
3 2017-12-31
4 2018-03-31
5 2018-06-30
6 2018-09-30
7 2018-12-31
8 2019-03-31
dtype: datetime64[ns]

>>> daterng.dt.day_name()
0 Friday
1 Friday
2 Saturday
3 Sunday
4 Saturday
5 Saturday
6 Sunday
7 Monday
8 Sunday
dtype: object

>>> # Second-half of year only
>>> daterng[daterng.dt.quarter > 2]
2 2017-09-30
3 2017-12-31
6 2018-09-30
7 2018-12-31
dtype: datetime64[ns]

>>> daterng[daterng.dt.is_year_end]
3 2017-12-31
7 2018-12-31
dtype: datetime64[ns]

El tercer descriptor de acceso, .cat, es sólo para datos categóricos, que veremos en breve en su propia sección.

4. Cree un DatetimeIndex del componente Columnas

Hablando de fecha y hora como datos, como en daterng anterior, es posible crear un pandas DatetimeIndex de columnas múltiples componentes que juntos forman una fecha o de fecha y hora:

>>> from itertools import product
>>> datecols = ['year', 'month', 'day']

>>> df = pd.DataFrame(list(product([2017, 2016], [1, 2], [1, 2, 3])),
... columns=datecols)
>>> df['data'] = np.random.randn(len(df))
>>> df
year month day data
0 2017 1 1 -0.0767
1 2017 1 2 -1.2798
2 2017 1 3 0.4032
3 2017 2 1 1.2377
4 2017 2 2 -0.2060
5 2017 2 3 0.6187
6 2016 1 1 2.3786
7 2016 1 2 -0.4730
8 2016 1 3 -2.1505
9 2016 2 1 -0.6340
10 2016 2 2 0.7964
11 2016 2 3 0.0005

>>> df.index = pd.to_datetime(df[datecols])
>>> df.head()
year month day data
2017-01-01 2017 1 1 -0.0767
2017-01-02 2017 1 2 -1.2798
2017-01-03 2017 1 3 0.4032
2017-02-01 2017 2 1 1.2377
2017-02-02 2017 2 2 -0.2060

Por último, se puede colocar las columnas individuales y convertir por mayor para una Serie:

>>> df = df.drop(datecols, axis=1).squeeze()
>>> df.head()
2017-01-01 -0.0767
2017-01-02 -1.2798
2017-01-03 0.4032
2017-02-01 1.2377
2017-02-02 -0.2060
Name: data, dtype: float64

>>> df.index.dtype_str
'datetime64[ns]

la intuición detrás de una trama de datos que pasa es que una trama de datos se asemeja a un diccionario de Python, donde los nombres de columna son claves, y las columnas individuales (Series) son los valores de diccionario. Es por eso que pd.to_datetime (df [datecols] .to_dict (Orient = ‘lista’)) también funcionaría en este caso. Esto refleja la construcción de datetime.datetime de Python, donde se pasa argumentos de palabras clave tales como datetime.datetime (año = 2000 = 1 mes, día = 15, hora = 10).

5. Uso de datos categóricos para ahorrar en tiempo y espacio

Una potente función de las pandas es su dtype categórica.

Incluso si no siempre está trabajando con gigabytes de datos en la RAM, de lo que has topado con casos en los que las operaciones sencillas sobre una gran trama de datos parecen colgar durante más de unos pocos segundos.

pandas objeto dtype es a menudo un gran candidato para la conversión de datos de categoría. (Objeto es un contenedor para str Python, tipos de datos heterogéneos, o “otros” tipos.) Strings ocupan una cantidad significativa de espacio en la memoria:

>>> colors = pd.Series([
... 'periwinkle',
... 'mint green',
... 'burnt orange',
... 'periwinkle',
... 'burnt orange',
... 'rose',
... 'rose',
... 'mint green',
... 'rose',
... 'navy'
... ])
...
>>> import sys
>>> colors.apply(sys.getsizeof)
0 59
1 59
2 61
3 59
4 61
5 53
6 53
7 59
8 53
9 53
dtype: int64

Nota: I utiliza sys.getsizeof () para mostrar la memoria ocupada por cada valor individual en la serie. Tenga en cuenta que estos son los objetos de Python que tienen cierta sobrecarga en el primer lugar. (Sys.getsizeof ( ») devolverá 49 bytes.)

También es colors.memory_usage (), que resume el uso de la memoria y se basa en el atributo .nbytes de la matriz NumPy subyacente. No se acerque demasiado empantanado en estos detalles: lo que es importante es el uso de memoria relativa que resulta de la conversión de tipos, como se verá a continuación.

Ahora, lo que si podría tomar los colores únicos anteriores y asignar cada uno a un número entero menor acaparando espacio-? Aquí es una aplicación ingenua de que:

>>> mapper = {v: k for k, v in enumerate(colors.unique())}
>>> mapper
{'periwinkle': 0, 'mint green': 1, 'burnt orange': 2, 'rose': 3, 'navy': 4}

>>> as_int = colors.map(mapper)
>>> as_int
0 0
1 1
2 2
3 0
4 2
5 3
6 3
7 1
8 3
9 4
dtype: int64

>>> as_int.apply(sys.getsizeof)
0 24
1 28
2 28
3 24
4 28
5 28
6 28
7 28
8 28
9 28
dtype: int64

Nota : Otra manera de hacer esto es lo mismo con pd.factorize pandas’ (colores):

>>> pd.factorize(colors)[0]
array([0, 1, 2, 0, 2, 3, 3, 1, 3, 4])

De cualquier manera, va a codificar el objeto como un tipo enumerado (categórica variable).

Se dará cuenta inmediatamente de que el uso de memoria es casi reducido a la mitad en comparación con cuando las cuerdas completos se utilizan con dtype objeto.

anteriormente en la sección de descriptores de acceso, que menciona el descriptor de acceso (categórica) .cat. El asignador de arriba con una ilustración aproximada de lo que ocurre internamente con pandas’ categórica dtype:

“El uso de la memoria de un categórico es proporcional al número de categorías más la longitud de los datos. En contraste, un dtype objeto es una constante multiplicada por la longitud de los datos “. (Fuente)

en colores más arriba, que tienen una proporción de 2 valores para cada valor único (categoría):

>>> len(colors) / colors.nunique()
2.0

Como resultado, el ahorro de memoria a partir de la conversión a categórica es buena, pero no excelente:

>>> # Not a huge space-saver to encode as Categorical
>>> colors.memory_usage(index=False, deep=True)
650
>>> colors.astype('category').memory_usage(index=False, deep=True)
495

Sin embargo, Si soplas la proporción anterior, con una gran cantidad de datos y unos valores únicos (pensar en los datos sobre la demografía o resultados de las pruebas alfabéticos), la reducción de la memoria requerida es más de 10 veces:

>>> manycolors = colors.repeat(10)
>>> len(manycolors) / manycolors.nunique() # Much greater than 2.0x
20.0

>>> manycolors.memory_usage(index=False, deep=True)
6500
>>> manycolors.astype('category').memory_usage(index=False, deep=True)
585

una ventaja es que la eficiencia computacional consigue un aumentar demasiado: para la serie categórica, se realizan las operaciones de cadena en los .cat.categories atribuyen más bien que en cada elemento original de la serie.

En otras palabras, la operación se realiza una vez por categoría única, y los resultados se asignan a los valores. Los datos categóricos tiene un descriptor de acceso .cat que es una ventana a atributos y métodos para manipular las categorías:

>>> ccolors = colors.astype('category')
>>> ccolors.cat.categories
Index(['burnt orange', 'mint green', 'navy', 'periwinkle', 'rose'], dtype='object')

De hecho, se puede reproducir algo similar al ejemplo anterior que lo hizo de forma manual:

>>> ccolors.cat.codes
0 3
1 1
2 0
3 3
4 0
5 4
6 4
7 1
8 4
9 2
dtype: int8

Todo lo que necesita hacer para exactamente imitan la salida anterior manual es para reordenar los códigos:

>>> ccolors.cat.reorder_categories(mapper).cat.codes
0 0
1 1
2 2
3 0
4 2
5 3
6 3
7 1
8 3
9 4
dtype: int8

en cuenta que la dtype es INT8 de NumPy, un niño de 8 bits con signo entero que puede tomar valores entre -127 y 128. (Sólo se necesita un solo byte para representar una valor en la memoria. 64-bits con signo enteros pueden ser excesivos en términos de uso de memoria.) Nuestro ejemplo tosco dio lugar a Int64 datos por defecto, mientras que las pandas es lo suficientemente inteligente como para datos categóricos abatido a la dtype numérica más pequeña posible.

La mayoría de los atributos de .cat están relacionados con ver y manipular las categorías subyacentes a sí mismos:

>>> [i for i in dir(ccolors.cat) if not i.startswith('_')]
['add_categories',
'as_ordered',
'as_unordered',
'categories',
'codes',
'ordered',
'remove_categories',
'remove_unused_categories',
'rename_categories',
'reorder_categories',
'set_categories']

Hay algunas advertencias, sin embargo. Los datos categóricos es generalmente menos flexible. Por ejemplo, si la inserción de los valores nunca antes vistos, es necesario agregar este valor a un contenedor .categories primera:

>>> ccolors.iloc[5] = 'a new color'
# ...
ValueError: Cannot setitem on a Categorical with a new category,
set the categories first

>>> ccolors = ccolors.cat.add_categories(['a new color'])
>>> ccolors.iloc[5] = 'a new color' # No more ValueError

Si va a ser el establecimiento de valores o la remodelación de datos en lugar de derivar nuevos cálculos, tipos categóricos pueden ser menos ágil.

6. Introspect GroupBy objetos a través de la iteración

Cuando se llama a df.groupby ( ‘x’), los objetos GroupBy pandas resultante puede ser un poco opaco. Este objeto se crea una instancia con pereza y no tiene ninguna representación significativa por sí misma.

Usted puede demostrar con el conjunto de datos de abulón del ejemplo 1:

>>> abalone['ring_quartile'] = pd.qcut(abalone.rings, q=4, labels=range(1, 5))
>>> grouped = abalone.groupby('ring_quartile')

>>> grouped

bien, ahora tiene un objeto GroupBy, pero ¿qué es esto, y no como lo veo?

Antes de llamar algo así como grouped.apply (func), se puede aprovechar el hecho de que los objetos son GroupBy iterable:

>>> help(grouped.__iter__)

Groupby iterator

Returns
-------
Generator yielding sequence of (name, subsetted object)
for each group

Cada “cosa” cedido por agrupada .__ __ iter () es una tupla de (nombre, objeto con subjuegos ), donde nombre es el valor de la columna en la que está la agrupación, y el objeto con subjuegos es una trama de datos que es un subconjunto de la trama de datos original basado en lo que sea que agrupa condición especificada. Es decir, los datos se fragmentan por grupo:

>>> for idx, frame in grouped:
... print(f'Ring quartile: {idx}')
... print('-' * 16)
... print(frame.nlargest(3, 'weight'), end='\n\n')
...
Ring quartile: 1
----------------
sex length diam height weight rings ring_quartile
2619 M 0.690 0.540 0.185 1.7100 8 1
1044 M 0.690 0.525 0.175 1.7005 8 1
1026 M 0.645 0.520 0.175 1.5610 8 1

Ring quartile: 2
----------------
sex length diam height weight rings ring_quartile
2811 M 0.725 0.57 0.190 2.3305 9 2
1426 F 0.745 0.57 0.215 2.2500 9 2
1821 F 0.720 0.55 0.195 2.0730 9 2

Ring quartile: 3
----------------
sex length diam height weight rings ring_quartile
1209 F 0.780 0.63 0.215 2.657 11 3
1051 F 0.735 0.60 0.220 2.555 11 3
3715 M 0.780 0.60 0.210 2.548 11 3

Ring quartile: 4
----------------
sex length diam height weight rings ring_quartile
891 M 0.730 0.595 0.23 2.8255 17 4
1763 M 0.775 0.630 0.25 2.7795 12 4
165 M 0.725 0.570 0.19 2.5500 14 4

En relación con esto, un objeto GroupBy también tiene .Grupos y un grupo-comprador, .get_group ():

>>> grouped.groups.keys()
dict_keys([1, 2, 3, 4])

>>> grouped.get_group(2).head()
sex length diam height weight rings ring_quartile
2 F 0.530 0.420 0.135 0.6770 9 2
8 M 0.475 0.370 0.125 0.5095 9 2
19 M 0.450 0.320 0.100 0.3810 9 2
23 F 0.550 0.415 0.135 0.7635 9 2
39 M 0.355 0.290 0.090 0.3275 9 2

Esto puede ayudar a ser un poco más seguros de que la operación que’ re realizar es la que desea:

>>> grouped['height', 'weight'].agg(['mean', 'median'])
height weight
mean median mean median
ring_quartile
1 0.1066 0.105 0.4324 0.3685
2 0.1427 0.145 0.8520 0.8440
3 0.1572 0.155 1.0669 1.0645
4 0.1648 0.165 1.1149 1.0655

No importa lo que el cálculo se realiza en agrupada, ya sea un método de pandas sola o función hecha a la medida, cada uno de estos “sub-tramas” se pasa de uno en uno como un argumento a que se puede llamar. Aquí es donde el término “split-aplicar-se combinan” viene de: romper los datos por grupos, realizar un cálculo por grupo, y se recombinan en una cierta manera agregada.

Si tiene problemas para visualizar exactamente lo que los grupos realmente se verá como, simplemente iterar sobre ellos y la impresión de unos pocos pueden ser tremendamente útil.

7. Usar este mapeo truco para decir afiliación Agrupación

Vamos que tiene una serie y una correspondiente “tabla de asignación”, donde cada valor pertenece a un grupo de varios miembros, o para ningún grupo en absoluto:

>>> countries = pd.Series([
... 'United States',
... 'Canada',
... 'Mexico',
... 'Belgium',
... 'United Kingdom',
... 'Thailand'
... ])
...
>>> groups = {
... 'North America': ('United States', 'Canada', 'Mexico', 'Greenland'),
... 'Europe': ('France', 'Germany', 'United Kingdom', 'Belgium')
... }

En otra es decir, que necesitan asignar países al siguiente resultado:

0 North America
1 North America
2 North America
3 Europe
4 Europe
5 other
dtype: object

lo que hay aquí es una función similar a pd.cut pandas’ (), pero para hurgar en la basura basada en la pertenencia categórica. Puede utilizar pd.Series.map (), que ya se vio en el ejemplo # 5, para imitar esto:

from typing import Any

def membership_map(s: pd.Series, groups: dict,
fillvalue: Any=-1) -> pd.Series:
# Reverse & expand the dictionary key-value pairs
groups = {x: k for k, v in groups.items() for x in v}
return s.map(groups).fillna(fillvalue)

Esto debe ser significativamente más rápido que un bucle anidado Python a través de grupos de cada país en los países.

Aquí está una prueba de conducción: la ruptura de

>>> membership_map(countries, groups, fillvalue='other')
0 North America
1 North America
2 North America
3 Europe
4 Europe
5 other
dtype: object

defraudado lo que está pasando aquí. (Nota al margen:. Este es un gran lugar de entrar en el alcance de una función con depurador de Python, pdb, para inspeccionar qué variables son locales de la función)

El objetivo es mapear cada grupo en grupos a un entero. Sin embargo, Series.map () no reconocerá ‘ab’-que necesita la versión rota con cada personaje de cada grupo asignado a un entero. Esto es lo que el diccionario por comprensión está haciendo:

>>> groups = dict(enumerate(('ab', 'cd', 'xyz')))
>>> {x: k for k, v in groups.items() for x in v}
{'a': 0, 'b': 0, 'c': 1, 'd': 1, 'x': 2, 'y': 2, 'z': 2}

Este diccionario se puede pasar a s.map () para mapear o “traducir” sus valores a sus índices de grupo correspondientes.

8. Comprender la forma pandas utiliza operadores de Boole

Usted puede estar familiarizado con la prioridad de los operadores de Python, dónde y, no, y o tienen menor precedencia que los operadores aritméticos como <, <=, >, > =,! =, Y ==. Considere las dos afirmaciones siguientes, donde tienen mayor precedencia que el operador and:

>>> # Evaluates to "False and True"
>>> 4 < 3 and 5 > 4
False

>>> # Evaluates to 4 < 5 > 4
>>> 4 < (3 and 5) > 4
True

Nota : No es específicamente relacionada con las pandas, pero 3 y 5 se evalúa en 5 a causa de la evaluación de cortocircuito:

“El valor de retorno de un operador de cortocircuito es el último argumento evaluado “. (Fuente)

pandas (y NumPy, sobre la que se construye pandas) no utiliza y, o, o no. En su lugar, utiliza y, |, y ~, respectivamente, que son normales, de buena fe Python operadores bit a bit.

Estos operadores no son “inventados” por los pandas. Por el contrario, y, |, y ~ son válidos Python incorporada operadores que tienen mayor (en lugar de inferior) precedencia que los operadores aritméticos. (. Pandas anula métodos dunder como .__ ROR __ () que se asignan al operador |) a sacrificar algún detalle, se puede pensar en “bit a bit” como “elementwise” en lo que respecta a las pandas y NumPy:

>>> pd.Series([True, True, False]) & pd.Series([True, False, False])
0 True
1 False
2 False
dtype: bool

Vale la pena entender esto concepto en su totalidad. Digamos que usted tiene un rango similar al de la serie:

>>> s = pd.Series(range(10))

yo supongo que es posible que haya visto esta excepción planteado en algún momento: de

>>> s % 2 == 0 & s > 3
ValueError: The truth value of a Series is ambiguous.
Use a.empty, a.bool(), a.item(), a.any() or a.all().

¿Qué pasa aquí? Es útil para incrementalmente unen la expresión con paréntesis, explicando cómo Python expande este paso expresión por paso:

s % 2 == 0 & s > 3 # Same as above, original expression
(s % 2) == 0 & s > 3 # Modulo is most tightly binding here
(s % 2) == (0 & s) > 3 # Bitwise-and is second-most-binding
(s % 2) == (0 & s) and (0 & s) > 3 # Expand the statement
((s % 2) == (0 & s)) and ((0 & s) > 3) # The `and` operator is least-binding

La expresión s% 2 == 0 y s > 3 es equivalente a (o es tratado como) ((s% 2 ) == (0 & s)) y ((0 & s) > 3). Esto se llama expansión: x

bien, ahora parada allí, y vamos a llevar esto a pandas-hablar. Tiene dos Series pandas que llamaremos izquierda y derecha:

>>> left = (s % 2) == (0 & s)
>>> right = (0 & s) > 3
>>> left and right # This will raise the same ValueError

Usted sabe que una declaración de la forma de izquierda a derecha es el valor de verdad prueba tanto a la izquierda y la derecha, como en el siguiente:

>>> bool(left) and bool(right)

El problema es que pandas desarrolladores intencionadamente no establecen un valor de verdad (truthiness) para una serie completa. Es un Verdadero o Falso Serie? ¿Quién sabe? El resultado es ambiguo:

>>> bool(s)
ValueError: The truth value of a Series is ambiguous.
Use a.empty, a.bool(), a.item(), a.any() or a.all().

La única comparación que tiene sentido es una comparación elementwise. Es por eso que, si se trata de un operador aritmético, necesitará paréntesis:

>>> (s % 2 == 0) & (s > 3)
0 False
1 False
2 False
3 False
4 True
5 False
6 True
7 False
8 True
9 False
dtype: bool

En resumen, si ve el ValueError por encima de pop-up con la indexación booleano, la primera cosa que probablemente debería mirar a hacer es espolvorear en algunos paréntesis necesarios.

9. Carga de datos desde el portapapeles

Es una situación común a la necesidad de transferir datos de un lugar como Excel o texto sublime a una estructura de datos pandas. Idealmente, usted quiere hacer esto sin pasar por la etapa intermedia de guardar los datos en un archivo y después de leer en el archivo de pandas.

Puede cargar en tramas de datos de búfer de datos del portapapeles de su ordenador con pd.read_clipboard (). Sus argumentos son pasados ​​a pd.read_table ().

Esto le permite copiar texto estructurado directamente a una trama de datos o serie. En Excel, los datos se vería algo como esto:

Su representación en texto plano (por ejemplo, en un editor de texto) se vería así:

a b c d
0 1 inf 1/1/00
2 7.389056099 N/A 5-Jan-13
4 54.59815003 nan 7/24/18
6 403.4287935 None NaT

Basta con seleccionar y copiar el texto anterior, y Pd llamada .read_clipboard ():

>>> df = pd.read_clipboard(na_values=[None], parse_dates=['d'])
>>> df
a b c d
0 0 1.0000 inf 2000-01-01
1 2 7.3891 NaN 2013-01-05
2 4 54.5982 NaN 2018-07-24
3 6 403.4288 NaN NaT

>>> df.dtypes
a int64
b float64
c float64
d datetime64[ns]
dtype: object

10. Escribe pandas objetos directamente en formato comprimido

de este uno corto y dulce para completar la lista. A partir de las pandas versión 0.21.0, puede escribir pandas objetos directamente a gzip, bz2, código postal o la compresión xz, en lugar de esconder el archivo sin comprimir en la memoria y su conversión. He aquí un ejemplo utilizando los datos de abulón de truco # 1:

abalone.to_json('df.json.gz', orient='records',
lines=True, compression='gzip')

En este caso, la diferencia de tamaño es 11.6x:

>>> import os.path
>>> abalone.to_json('df.json', orient='records', lines=True)
>>> os.path.getsize('df.json') / os.path.getsize('df.json.gz')
11.603035760226396

desea agregar a esta lista? Háganos saber

Es de esperar que fuera capaz de recoger un par de trucos útiles de esta lista a prestar su código pandas mejor legibilidad, versatilidad y rendimiento.

Si usted tiene algo bajo la manga que no está cubierto aquí, por favor deje una sugerencia en los comentarios o como GitHub Gist. Con mucho gusto vamos a añadir a esta lista y dar crédito donde es debido.

Mira ahora Este tutorial tiene un vídeo relacionado curso creado por el equipo del Real Python. Mira que junto con el tutorial escrito para profundizar su comprensión: idiomático pandas: trucos y características que no puede saber

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *