PANDAS - Manipulación de Datos con Python

Por Jose R. Zapata

Ultima actualizacion: 26/Abril/2024 - Pandas 2.0.3

Invitame a un Cafe

Pandas es una herramienta de manipulación de datos de alto nivel desarrollada por Wes McKinney. En su inicio es construido sobre Numpy y ahora compatible con Arrow y permite el análisis de datos que cuenta con las estructuras de datos que necesitamos para limpiar los datos en bruto y que sean aptos para el análisis (por ejemplo, tablas). Como Pandas permite realizar tareas importantes, como alinear datos para su comparación, fusionar conjuntos de datos, gestión de datos perdidos, etc., se ha convertido en una librería muy importante para procesar datos a alto nivel en Python (es decir, estadísticas ). Pandas fue diseñada originalmente para gestionar datos financieros, y como alternativo al uso de hojas de cálculo (es decir, Microsoft Excel).

Los principales tipos de datos que pueden representarse con pandas son:

  • Datos tabulares con columnas de tipo heterogéneo con etiquetas en columnas y filas.
  • Series temporales

Pandas proporciona herramientas que permiten:

  • leer y escribir datos en diferentes formatos: CSV, JSON, Excel, bases SQL, parquet y HDF5 entre otros
  • seleccionar y filtrar de manera sencilla tablas de datos en función de posición, valor o etiquetas
  • fusionar y unir datos
  • transformar datos aplicando funciones tanto en global como por ventanas
  • manipulación de series temporales
  • hacer gráficas

En pandas existen 2 tipos básicos de objetos todos ellos basados a su vez en Numpy y ahora en Arrow:

  • Series (listas, 1D)
  • DataFrame (tablas, 2D)

Por lo tanto, Pandas nos proporciona las estructuras de datos y funciones necesarias para el análisis de datos.

Instalar Pandas

Pandas ya esta preinstalado si se usa Google Collaboratory, si va realizar una instalacion en su computador

PIP

pip install pandas

Pandas con librerias para leer archivos de excel

pip install "pandas[excel]"

Pandas para leer tablas de HTML

pip install "pandas[html]"

Para ver otras opciones ir al siguiente link otras instalaciones de pandas

Importando Pandas

La libreria Pandas se importa de la siguiente manera

import pandas as pd # Importacion estandar de la libreria Pandas
import numpy  as np # Importacion estandar de la libreria NumPy
pd.__version__
'2.0.3'

Series

Una serie es el primer tipo de datos de pandas y es muy similar a una matriz NumPy (de hecho está construida sobre el objeto de matriz NumPy). Lo que diferencia un arreglo NumPy de una serie, es que una serie puede tener etiquetas en los ejes, lo que significa que puede ser indexada por una etiqueta, en lugar de solo una ubicación numérica. Tampoco necesita contener datos numéricos, puede contener cualquier Objeto de Python arbitrario.

Creando una Serie

Puede convertir una lista, una matriz numpy o un diccionario en una serie, usando el metodo pd.Series:

# Crear diferentes tipos de datos
labels = ['a','b','c'] # lista de etiquetas
my_list = [10,20,30] # lista con valores
arr = np.array([10,20,30]) # Convertir ista de valores en arreglo NumPy
d = {'a':10,'b':20,'c':30} # Creacion de un diccionario

Desde Listas

# Convertir una lista en series usando el metodo pd.Series
# observe que se crean los nombres con las posiciones de cada elemento
pd.Series(data=my_list)
0    10
1    20
2    30
dtype: int64
# Convertir una lista en series usando el metodo pd.Series
# se puede ingresar el nombre de las posiciones
pd.Series(data=my_list,index=labels)
a    10
b    20
c    30
dtype: int64
# No es necesario ingresar la palabra de 'data =''  en el argumento
pd.Series(my_list,labels)
a    10
b    20
c    30
dtype: int64

Desde Arreglos NumPy

# Convertir un arreglo en series usando el metodo pd.Series
pd.Series(arr)
0    10
1    20
2    30
dtype: int64
# Convertir un arreglo en series indicando tambien los valores del index
pd.Series(arr,labels)
a    10
b    20
c    30
dtype: int64

Desde un Diccionario

# Convertir un diccionario en series usando el metodo pd.Series
# Como el diccionario ya tiene clave entonces se le asigna como valor de la posicion
pd.Series(d)
a    10
b    20
c    30
dtype: int64

Datos en una Series

Una serie de pandas puede contener una variedad de tipos de objetos:

# Creando una serie basado solo en una lista de letras
pd.Series(data=labels)
0    a
1    b
2    c
dtype: object

Indexacion

La clave para usar una serie es entender su índice. Pandas hace uso de estos nombres o números de índice al permitir búsquedas rápidas de información (funciona como una tabla hash o diccionario).

Veamos algunos ejemplos de cómo obtener información de una serie. Vamos a crear dos series, ser1 y ser2:

# Creacion de una serie con sus labels o indices
ser1 = pd.Series([1,2,3,4],
                 index = ['USA', 'Alemania','Italia', 'Japon'])
ser1
USA         1
Alemania    2
Italia      3
Japon       4
dtype: int64
# Creacion de una serie con sus labels o indices
ser2 = pd.Series([1,2,5,4],
                 index = ['USA', 'Alemania','Colombia', 'Japon'])
ser2
USA         1
Alemania    2
Colombia    5
Japon       4
dtype: int64
# La busqueda en una serie es igual como en un diccionario
ser1['USA']
1
# La busqueda en una serie es igual como en un diccionario
ser2['Colombia']
5

Las operaciones también se realizan según el índice:

# Observe los resultados de los paises que solo estan en una serie y no en las dos
ser1 + ser2
Alemania    4.0
Colombia    NaN
Italia      NaN
Japon       8.0
USA         2.0
dtype: float64

DataFrames

Los DataFrames son la estructura mas importante en pandas y están directamente inspirados en el lenguaje de programación R. Se puede pensar en un DataFrame como un conjunto de Series reunidas que comparten el mismo índice. En los DataFrame tenemos la opción de especificar tanto el index (el nombre de las filas) como columns (el nombre de las columnas).

# Importar la funcion de NumPy para crear arreglos de numeros enteros
from numpy.random import randn
np.random.seed(101) # Inicializar el generador aleatorio
# Forma rapida de crear una lista de python desde strings
'A B C D E F'.split()
['A', 'B', 'C', 'D', 'E', 'F']
# Crear un dataframe con numeros aleatorios de 4 Columnas y 5 Filas
# Crear listas rapidamente usando la funcion split 'A B C D E'.split()
# Esto evita tener que escribir repetidamente las comas

df = pd.DataFrame(randn(6,4),
                  index='A B C D E F'.split(),
                  columns='W X Y Z'.split())
df

WXYZ
A2.7068500.6281330.9079690.503826
B0.651118-0.319318-0.8480770.605965
C-2.0181680.7401220.528813-0.589001
D0.188695-0.758872-0.9332370.955057
E0.1907941.9787572.6059670.683509
F0.3026651.693723-1.706086-1.159119

Descripcion general del dataframe

Numero de Filas y Columnas

df.shape # retorna un Tuple asi: (filas, col)
(6, 4)

Informacion General de los datos

# Informacion general de los datos de cada cloumna
# Indica el numero de filas del dataset
# Muestra el numero de datos No Nulos por columna (valores validos)
# Tipo de dato de cada columna
# Tamaño total del dataset
df.info()
<class 'pandas.core.frame.DataFrame'>
Index: 6 entries, A to F
Data columns (total 4 columns):
 #   Column  Non-Null Count  Dtype
---  ------  --------------  -----
 0   W       6 non-null      float64
 1   X       6 non-null      float64
 2   Y       6 non-null      float64
 3   Z       6 non-null      float64
dtypes: float64(4)
memory usage: 240.0+ bytes
# Tipos de datos que existen en las columnas del dataframe
df.dtypes
W    float64
X    float64
Y    float64
Z    float64
dtype: object

Resumen de estadistica descriptiva General

el metodo .describe() de los dataframes presenta un resumen de la estadistica descriptiva general de las columnas numericas del dataframe, presenta la informacion de:

  • Promedio (mean)
  • Desviacion estandard (std)
  • Valor minimo
  • Valor maximo
  • Cuartiles (25%, 50% y 75%)
df.describe() # No muestra la informacion de las columnas categoricas

WXYZ
count6.0000006.0000006.0000006.000000
mean0.3369920.6604240.0925580.166706
std1.5037441.0758621.5712800.839534
min-2.018168-0.758872-1.706086-1.159119
25%0.189220-0.082455-0.911947-0.315794
50%0.2467300.684127-0.1596320.554896
75%0.5640051.4553230.8131800.664123
max2.7068501.9787572.6059670.955057

Ver Primeros elementos del dataframe

df.head()

WXYZ
A2.7068500.6281330.9079690.503826
B0.651118-0.319318-0.8480770.605965
C-2.0181680.7401220.528813-0.589001
D0.188695-0.758872-0.9332370.955057
E0.1907941.9787572.6059670.683509

Ver Ultimos elementos del dataframe

df.tail()

WXYZ
B0.651118-0.319318-0.8480770.605965
C-2.0181680.7401220.528813-0.589001
D0.188695-0.758872-0.9332370.955057
E0.1907941.9787572.6059670.683509
F0.3026651.693723-1.706086-1.159119

Ver elementos aleatorios del dataframe

df.sample(3)

WXYZ
B0.651118-0.319318-0.8480770.605965
D0.188695-0.758872-0.9332370.955057
C-2.0181680.7401220.528813-0.589001

Seleccion y Indexacion

Existen diversos métodos para tomar datos de un DataFrame

# Regresara todos los datos de la columna W
df['W']
A    2.706850
B    0.651118
C   -2.018168
D    0.188695
E    0.190794
F    0.302665
Name: W, dtype: float64
# Seleccionar dos o mas columnas
# Pasar una lista con los nombres de las columnas

df[['W','Z']]

WZ
A2.7068500.503826
B0.6511180.605965
C-2.018168-0.589001
D0.1886950.955057
E0.1907940.683509
F0.302665-1.159119
# Seleccionar dos o mas columnas
# Pasar una lista con los nombres de las columnas
# Puedo indicar el orden de las columnas

df[['X','W','Z']]

XWZ
A0.6281332.7068500.503826
B-0.3193180.6511180.605965
C0.740122-2.018168-0.589001
D-0.7588720.1886950.955057
E1.9787570.1907940.683509
F1.6937230.302665-1.159119

Las columnas de un DataFrame Columns son solo Series

type(df['W']) # Tipos de datos
pandas.core.series.Series

Creando una Nueva Columna

# Nueva columna igual a la suma de otras dos
# operacion vectorizada
df['new'] = df['W'] + df['Y']
df

WXYZnew
A2.7068500.6281330.9079690.5038263.614819
B0.651118-0.319318-0.8480770.605965-0.196959
C-2.0181680.7401220.528813-0.589001-1.489355
D0.188695-0.758872-0.9332370.955057-0.744542
E0.1907941.9787572.6059670.6835092.796762
F0.3026651.693723-1.706086-1.159119-1.403420

Eliminando Columnas

df.drop('new',axis='columns')

WXYZ
A2.7068500.6281330.9079690.503826
B0.651118-0.319318-0.8480770.605965
C-2.0181680.7401220.528813-0.589001
D0.188695-0.758872-0.9332370.955057
E0.1907941.9787572.6059670.683509
F0.3026651.693723-1.706086-1.159119
# No se aplica a el dataframe a menos que se especifique.
# Como se ve la operacion pasada no quedo grabada
df

WXYZnew
A2.7068500.6281330.9079690.5038263.614819
B0.651118-0.319318-0.8480770.605965-0.196959
C-2.0181680.7401220.528813-0.589001-1.489355
D0.188695-0.758872-0.9332370.955057-0.744542
E0.1907941.9787572.6059670.6835092.796762
F0.3026651.693723-1.706086-1.159119-1.403420
# Para que quede grabado se puede hacer de dos formas
#df = df.drop('new',axis='columns') # Forma 1

df.drop('new', axis='columns', inplace=True) # Forma 2
df

WXYZ
A2.7068500.6281330.9079690.503826
B0.651118-0.319318-0.8480770.605965
C-2.0181680.7401220.528813-0.589001
D0.188695-0.758872-0.9332370.955057
E0.1907941.9787572.6059670.683509
F0.3026651.693723-1.706086-1.159119
df

WXYZ
A2.7068500.6281330.9079690.503826
B0.651118-0.319318-0.8480770.605965
C-2.0181680.7401220.528813-0.589001
D0.188695-0.758872-0.9332370.955057
E0.1907941.9787572.6059670.683509
F0.3026651.693723-1.706086-1.159119

También se puede sacar filas de esta manera:

df.drop('E',axis='index')

WXYZ
A2.7068500.6281330.9079690.503826
B0.651118-0.319318-0.8480770.605965
C-2.0181680.7401220.528813-0.589001
D0.188695-0.758872-0.9332370.955057
F0.3026651.693723-1.706086-1.159119
df

WXYZ
A2.7068500.6281330.9079690.503826
B0.651118-0.319318-0.8480770.605965
C-2.0181680.7401220.528813-0.589001
D0.188695-0.758872-0.9332370.955057
E0.1907941.9787572.6059670.683509
F0.3026651.693723-1.706086-1.159119
# Otra manera de borrar las columnas es
del df['X'] # Esta funcion es INPLACE
df

WYZ
A2.7068500.9079690.503826
B0.651118-0.8480770.605965
C-2.0181680.528813-0.589001
D0.188695-0.9332370.955057
E0.1907942.6059670.683509
F0.302665-1.706086-1.159119

Obtener los nombres de las columnas y los indices (index):

df.columns # nombres de las columnas
Index(['W', 'Y', 'Z'], dtype='object')
df.index # nombres de los indices
Index(['A', 'B', 'C', 'D', 'E', 'F'], dtype='object')

Seleccionando Filas y Columnas

las dos formas de seleccion principal son:

  • DataFrame.loc[etiqueta_fila, etiqueta_columna] <- por etiquetas
  • DataFrame.iloc[indice_fila, indice_columna] <- por indices
# la funcion loc busca por medio de los nombres de los indices y columnas
df.loc['A'] # se selecciona todos los valores de la fila 'A'
W    2.706850
Y    0.907969
Z    0.503826
Name: A, dtype: float64

O basado en la posicion (index) en vez de usar la etiqueta

df.iloc[2] # Se seleccionan los valores de la fila con indice 2
# recordar que los index empiezan en cero
W   -2.018168
Y    0.528813
Z   -0.589001
Name: C, dtype: float64

Seleccionar un subconjunto de filas y columnas

# Mediante etiquetas
# se selecciona el elemento que esta en la fila=B Col=Y
df.loc['B','Y'] # con etiquetas
-0.8480769834036315
# Mediante etiquetas
# se selecciona un subconjunto de datos que estan entre
# filas = A, B   Cols= W, Y
df.loc[['A','B'],['W','Y']]

WY
A2.7068500.907969
B0.651118-0.848077
df.loc[['B','A'],['Y','W']]

YW
B-0.8480770.651118
A0.9079692.706850

Seleccion Condicional o Filtros

Una característica importante de pandas es la selección condicional usando la notación de corchetes, muy similar a NumPy:

df

WYZ
A2.7068500.9079690.503826
B0.651118-0.8480770.605965
C-2.0181680.528813-0.589001
D0.188695-0.9332370.955057
E0.1907942.6059670.683509
F0.302665-1.706086-1.159119
# Devuelve un dataframe con booleans
# segun si se cumple o no la condicion
df>0

WYZ
ATrueTrueTrue
BTrueFalseTrue
CFalseTrueFalse
DTrueFalseTrue
ETrueTrueTrue
FTrueFalseFalse
# Esta operacion solo mostrara los valores del dataframe que cumplen la condicion
# los que no cumplen devuelve el valor NaN
df[df>0]

WYZ
A2.7068500.9079690.503826
B0.651118NaN0.605965
CNaN0.528813NaN
D0.188695NaN0.955057
E0.1907942.6059670.683509
F0.302665NaNNaN
# seleccionar todas las filas donde el valor
# que esta en la columna 'W' sea mayor que cero
df[df['W']>0]

WYZ
A2.7068500.9079690.503826
B0.651118-0.8480770.605965
D0.188695-0.9332370.955057
E0.1907942.6059670.683509
F0.302665-1.706086-1.159119
# Seleccionar las filas donde 'W' sea mayor que cero
# y de esas filas escoger los valores de la columna 'Y'
df[df['W']>0]['Y']
A    0.907969
B   -0.848077
D   -0.933237
E    2.605967
F   -1.706086
Name: Y, dtype: float64
# Seleccionar las filas donde 'W' sea mayor que cero
# y de esas filas escoger los valores de las columna 'Y' y 'X'
df[df['W']>0][['Y','Z']]

YZ
A0.9079690.503826
B-0.8480770.605965
D-0.9332370.955057
E2.6059670.683509
F-1.706086-1.159119

Para dos condiciones, se usa los booleanos de esta forma

  • | en vez de or
  • & en vez de and
  • ~ en vez de not

Por amor a Dios, recuerde usar paréntesis:

# Seleccionar las filas donde 'W' sea mayor que cero
# y tambien donde 'Y' sea mayor que 0.5
df[(df['W']>0) & (df['Y'] > 0.5)]

WYZ
A2.7068500.9079690.503826
E0.1907942.6059670.683509

.query() Busqueda condicional

Los terminos de busqueda condicional o filtros se entregan al metodo como tipo ‘string’

df

WYZ
A2.7068500.9079690.503826
B0.651118-0.8480770.605965
C-2.0181680.528813-0.589001
D0.188695-0.9332370.955057
E0.1907942.6059670.683509
F0.302665-1.706086-1.159119
# seleccionar todas las filas donde el valor
# que esta en la columna 'W' sea mayor que cero

#df[df['W']>0]
df.query('W>0')

WYZ
A2.7068500.9079690.503826
B0.651118-0.8480770.605965
D0.188695-0.9332370.955057
E0.1907942.6059670.683509
F0.302665-1.706086-1.159119
# Seleccionar las filas donde 'W' sea mayor que cero
# y de esas filas escoger los valores de la columna 'Y'

#df[df['W']>0]['Y']
df.query('W>0')['Y']
A    0.907969
B   -0.848077
D   -0.933237
E    2.605967
F   -1.706086
Name: Y, dtype: float64
# Seleccionar las filas donde 'W' sea mayor que cero
# y de esas filas escoger los valores de las columna 'Y' y 'X'

#df[df['W']>0][['Y','Z']]
df.query('W>0')[['Y','Z']]

YZ
A0.9079690.503826
B-0.8480770.605965
D-0.9332370.955057
E2.6059670.683509
F-1.706086-1.159119

Para dos condiciones, puede usar | = or y & = and con paréntesis:

# Seleccionar las filas donde 'W' sea mayor que cero
# y tambien donde 'Y' sea mayor que 0.5

#df[(df['W']>0) & (df['Y'] > 0.5)]
df.query('W>0 and Y>0.5')

WYZ
A2.7068500.9079690.503826
E0.1907942.6059670.683509

Cambio de columna de Indexacion

Analicemos algunas características más de la indexación, incluido el restablecimiento del índice o el establecimiento de parametros.

df

WYZ
A2.7068500.9079690.503826
B0.651118-0.8480770.605965
C-2.0181680.528813-0.589001
D0.188695-0.9332370.955057
E0.1907942.6059670.683509
F0.302665-1.706086-1.159119
# Reinicializar el indice a su valor por defecto 0,1...n index
df = df.reset_index()
df

indexWYZ
0A2.7068500.9079690.503826
1B0.651118-0.8480770.605965
2C-2.0181680.528813-0.589001
3D0.188695-0.9332370.955057
4E0.1907942.6059670.683509
5F0.302665-1.706086-1.159119
newind = 'CA NY WY OR CO FL'.split() # crear una lista con strings
newind
['CA', 'NY', 'WY', 'OR', 'CO', 'FL']
# Agregar la lista creada en el paso anterior al dataframe
df['States'] = newind
df

indexWYZStates
0A2.7068500.9079690.503826CA
1B0.651118-0.8480770.605965NY
2C-2.0181680.528813-0.589001WY
3D0.188695-0.9332370.955057OR
4E0.1907942.6059670.683509CO
5F0.302665-1.706086-1.159119FL
# Redefinir la columna states como el indice
df.set_index('States')

indexWYZ
States
CAA2.7068500.9079690.503826
NYB0.651118-0.8480770.605965
WYC-2.0181680.528813-0.589001
ORD0.188695-0.9332370.955057
COE0.1907942.6059670.683509
FLF0.302665-1.706086-1.159119
# por que no queda establecido el indice?
df

indexWYZStates
0A2.7068500.9079690.503826CA
1B0.651118-0.8480770.605965NY
2C-2.0181680.528813-0.589001WY
3D0.188695-0.9332370.955057OR
4E0.1907942.6059670.683509CO
5F0.302665-1.706086-1.159119FL
# para establecer el indice debe ser una funcion inplace
df.set_index('States',inplace=True)
#df = df.set_index('States') # otra forma de hacerlo
df

indexWYZ
States
CAA2.7068500.9079690.503826
NYB0.651118-0.8480770.605965
WYC-2.0181680.528813-0.589001
ORD0.188695-0.9332370.955057
COE0.1907942.6059670.683509
FLF0.302665-1.706086-1.159119

Groupby (Agrupacion por filas)

El método groupby le permite agrupar filas de datos y llamar a funciones agregadas

import pandas as pd
# Crear dataframe desde un diccionario
data = {'Company':['GOOG','GOOG','MSFT','MSFT','FB','FB','GOOG','MSFT','FB'],
       'Person':['Sam','Charlie','Amy','Vanessa','Carl','Sarah','John','Randy','David'],
       'Sales':[200,120,340,124,243,350,275,400,180]}
data
{'Company': ['GOOG', 'GOOG', 'MSFT', 'MSFT', 'FB', 'FB', 'GOOG', 'MSFT', 'FB'],
 'Person': ['Sam',
  'Charlie',
  'Amy',
  'Vanessa',
  'Carl',
  'Sarah',
  'John',
  'Randy',
  'David'],
 'Sales': [200, 120, 340, 124, 243, 350, 275, 400, 180]}
#conversion del diccionario a dataframe
df = pd.DataFrame(data)
df

CompanyPersonSales
0GOOGSam200
1GOOGCharlie120
2MSFTAmy340
3MSFTVanessa124
4FBCarl243
5FBSarah350
6GOOGJohn275
7MSFTRandy400
8FBDavid180

Se puede usar el método .groupby() para agrupar filas en función de un nombre de columna. Por ejemplo, vamos a agruparnos a partir de la Compañía. Esto creará un objeto DataFrameGroupBy:

#agrupar por Company
df.groupby('Company')
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x715b141134c0>

Se puede grabar este objeto en una nueva variable:

by_comp = df.groupby("Company")

utilizar los métodos agregados del objeto:

# Promedio de ventas por company
by_comp.mean(numeric_only=True)

Sales
Company
FB257.666667
GOOG198.333333
MSFT288.000000
# agrupar por compañia y calcular el promedio por cada una
df.groupby('Company').mean(numeric_only=True)

Sales
Company
FB257.666667
GOOG198.333333
MSFT288.000000

Más ejemplos de métodos agregados:

# agrupar por compañia y calcular la desviacion estandard
by_comp.std(numeric_only=True)

Sales
Company
FB85.943780
GOOG77.513440
MSFT145.161978
# agrupar por compañia y calcular el minimo
by_comp.min()

PersonSales
Company
FBCarl180
GOOGCharlie120
MSFTAmy124
# agrupar por compañia y calcular el maximo
by_comp.max()

PersonSales
Company
FBSarah350
GOOGSam275
MSFTVanessa400
# agrupar por compañia y sumar los elementos que hay excluyendo los NaN
by_comp.count()

PersonSales
Company
FB33
GOOG33
MSFT33
# Una de las funciones mas usadas para descripcion estadistica de un dataframe
# Genera estadísticas descriptivas que resumen la tendencia central, la dispersión y la forma de la distribución de un conjunto de datos, excluyendo los valores `` NaN``.
# by_comp.describe(include = 'all') # incluir todo
by_comp.describe()

Sales
countmeanstdmin25%50%75%max
Company
FB3.0257.66666785.943780180.0211.5243.0296.5350.0
GOOG3.0198.33333377.513440120.0160.0200.0237.5275.0
MSFT3.0288.000000145.161978124.0232.0340.0370.0400.0
# Una de las funciones mas usadas para descripcion estadistica de un dataframe
# Genera estadísticas descriptivas que resumen la tendencia central, la dispersión y la forma de la distribución de un conjunto de datos, excluyendo los valores `` NaN``.
# Transponer la descripcion
by_comp.describe().transpose()

CompanyFBGOOGMSFT
Salescount3.0000003.0000003.000000
mean257.666667198.333333288.000000
std85.94378077.513440145.161978
min180.000000120.000000124.000000
25%211.500000160.000000232.000000
50%243.000000200.000000340.000000
75%296.500000237.500000370.000000
max350.000000275.000000400.000000
# Descripcion estadistica de los datos de la copmañia GOOG
by_comp.describe().transpose()['GOOG']
Sales  count      3.000000
       mean     198.333333
       std       77.513440
       min      120.000000
       25%      160.000000
       50%      200.000000
       75%      237.500000
       max      275.000000
Name: GOOG, dtype: float64

Pivot Tables

La funcionlidad “Pivot_table” es muy utilizada y popular en las conocidas “hojas de cálculo” tipo, OpenOffice, LibreOffice, Excel, Lotus, etc. Esta funcionalidad nos permite agrupar, ordenar, calcular datos y manejar datos de una forma muy similar a la que se hace con las hojas de cálculo. mas informacion

La principal función del “Pivot_table” son las agrupaciones de datos a las que se les suelen aplicar funciones matemáticas como sumatorios, promedios, etc

import seaborn as sns # importar la libreria seaborn
# cargar dataset del titanic
titanic = sns.load_dataset('titanic')
titanic.head()

survivedpclasssexagesibspparchfareembarkedclasswhoadult_maledeckembark_townalivealone
003male22.0107.2500SThirdmanTrueNaNSouthamptonnoFalse
111female38.01071.2833CFirstwomanFalseCCherbourgyesFalse
213female26.0007.9250SThirdwomanFalseNaNSouthamptonyesTrue
311female35.01053.1000SFirstwomanFalseCSouthamptonyesFalse
403male35.0008.0500SThirdmanTrueNaNSouthamptonnoTrue

Haciendo el Pivot table a mano para obtener el promedio de personas que sobrevivieron por genero

# 1. Agrupar por genero
# 2. Obtener los sobrevivientes
# 3. Calcular el promedio
titanic.groupby('sex')[['survived']].mean()

survived
sex
female0.742038
male0.188908

promedio de cuantos sobrevivieron por genero divididos por clase

# 1. Agrupar por genero y clase
# 2. Obtener los sobrevivientes
# 3. Calcular el promedio
# 4. Poner el resultado como una tabla (.unstack)
titanic.groupby(['sex', 'class'])['survived'].mean().unstack()

classFirstSecondThird
sex
female0.9680850.9210530.500000
male0.3688520.1574070.135447

Usando Pivot tables

titanic.pivot_table('survived', index='sex', columns='class')

classFirstSecondThird
sex
female0.9680850.9210530.500000
male0.3688520.1574070.135447
titanic.pivot_table('survived', index='sex', columns='class', margins=True)

classFirstSecondThirdAll
sex
female0.9680850.9210530.5000000.742038
male0.3688520.1574070.1354470.188908
All0.6296300.4728260.2423630.383838

Concatenar, Fusionar y Unir (Concatenating, Merging, Joining)

Hay 3 formas principales de combinar DataFrames: concatenar, fusionar y unir.

# DataFrames de ejemplo para concatenacion
import pandas as pd
df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
                        'B': ['B0', 'B1', 'B2', 'B3'],
                        'C': ['C0', 'C1', 'C2', 'C3'],
                        'D': ['D0', 'D1', 'D2', 'D3']},
                        index=[0, 1, 2, 3])
df2 = pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'],
                        'B': ['B4', 'B5', 'B6', 'B7'],
                        'C': ['C4', 'C5', 'C6', 'C7'],
                        'D': ['D4', 'D5', 'D6', 'D7']},
                         index=[4, 5, 6, 7])
df3 = pd.DataFrame({'A': ['A8', 'A9', 'A10', 'A11'],
                        'B': ['B8', 'B9', 'B10', 'B11'],
                        'C': ['C8', 'C9', 'C10', 'C11'],
                        'D': ['D8', 'D9', 'D10', 'D11']},
                        index=[8, 9, 10, 11])
df1

ABCD
0A0B0C0D0
1A1B1C1D1
2A2B2C2D2
3A3B3C3D3
df2

ABCD
4A4B4C4D4
5A5B5C5D5
6A6B6C6D6
7A7B7C7D7
df3

ABCD
8A8B8C8D8
9A9B9C9D9
10A10B10C10D10
11A11B11C11D11

Concatenacion (Concatenation)

La concatenación básicamente combina DataFrames. Tenga en cuenta que las dimensiones deben coincidir a lo largo del eje con el que se está concatenando.

la concatenacion se hace con dataframes de diferentes indices

Puede usar .concat() y pasar una lista de DataFrames para concatenar juntos:

# Concatenar cada dateframe verticalmente,
# ya que coinciden los nombres de las columnas

pd.concat([df1,df2,df3], axis='index')

ABCD
0A0B0C0D0
1A1B1C1D1
2A2B2C2D2
3A3B3C3D3
4A4B4C4D4
5A5B5C5D5
6A6B6C6D6
7A7B7C7D7
8A8B8C8D8
9A9B9C9D9
10A10B10C10D10
11A11B11C11D11
#concatenar dataframe horizontalmente,
# como no coinciden los index observar lo que ocurre

pd.concat([df1,df2,df3], axis='columns')

ABCDABCDABCD
0A0B0C0D0NaNNaNNaNNaNNaNNaNNaNNaN
1A1B1C1D1NaNNaNNaNNaNNaNNaNNaNNaN
2A2B2C2D2NaNNaNNaNNaNNaNNaNNaNNaN
3A3B3C3D3NaNNaNNaNNaNNaNNaNNaNNaN
4NaNNaNNaNNaNA4B4C4D4NaNNaNNaNNaN
5NaNNaNNaNNaNA5B5C5D5NaNNaNNaNNaN
6NaNNaNNaNNaNA6B6C6D6NaNNaNNaNNaN
7NaNNaNNaNNaNA7B7C7D7NaNNaNNaNNaN
8NaNNaNNaNNaNNaNNaNNaNNaNA8B8C8D8
9NaNNaNNaNNaNNaNNaNNaNNaNA9B9C9D9
10NaNNaNNaNNaNNaNNaNNaNNaNA10B10C10D10
11NaNNaNNaNNaNNaNNaNNaNNaNA11B11C11D11

Fusion (Merging)

La función merge() le permite fusionar DataFrames juntos utilizando una lógica similar a la combinación de Tablas SQL. Por ejemplo:

# DataFrames de ejemplo para merging
left = pd.DataFrame({
    'Producto': ['Arepas', 'Banano', 'Cafe'],
    'Tienda': [1, 2, 1],
    'Ventas': [100, 200, 50]
})

right = pd.DataFrame({
    'Producto': ['Arepas', 'Banano', 'Cafe'],
    'Tienda': [1, 2, 1],
    'Inventario': [50, 100, 75]
})
left

ProductoTiendaVentas
0Arepas1100
1Banano2200
2Cafe150
right

ProductoTiendaInventario
0Arepas150
1Banano2100
2Cafe175
# how='inner' utilice la intersección de las claves de ambos marcos, similar a una combinación interna de SQL;
# las keys son comunes
pd.merge(left,right,how='inner',on='Producto')

ProductoTienda_xVentasTienda_yInventario
0Arepas1100150
1Banano22002100
2Cafe150175

Un ejemplo mas complicado:

  • Natural join: para mantener solo las filas que coinciden con los marcos de datos, especifique el argumento how = ‘inner’.
  • Full outer join: para mantener todas las filas de ambos dataframe, especifique how = ‘OUTER’.
  • Left outer join: para incluir todas las filas de su dataframe x y solo aquellas de y que coincidan, especifique how=‘left’.
  • Right outer join: para incluir todas las filas de su dataframe y y solo aquellas de x que coincidan, especifique how=‘right’.

left = pd.DataFrame({
    'Producto': ['Arepas', 'Leche', 'Cafe'],
    'Tienda': [1, 2, 1],
    'Ventas': [100, 200, 50]
})

right = pd.DataFrame({
    'Producto': ['Arepas', 'Banano', 'Cafe'],
    'Tienda': [1, 2, 1],
    'Inventario': [50, 100, 75]
})
left

ProductoTiendaVentas
0Arepas1100
1Leche2200
2Cafe150
right

ProductoTiendaInventario
0Arepas150
1Banano2100
2Cafe175
# fusionando comparando las mismas claves que tengan comunes
pd.merge(left, right, on=['Producto'])

ProductoTienda_xVentasTienda_yInventario
0Arepas1100150
1Cafe150175
# fusionando totalmente las dos tablas con las claves
pd.merge(left, right, how='outer', on=['Producto'])

ProductoTienda_xVentasTienda_yInventario
0Arepas1.0100.01.050.0
1Leche2.0200.0NaNNaN
2Cafe1.050.01.075.0
3BananoNaNNaN2.0100.0
# fusionando usando las claves de la tabla right
pd.merge(left, right, how='right', on=['Producto'])

ProductoTienda_xVentasTienda_yInventario
0Arepas1.0100.0150
1BananoNaNNaN2100
2Cafe1.050.0175
# fusionando usando las claves de la tabla left
pd.merge(left, right, how='left', on=['Producto'])

ProductoTienda_xVentasTienda_yInventario
0Arepas11001.050.0
1Leche2200NaNNaN
2Cafe1501.075.0

Datos Categoricos

  • La busqueda en datos categoricos es mucho mas rapida
  • Ocupan Menos memoria que si los datos estan como string
  • Se pueden tener datos categoricos Ordinales

Mas informacion de datos categoricos:

https://pandas.pydata.org/pandas-docs/stable/user_guide/categorical.html

Creacion

# Creacion de una serie de datos categoricos
cate = pd.Series(["manzana", "banano", "corozo", "manzana","pera"],
                 dtype="category")
cate
0    manzana
1     banano
2     corozo
3    manzana
4       pera
dtype: category
Categories (4, object): ['banano', 'corozo', 'manzana', 'pera']
cate.dtypes
CategoricalDtype(categories=['banano', 'corozo', 'manzana', 'pera'], ordered=False)
cate.describe()
count           5
unique          4
top       manzana
freq            2
dtype: object
# Creando primero los datos y luego convirtiendolos en categoricos
df_cate = pd.DataFrame({"Fruta":["manzana", "banano", "corozo", "manzana","pera"]})
df_cate

Fruta
0manzana
1banano
2corozo
3manzana
4pera
# Observar los tipos de datos en el data frame
df_cate.dtypes
Fruta    object
dtype: object
df_cate["Fruta2"] = df_cate["Fruta"].astype('category')
df_cate

FrutaFruta2
0manzanamanzana
1bananobanano
2corozocorozo
3manzanamanzana
4perapera
# Observar los tipos de datos en el dataframe
df_cate.dtypes
Fruta       object
Fruta2    category
dtype: object
# Crear los datos categoricos desde a declaracion de los datos
df_cate = pd.DataFrame({'A': list('abca'),
                        'B': list('bccd')},
                       dtype="category")
df_cate

AB
0ab
1bc
2cc
3ad
df_cate.dtypes
A    category
B    category
dtype: object
df_cate.describe()

AB
count44
unique33
topac
freq22

Categoricos Ordinales

# creacion de dataframe con datos
df_cate = pd.DataFrame({'A': list('abca'),
                        'B': list('bccd')})
df_cate

AB
0ab
1bc
2cc
3ad
df_cate.dtypes
A    object
B    object
dtype: object
# Definicion de los tipos de datos y que estan en orden
df_cate["A"] = pd.Categorical(df_cate['A'],
                              categories=['a','b','c','d'],
                              ordered=True)
df_cate

AB
0ab
1bc
2cc
3ad
df_cate["A"]
0    a
1    b
2    c
3    a
Name: A, dtype: category
Categories (4, object): ['a' < 'b' < 'c' < 'd']
# Los datos no tienen que ser strings para que sean categoricos
s = pd.Series([1, 2, 3, 1], dtype="category")
s
0    1
1    2
2    3
3    1
dtype: category
Categories (3, int64): [1, 2, 3]
s = s.cat.set_categories([2, 3, 1],
                         ordered=True)
s
0    1
1    2
2    3
3    1
dtype: category
Categories (3, int64): [2 < 3 < 1]

Correcion de tipos de datos (Casting)

Cuando se trabaja con datos, es posible que se encuentre con un DataFrame donde el tipo de datos de una columna no es la correcta. los tipos de datos son principalmente: numericos, categoricos nominales, categoricos ordinales, booleanos, fechas y tiempos, texto.

Se debe convertir los tipos de datos para que sean apropiados para el tipo de datos que representan. Por ejemplo, es posible que desee convertir una columna de strings que representan números en números enteros o flotantes. O puede tener una columna de números que representan fechas, pero que pandas no reconoce como fechas.

Nota: al convertir los datos a su forma correcta, normalmente hace que los DataFrames sean mucho más pequeños en la memoria, lo que los hace más eficientes de usar.

import seaborn as sns # importar la libreria seaborn
titanic = sns.load_dataset('titanic')
titanic.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 15 columns):
 #   Column       Non-Null Count  Dtype
---  ------       --------------  -----
 0   survived     891 non-null    int64
 1   pclass       891 non-null    int64
 2   sex          891 non-null    object
 3   age          714 non-null    float64
 4   sibsp        891 non-null    int64
 5   parch        891 non-null    int64
 6   fare         891 non-null    float64
 7   embarked     889 non-null    object
 8   class        891 non-null    category
 9   who          891 non-null    object
 10  adult_male   891 non-null    bool
 11  deck         203 non-null    category
 12  embark_town  889 non-null    object
 13  alive        891 non-null    object
 14  alone        891 non-null    bool
dtypes: bool(2), category(2), float64(2), int64(4), object(5)
memory usage: 80.7+ KB
titanic.sample(5)

survivedpclasssexagesibspparchfareembarkedclasswhoadult_maledeckembark_townalivealone
13901male24.00079.2000CFirstmanTrueBCherbourgnoTrue
54803male33.01120.5250SThirdmanTrueNaNSouthamptonnoFalse
3213femaleNaN007.7500QThirdwomanFalseNaNQueenstownyesTrue
3613maleNaN007.2292CThirdmanTrueNaNCherbourgyesTrue
72411male27.01053.1000SFirstmanTrueESouthamptonyesFalse

Casting variables Categoricas nominales

# convertir la columna sex, embarked, who, embark_town en categoricas
cols_categoricas_nom = ["sex", "embarked", "who", "embark_town"]

# ver los datos unicos de las columnas_categoricas_nom
for columna in cols_categoricas_nom:
  print(f"Valores únicos en {columna}: {titanic[columna].unique()}")
Valores únicos en sex: ['male' 'female']
Valores únicos en embarked: ['S' 'C' 'Q' nan]
Valores únicos en who: ['man' 'woman' 'child']
Valores únicos en embark_town: ['Southampton' 'Cherbourg' 'Queenstown' nan]
titanic[cols_categoricas_nom] = titanic[cols_categoricas_nom].astype("category")

# ver los datos unicos de las columnas_categoricas_nom
for columna in cols_categoricas_nom:
  print(f"Valores únicos en {columna}: {titanic[columna].unique()}")
Valores únicos en sex: ['male', 'female']
Categories (2, object): ['female', 'male']
Valores únicos en embarked: ['S', 'C', 'Q', NaN]
Categories (3, object): ['C', 'Q', 'S']
Valores únicos en who: ['man', 'woman', 'child']
Categories (3, object): ['child', 'man', 'woman']
Valores únicos en embark_town: ['Southampton', 'Cherbourg', 'Queenstown', NaN]
Categories (3, object): ['Cherbourg', 'Queenstown', 'Southampton']

Casting variables Categoricas Ordinales

cols_categoricas_ord = ["pclass", "deck"]

for columna in cols_categoricas_ord:
  print(f"Valores únicos en {columna}: {titanic[columna].unique()}")
Valores únicos en pclass: [3 1 2]
Valores únicos en deck: [NaN, 'C', 'E', 'G', 'D', 'A', 'B', 'F']
Categories (7, object): ['A', 'B', 'C', 'D', 'E', 'F', 'G']
titanic["pclass"] = pd.Categorical(titanic["pclass"],
                                   categories=[3, 2, 1],
                                   ordered=True)
titanic["deck"] = pd.Categorical(titanic["deck"],
                                 categories=list("ABCDEFG"),
                                 ordered=True)
for columna in cols_categoricas_ord:
  print(f"Valores únicos en {columna}: {titanic[columna].unique()}")
Valores únicos en pclass: [3, 1, 2]
Categories (3, int64): [3 < 2 < 1]
Valores únicos en deck: [NaN, 'C', 'E', 'G', 'D', 'A', 'B', 'F']
Categories (7, object): ['A' < 'B' < 'C' < 'D' < 'E' < 'F' < 'G']

Casting variables booleanas

columnas_bool = ["alive", "alone", "survived"]

titanic[columnas_bool] = titanic[columnas_bool].astype("bool")

Resulado Casting

titanic.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 15 columns):
 #   Column       Non-Null Count  Dtype
---  ------       --------------  -----
 0   survived     891 non-null    bool
 1   pclass       891 non-null    category
 2   sex          891 non-null    category
 3   age          714 non-null    float64
 4   sibsp        891 non-null    int64
 5   parch        891 non-null    int64
 6   fare         891 non-null    float64
 7   embarked     889 non-null    category
 8   class        891 non-null    category
 9   who          891 non-null    category
 10  adult_male   891 non-null    bool
 11  deck         203 non-null    category
 12  embark_town  889 non-null    category
 13  alive        891 non-null    bool
 14  alone        891 non-null    bool
dtypes: bool(4), category(7), float64(2), int64(2)
memory usage: 38.7 KB

Datos Faltantes (Missing data)

Métodos para Manejar datos faltantes en pandas:

# Declaracion de data frame con algunos datos faltantes
# NaN = Not a Number
df = pd.DataFrame({'A':[1,2,np.nan],
                  'B':[5,np.nan,np.nan],
                  'C':[1,2,3]})
df

ABC
01.05.01
12.0NaN2
2NaNNaN3

Detectar si Faltan datos

# verificar cuales valores son NaN o nulos (Null)
df.isna()

ABC
0FalseFalseFalse
1FalseTrueFalse
2TrueTrueFalse
# Verificar si hay datos faltantes por columna
df.isna().any()
A     True
B     True
C    False
dtype: bool

Numero de datos faltantes

Calcular el numero de datos nulos que hay por columna

# Numero de datos faltantes por columna
df.isna().sum()
A    1
B    2
C    0
dtype: int64

Eliminar datos Faltantes

# Eliminar todas las filas que tengan datos faltantes
df.dropna(axis='index') # cuando son filas no es neceario escribir axis=0

ABC
01.05.01
# Eliminar todas las columnas que tengan datos faltantes
df.dropna(axis='columns')

C
01
12
23
# eliminar las filas que tengas 2 o mas valores NaN
df.dropna(thresh=2)

ABC
01.05.01
12.0NaN2

Reemplazar los datos faltantes

# Llenar los datos faltantes con el dato que nos interese
df.fillna(value='Llenar Valores') # llenar los espacios con un string
                              # puede ser una palabra, numero , etc

ABC
01.05.01
12.0Llenar Valores2
2Llenar ValoresLlenar Valores3
# Llenar los datos faltantes con el dato que nos interese
df.fillna(value=99) # llenar los espacios con un numero

ABC
01.05.01
12.099.02
299.099.03
# Llenar los datos faltantes con el promedio de esa columna
df['A'].fillna(value=df['A'].mean())
0    1.0
1    2.0
2    1.5
Name: A, dtype: float64
# Llenar los datos faltantes con el promedio de cada columna
df.fillna(value=df.mean())

ABC
01.05.01
12.05.02
21.55.03

Datos unicos (Unique Values)

import pandas as pd
# crear un dataframe
df = pd.DataFrame({'col1':[1,2,3,4],
                   'col2':[444,555,666,444],
                   'col3':['abc','def','ghi','xyz']})
df.head() # solamente mostrar los primeros elementos del dataframe

col1col2col3
01444abc
12555def
23666ghi
34444xyz
# valores unicos de la columna col2
df['col2'].unique()
array([444, 555, 666])
# Numero de valores unicos en el dataframe
df['col2'].nunique()
3
# contar cuanto se repiten cada uno de los valores
df['col2'].value_counts()
col2
444    2
555    1
666    1
Name: count, dtype: int64

Datos Duplicados

Se puede borrar los registros que son exactamente iguales en todos los valores de las columnas

import pandas as pd
datos = {'nombre': ['Jaime', 'Juan', 'Roberto', 'Juan'],
         'edad': [18, 20, 22, 20],
         'trabajo': ['Asistente', 'Manager', 'Cientifico', 'Manager']}
df_dup = pd.DataFrame(datos)
df_dup

nombreedadtrabajo
0Jaime18Asistente
1Juan20Manager
2Roberto22Cientifico
3Juan20Manager
# Metodo para detectar los datos duplicados
# me sirve para ver si existen registros duplicados
df_dup.duplicated()
0    False
1    False
2    False
3     True
dtype: bool
# Contar cuantos datos duplicados existen
df_dup.duplicated().sum()
1
# Para remover los datos duplicados
df_dup.drop_duplicates()

nombreedadtrabajo
0Jaime18Asistente
1Juan20Manager
2Roberto22Cientifico
# El metodo drop_duplicates entrega el data frame sin duplicados
# Pero la funcion no es inplace, osea que el dataframe original sigue igual
df_dup

nombreedadtrabajo
0Jaime18Asistente
1Juan20Manager
2Roberto22Cientifico
3Juan20Manager
df_dup.drop_duplicates(inplace=True)
df_dup

nombreedadtrabajo
0Jaime18Asistente
1Juan20Manager
2Roberto22Cientifico

Duplicados por Columna

Se pueden borrar los valores que se repitan solamente verificando la columna

frame_datos = {'nombre': ['Jaime', 'Juan', 'Roberto', 'Juan'],
               'edad': [18, 20, 22, 21],
              'trabajo': ['Asistente', 'Manager', 'Cientifico', 'Profesor']}
df_dup = pd.DataFrame(frame_datos)
df_dup

nombreedadtrabajo
0Jaime18Asistente
1Juan20Manager
2Roberto22Cientifico
3Juan21Profesor

el valor de jason esta duplicado en la columna name

# recordar que estas funciones no son inplace
df_dup.drop_duplicates(['nombre'])

nombreedadtrabajo
0Jaime18Asistente
1Juan20Manager
2Roberto22Cientifico

Outliers

Una de las formas de eliminar los outliers es identificando cual sera el rango en el que queremos nuestros datos y limitar los datos entre ese rango

import seaborn as sns # importar la libreria seaborn
# cargar dataset del titanic
titanic = sns.load_dataset('titanic')
titanic.head()

survivedpclasssexagesibspparchfareembarkedclasswhoadult_maledeckembark_townalivealone
003male22.0107.2500SThirdmanTrueNaNSouthamptonnoFalse
111female38.01071.2833CFirstwomanFalseCCherbourgyesFalse
213female26.0007.9250SThirdwomanFalseNaNSouthamptonyesTrue
311female35.01053.1000SFirstwomanFalseCSouthamptonyesFalse
403male35.0008.0500SThirdmanTrueNaNSouthamptonnoTrue
edad = titanic['age']
edad
0      22.0
1      38.0
2      26.0
3      35.0
4      35.0
       ...
886    27.0
887    19.0
888     NaN
889    26.0
890    32.0
Name: age, Length: 891, dtype: float64
# Cual es la edad maxima
edad.max()
80.0
# Cual es la edad Minima
edad.min()
0.42

Solo por hacer el ejercicio se delimitaran las edades entre 1 y 70 años

esto se puede hacer con el metodo .clip(lower = Valor mas bajo, upper = valor mas alto)

edad = edad.clip(lower=1,upper = 70)
edad.max()
70.0
edad.min()
1.0

Tablas de Contingencia (two way tables)

# Crear Datos
raw_data = {'regiment': ['Nighthawks', 'Nighthawks', 'Nighthawks', 'Nighthawks', 'Dragoons', 'Dragoons', 'Dragoons', 'Dragoons', 'Scouts', 'Scouts', 'Scouts', 'Scouts'],
        'company': ['infantry', 'infantry', 'cavalry', 'cavalry', 'infantry', 'infantry', 'cavalry', 'cavalry','infantry', 'infantry', 'cavalry', 'cavalry'],
        'experience': ['veteran', 'rookie', 'veteran', 'rookie', 'veteran', 'rookie', 'veteran', 'rookie','veteran', 'rookie', 'veteran', 'rookie'],
        'name': ['Miller', 'Jacobson', 'Ali', 'Milner', 'Cooze', 'Jacon', 'Ryaner', 'Sone', 'Sloan', 'Piger', 'Riani', 'Ali'],
        'preTestScore': [4, 24, 31, 2, 3, 4, 24, 31, 2, 3, 2, 3],
        'postTestScore': [25, 94, 57, 62, 70, 25, 94, 57, 62, 70, 62, 70]}
df = pd.DataFrame(raw_data, columns = ['regiment', 'company', 'experience', 'name', 'preTestScore', 'postTestScore'])
df

regimentcompanyexperiencenamepreTestScorepostTestScore
0NighthawksinfantryveteranMiller425
1NighthawksinfantryrookieJacobson2494
2NighthawkscavalryveteranAli3157
3NighthawkscavalryrookieMilner262
4DragoonsinfantryveteranCooze370
5DragoonsinfantryrookieJacon425
6DragoonscavalryveteranRyaner2494
7DragoonscavalryrookieSone3157
8ScoutsinfantryveteranSloan262
9ScoutsinfantryrookiePiger370
10ScoutscavalryveteranRiani262
11ScoutscavalryrookieAli370
# Tabla de contingencia por compañía y regimiento
pd.crosstab(df['regiment'], df['company'], margins=True)

companycavalryinfantryAll
regiment
Dragoons224
Nighthawks224
Scouts224
All6612
# Tabla de contingencia de compañia y experiencia por regimiento
pd.crosstab([df['company'], df['experience']], df['regiment'],  margins=True)

regimentDragoonsNighthawksScoutsAll
companyexperience
cavalryrookie1113
veteran1113
infantryrookie1113
veteran1113
All44412

Metodos y Funciones en Pandas

Todos los metodos de los dataframe de pandas se pueden encontrar en:

http://pandas.pydata.org/pandas-docs/stable/reference/frame.html

import pandas as pd
# crear un dataframe
df = pd.DataFrame({'col1':[1,2,3,4],
                   'col2':[444,555,666,444],
                   'col3':['mama   ','  papa','   HIJO  ','HiJa']})
df.head() # solamente mostrar los primeros elementos del dataframe

col1col2col3
01444mama
12555papa
23666HIJO
34444HiJa

Metodos Basicos Pandas

Ejemplos simples de los metodos de los dataframe de pandas

Para informacion completa de los metodos de computacion y estadisticos ver:

http://pandas.pydata.org/pandas-docs/stable/reference/frame.html#computations-descriptive-stats

# Suma total de cada Columna, si es categorico no lo suma
df.sum()
col1                            10
col2                          2109
col3    mama     papa   HIJO  HiJa
dtype: object
# Metodo en una sola columna
df['col1'].sum()
10
# Metodo en varias columnas
df[['col1','col2']].sum()
col1      10
col2    2109
dtype: int64
# Valor Minimo cada Columna
df.min()
col1            1
col2          444
col3       HIJO
dtype: object
# Valor Maximo cada Columna
df.max()
col1          4
col2        666
col3    mama
dtype: object

Metodos de Informacion General

# Cargar la base de datos 'mpg' de la libreria seaborn
import seaborn as sns

# los datos se cargan en un dataframe
data = sns.load_dataset('mpg')
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 398 entries, 0 to 397
Data columns (total 9 columns):
 #   Column        Non-Null Count  Dtype
---  ------        --------------  -----
 0   mpg           398 non-null    float64
 1   cylinders     398 non-null    int64
 2   displacement  398 non-null    float64
 3   horsepower    392 non-null    float64
 4   weight        398 non-null    int64
 5   acceleration  398 non-null    float64
 6   model_year    398 non-null    int64
 7   origin        398 non-null    object
 8   name          398 non-null    object
dtypes: float64(4), int64(3), object(2)
memory usage: 28.1+ KB
data.head()

mpgcylindersdisplacementhorsepowerweightaccelerationmodel_yearoriginname
018.08307.0130.0350412.070usachevrolet chevelle malibu
115.08350.0165.0369311.570usabuick skylark 320
218.08318.0150.0343611.070usaplymouth satellite
316.08304.0150.0343312.070usaamc rebel sst
417.08302.0140.0344910.570usaford torino
data.describe() # ver datos estadisticos de las columnas numericas

mpgcylindersdisplacementhorsepowerweightaccelerationmodel_year
count398.000000398.000000398.000000392.000000398.000000398.000000398.000000
mean23.5145735.454774193.425879104.4693882970.42462315.56809076.010050
std7.8159841.701004104.26983838.491160846.8417742.7576893.697627
min9.0000003.00000068.00000046.0000001613.0000008.00000070.000000
25%17.5000004.000000104.25000075.0000002223.75000013.82500073.000000
50%23.0000004.000000148.50000093.5000002803.50000015.50000076.000000
75%29.0000008.000000262.000000126.0000003608.00000017.17500079.000000
max46.6000008.000000455.000000230.0000005140.00000024.80000082.000000
data.describe(include = 'all') # ver todos los datos incluidos los categoricos

mpgcylindersdisplacementhorsepowerweightaccelerationmodel_yearoriginname
count398.000000398.000000398.000000392.000000398.000000398.000000398.000000398398
uniqueNaNNaNNaNNaNNaNNaNNaN3305
topNaNNaNNaNNaNNaNNaNNaNusaford pinto
freqNaNNaNNaNNaNNaNNaNNaN2496
mean23.5145735.454774193.425879104.4693882970.42462315.56809076.010050NaNNaN
std7.8159841.701004104.26983838.491160846.8417742.7576893.697627NaNNaN
min9.0000003.00000068.00000046.0000001613.0000008.00000070.000000NaNNaN
25%17.5000004.000000104.25000075.0000002223.75000013.82500073.000000NaNNaN
50%23.0000004.000000148.50000093.5000002803.50000015.50000076.000000NaNNaN
75%29.0000008.000000262.000000126.0000003608.00000017.17500079.000000NaNNaN
max46.6000008.000000455.000000230.0000005140.00000024.80000082.000000NaNNaN
# Descripcion de una sola columna
data['cylinders'].describe()
count    398.000000
mean       5.454774
std        1.701004
min        3.000000
25%        4.000000
50%        4.000000
75%        8.000000
max        8.000000
Name: cylinders, dtype: float64
data['mpg'].describe()
count    398.000000
mean      23.514573
std        7.815984
min        9.000000
25%       17.500000
50%       23.000000
75%       29.000000
max       46.600000
Name: mpg, dtype: float64
data['cylinders'].dtypes
dtype('int64')

Estadistica Descriptiva

Metodos de Estadistica Descriptiva, de medida central, simetria, momentos, etc. para mas informacion: http://pandas.pydata.org/pandas-docs/stable/reference/frame.html#computations-descriptive-stats

Los calculos de las medidas estadisticas se hacen siempre en columnas, es algo predeterminado, si se quiere hacer por filas, se debe especificar dentro de los metodos el parametro axis=1.

Ejemplo:

  • Calculo de la media por columnas (predeterminado) = df.mean()
  • Calculo de la media por filas = df.mean(axis='columns')

Esto funciona con los otros tipos de medidas estadisticas

# Se tomara la columna 'mpg' para realizar los calculos
X = data['mpg']
type(X)
pandas.core.series.Series

Medidas de centralizacion

estas funciones se aplican sobre un dataframe de pandas

Media

# Media Aritmetica
X.mean()
23.514572864321607
# Media aritmetica en un dataframe
data.mean(numeric_only=True)
mpg               23.514573
cylinders          5.454774
displacement     193.425879
horsepower       104.469388
weight          2970.424623
acceleration      15.568090
model_year        76.010050
dtype: float64

Mediana

# Mediana
X.median()
23.0
# Mediana en un dataframe
data.median(numeric_only=True)
mpg               23.0
cylinders          4.0
displacement     148.5
horsepower        93.5
weight          2803.5
acceleration      15.5
model_year        76.0
dtype: float64

Maximo y Minimo

# Maximo
X.max()
46.6
# Maximo en un dataframe
data.max()
mpg                         46.6
cylinders                      8
displacement               455.0
horsepower                 230.0
weight                      5140
acceleration                24.8
model_year                    82
origin                       usa
name            vw rabbit custom
dtype: object
# Minimo
X.min()
9.0
# Minimo en un dataframe
data.min()
mpg                                 9.0
cylinders                             3
displacement                       68.0
horsepower                         46.0
weight                             1613
acceleration                        8.0
model_year                           70
origin                           europe
name            amc ambassador brougham
dtype: object

Moda

# Moda
X.mode()
0    13.0
Name: mpg, dtype: float64
# Moda en un dataframe
data.mode()

mpgcylindersdisplacementhorsepowerweightaccelerationmodel_yearoriginname
013.04.097.0150.0198514.573.0usaford pinto
1NaNNaNNaNNaN2130NaNNaNNaNNaN

Cuartiles

# Valores de los cuartiles
X.quantile([0, .25, .5, .75, 1])
0.00     9.0
0.25    17.5
0.50    23.0
0.75    29.0
1.00    46.6
Name: mpg, dtype: float64
# Valores de los cuartiles en un dataframe
data.quantile([0, 0.25, 0.5, 0.75, 1], numeric_only=True)

mpgcylindersdisplacementhorsepowerweightaccelerationmodel_year
0.009.03.068.0046.01613.008.00070.0
0.2517.54.0104.2575.02223.7513.82573.0
0.5023.04.0148.5093.52803.5015.50076.0
0.7529.08.0262.00126.03608.0017.17579.0
1.0046.68.0455.00230.05140.0024.80082.0

Medidas de dispersion

Varianza

# Varianza
X.var() #unbiased Normalized by N-1 by default.
61.089610774274405
# Varianza en un dataframe
data.var(numeric_only=True)
mpg                 61.089611
cylinders            2.893415
displacement     10872.199152
horsepower        1481.569393
weight          717140.990526
acceleration         7.604848
model_year          13.672443
dtype: float64

Desviacion Estandard

# Desviacion tipica o desviacion estandard
X.std()
7.815984312565782
# Desviacion tipica o desviacion estandard en un dataframe
data.std(numeric_only=True)
mpg               7.815984
cylinders         1.701004
displacement    104.269838
horsepower       38.491160
weight          846.841774
acceleration      2.757689
model_year        3.697627
dtype: float64

Coeficiente de Variacion

# Coeficiente de Variacion
X.std(numeric_only=True) / X.mean(numeric_only=True)
0.33238895546450203

Medidas de Asimetria

Asimetria de Fisher (skewness)

La asimetría es la medida que indica la simetría de la distribución de una variable respecto a la media aritmética, sin necesidad de hacer la representación gráfica. Los coeficientes de asimetría indican si hay el mismo número de elementos a izquierda y derecha de la media.

Existen tres tipos de curva de distribución según su asimetría:

  • Asimetría negativa: la cola de la distribución se alarga para valores inferiores a la media.
  • Simétrica: hay el mismo número de elementos a izquierda y derecha de la media. En este caso, coinciden la media, la mediana y la moda. La distribución se adapta a la forma de la campana de Gauss, o distribución normal.
  • Asimetría positiva: la cola de la distribución se alarga para valores superiores a la media.

#unbiased skew, Normalized by N-1
X.skew()
0.45706634399491913
# unbiased skew, Normalized by N-1 en un dataframe
data.skew(numeric_only=True)
mpg             0.457066
cylinders       0.526922
displacement    0.719645
horsepower      1.087326
weight          0.531063
acceleration    0.278777
model_year      0.011535
dtype: float64

Curtosis

Esta medida determina el grado de concentración que presentan los valores en la región central de la distribución. Por medio del Coeficiente de Curtosis, podemos identificar si existe una gran concentración de valores (Leptocúrtica), una concentración normal (Mesocúrtica) ó una baja concentración (Platicúrtica).

# unbiased kurtosis over requested axis using Fisher's definition
X.kurtosis()
-0.5107812652123154
# unbiased kurtosis over requested axis using Fisher's definition
# en un dataframe
data.kurtosis(numeric_only=True)
mpg            -0.510781
cylinders      -1.376662
displacement   -0.746597
horsepower      0.696947
weight         -0.785529
acceleration    0.419497
model_year     -1.181232
dtype: float64

Covarianza

Entre Series

s1 = pd.Series(np.random.randn(1000))
s2 = pd.Series(np.random.randn(1000))
s1.cov(s2)
-0.025094639027196358
# Numpy
np.cov(s1,s2)
array([[ 0.95048876, -0.02509464],
       [-0.02509464,  0.97241405]])

Dataframe

frame = pd.DataFrame(np.random.randn(1000, 5),columns=['a', 'b', 'c', 'd', 'e'])
frame.head()

abcde
00.499849-0.0940941.604184-1.0807161.031231
10.776868-0.0560330.590348-0.0229560.031928
2-1.4483700.0830800.559249-0.902921-0.222358
3-1.0422271.045355-0.1689180.3614340.150148
4-1.428764-1.904445-2.0166041.077732-0.853357
frame.cov()

abcde
a1.009833-0.0203530.011463-0.008649-0.090720
b-0.0203531.015555-0.070017-0.0000550.019908
c0.011463-0.0700171.022689-0.035151-0.023407
d-0.008649-0.000055-0.0351511.0015580.025479
e-0.0907200.019908-0.0234070.0254790.979957

Correlacion

Metodos:

  • pearson (predeterminado)
  • kendall
  • spearman
#  Creacion de dataframe con datos aleatorios
frame = pd.DataFrame(np.random.randn(1000, 5),
                     columns=['a', 'b', 'c', 'd', 'e'])
frame.head()

abcde
00.2073811.1401070.291974-1.0271030.806736
1-1.296042-0.506816-0.6106550.174875-0.023277
20.0976340.0891462.0391741.950184-1.713418
31.854029-0.337418-1.0758060.0066621.396997
40.813020-0.638845-0.038826-0.3042830.758953

Entre Series

frame['a'].corr(frame['b']) # Pearson que es el predeterminado
0.05612539367834173
frame['a'].corr(frame['b'], method='spearman') # Metodo spearman
0.04815865215865216
frame['a'].corr(frame['b'], method='kendall') # Metodo Kendall
0.03234834834834835
# Con Numpy se realiza el coefficiente de Pearson
# realiza la correlacion entre dos vectores
np.corrcoef(frame['a'],frame['b'])
array([[1.        , 0.05612539],
       [0.05612539, 1.        ]])

Dataframe

frame.corr()

abcde
a1.0000000.0561250.024210-0.005499-0.007650
b0.0561251.0000000.007777-0.009033-0.000781
c0.0242100.0077771.000000-0.001434-0.050740
d-0.005499-0.009033-0.0014341.000000-0.043050
e-0.007650-0.000781-0.050740-0.0430501.000000
# con Numpy
np.corrcoef(frame)
array([[ 1.        , -0.30647049, -0.65411155, ...,  0.29616673,
         0.29013432, -0.83433691],
       [-0.30647049,  1.        ,  0.02183588, ...,  0.71342068,
        -0.59432049, -0.22950743],
       [-0.65411155,  0.02183588,  1.        , ..., -0.66660793,
        -0.63905691,  0.61597841],
       ...,
       [ 0.29616673,  0.71342068, -0.66660793, ...,  1.        ,
        -0.0088048 , -0.63793483],
       [ 0.29013432, -0.59432049, -0.63905691, ..., -0.0088048 ,
         1.        ,  0.11039718],
       [-0.83433691, -0.22950743,  0.61597841, ..., -0.63793483,
         0.11039718,  1.        ]])

Funciones Agregadas

Para aplicar una o mas funciones en cada columna de los dataframe

df.agg(['sum', 'min'])

col1col2col3
sum102109mama papa HIJO HiJa
min1444HIJO
# Aplicar los metodos en columnas especificas
df[['col1','col2']].agg(['sum', 'min'])

col1col2
sum102109
min1444

Aplicando Funciones a cada elemento

#definicion de funcion
def times2(x:float)->float:
    return x*2
# es mas o menos lo que hace la funcion map
# aplicar la funcion times2 a cada elemento de la col1 de dataframe df
df['col1'].apply(times2)
0    2
1    4
2    6
3    8
Name: col1, dtype: int64
df['col3'].apply(len) #longitud de cada uno de los datos de la col3
0    7
1    6
2    9
3    4
Name: col3, dtype: int64
df['col1'].sum() #sumatoria total de los elementos de la col1
10

(Sorting) Ordenar un DataFrame:

df

col1col2col3
01444mama
12555papa
23666HIJO
34444HiJa
# ordenar el dataframe de menor a mayor basado en col2
df.sort_values(by='col2') #inplace=False por default

col1col2col3
01444mama
34444HiJa
12555papa
23666HIJO
df.sort_values(by='col2',ascending=False)

col1col2col3
23666HIJO
12555papa
01444mama
34444HiJa

Metodos de strings

Los metodos de los strings se pueden usar en pandas de forma vectorizada

https://pandas.pydata.org/docs/user_guide/basics.html#vectorized-string-methods

Los metodos vectorizados de los strings son:

https://pandas.pydata.org/pandas-docs/stable/user_guide/text.html#text-string-methods

Nota: Recordar que la mayoria de los metodos NO son inplace

df

col1col2col3
01444mama
12555papa
23666HIJO
34444HiJa
# Estos Metodos solo funcionan por columna (Series)
# se puede verificar el error
# df.str.lower()

Algunos ejemplos de metodos en strings en las columnas

# convertir strings en minuscula
df['col3'].str.lower()
0      mama
1         papa
2       hijo
3         hija
Name: col3, dtype: object
# convertir strings en Mayuscula
df['col3'].str.upper()
0      MAMA
1         PAPA
2       HIJO
3         HIJA
Name: col3, dtype: object
# Eliminar los espacios de los strings
df['col3'].str.strip()
0    mama
1    papa
2    HIJO
3    HiJa
Name: col3, dtype: object

Transformacion de Variables

  • Crear variables Dummy: convertir de categoría a númerica
  • Discretización o Binning: convertir de número a categoría

Columnas Dummy

Convertir variables categoricas a numericas

# crear datos categoricos
raw_data = {'first_name': ['Jason', 'Molly', 'Tina', 'Jake', 'Amy'],
        'last_name': ['Miller', 'Jacobson', 'Ali', 'Milner', 'Cooze'],
        'sex': ['male', 'female', 'male', 'female', 'female']}
df = pd.DataFrame(raw_data, columns = ['first_name', 'last_name', 'sex'])
df

first_namelast_namesex
0JasonMillermale
1MollyJacobsonfemale
2TinaAlimale
3JakeMilnerfemale
4AmyCoozefemale
# Crear un set de variables dummy para la columna sex
df_sex = pd.get_dummies(df['sex'])
df_sex

femalemale
0FalseTrue
1TrueFalse
2FalseTrue
3TrueFalse
4TrueFalse
# unir los dos dataframes
df_new = df.join(df_sex)
df_new

first_namelast_namesexfemalemale
0JasonMillermaleFalseTrue
1MollyJacobsonfemaleTrueFalse
2TinaAlimaleFalseTrue
3JakeMilnerfemaleTrueFalse
4AmyCoozefemaleTrueFalse

Discretización o Binning

Conversion de Numerica a Categorica

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.cut.html

# dividir los datos en 3 rangos iguales (categorias)

pd.cut(np.array([3.5, 2.8, 1, 5, 3, 4, 0, 4.4, 2, 3]), 3)
[(3.333, 5.0], (1.667, 3.333], (-0.005, 1.667], (3.333, 5.0], (1.667, 3.333], (3.333, 5.0], (-0.005, 1.667], (3.333, 5.0], (1.667, 3.333], (1.667, 3.333]]
Categories (3, interval[float64, right]): [(-0.005, 1.667] < (1.667, 3.333] < (3.333, 5.0]]
# Asignar etiquetas ordenadas
pd.cut(np.array([3.5, 2.8, 1, 5, 3, 4,0, 4.4, 2, 3]),
       3, labels=["Malo", "Regular", "Bien"])
['Bien', 'Regular', 'Malo', 'Bien', 'Regular', 'Bien', 'Malo', 'Bien', 'Regular', 'Regular']
Categories (3, object): ['Malo' < 'Regular' < 'Bien']
pd.cut(np.array([2, 4 , 10 , 35 , 25 , 60 , 23, 14]),
       3, labels=["Niño", "Adolescente", "Adulto"])
['Niño', 'Niño', 'Niño', 'Adolescente', 'Adolescente', 'Adulto', 'Adolescente', 'Niño']
Categories (3, object): ['Niño' < 'Adolescente' < 'Adulto']

Leer y guardar Datos (Data Input and Output)

Pandas puede leer una variedad de tipos de archivos usando sus métodos pd.read_ mas informacion

  • CSV
  • Parquet (Formato recomendado)
  • Excel
  • Json
  • Html
  • SQL

Nota: estos se ejemplos se hacen con archivos previamente creados para la demostracion

CSV File (comma-separated values)

Este es un formato muy común para compartir datos. Los archivos CSV son archivos de texto, sin formato, que usan comas para separar filas. Sus desventajas son que no especifican tipos de datos, no admiten datos faltantes, entre otros.

No es un formato ideal para compartir datos.

CSV Input

# Leer archivos separados por comas, extension .csv
df_supermarket_csv = pd.read_csv('supermarkets.csv')
df_supermarket_csv.sample(5)

IDAddressCityStateCountryNameEmployees
451056 Sanchez StSan FranciscoCaliforniaUSASanchez12
343995 23rd StSan FranciscoCA 94114USABen's Shop10
12735 Dolores StSan FranciscoCA 94119USABready Shop15
013666 21st StSan FranciscoCA 94114USAMadeira8
56551 Alvarado StSan FranciscoCA 94114USARichvalley20

CSV Output

# Grabar el dataframe como archivo separado por comas
df_supermarket_csv.to_csv('example_out.csv',index=False)

Parquet

Este es un formato de archivo binario de columna que es muy bueno para compartir datos. Es muy eficiente en el espacio y el tiempo de lectura.

Es el formato recomendado para compartir datos.

pip install pyarrow

Parquet Input

# Leer archivos separados por comas, extension .csv
df_supermarket_parquet = pd.read_parquet('supermarkets.parquet')
df_supermarket_parquet.sample(5)

IDAddressCityStateCountryNameEmployees
23332 Hill StSan FranciscoCalifornia 94114USASuper River25
013666 21st StSan FranciscoCA 94114USAMadeira8
56551 Alvarado StSan FranciscoCA 94114USARichvalley20
343995 23rd StSan FranciscoCA 94114USABen's Shop10
451056 Sanchez StSan FranciscoCaliforniaUSASanchez12

Parquet Output

# Grabar el dataframe como archivo parquet
df_supermarket_parquet.to_parquet('example_out.parquet')

Archivo de texto separado por otro caracter

# este archivo los valores estan separados por ;
df_supermarket = pd.read_csv("supermarkets-semi-colons.txt",sep=';')
df_supermarket

IDAddressCityStateCountryNameEmployees
013666 21st StSan FranciscoCA 94114USAMadeira8
12735 Dolores StSan FranciscoCA 94119USABready Shop15
23332 Hill StSan FranciscoCalifornia 94114USASuper River25
343995 23rd StSan FranciscoCA 94114USABen's Shop10
451056 Sanchez StSan FranciscoCaliforniaUSASanchez12
56551 Alvarado StSan FranciscoCA 94114USARichvalley20

Excel

Pandas puede leer y escribir archivos de Excel, tenga en cuenta que esto solo importa datos. No fórmulas o imágenes, que tengan imágenes o macros pueden hacer que este método read_excel se bloquee.

Es necesario isntalar la libreria openpyxl

pip install openpyxl

Excel Input

# leer un archivo de excel
df_supermarket_excel = pd.read_excel(
    "supermarkets.xlsx",
    sheet_name=0,  # leer la primera hoja del archivo
)
df_supermarket_excel.sample(5)

IDAddressCityStateCountrySupermarket NameNumber of Employees
013666 21st StSan FranciscoCA 94114USAMadeira8
23332 Hill StSan FranciscoCalifornia 94114USASuper River25
56551 Alvarado StSan FranciscoCA 94114USARichvalley20
451056 Sanchez StSan FranciscoCaliforniaUSASanchez12
343995 23rd StSan FranciscoCA 94114USABen's Shop10

Excel Output

df_supermarket_excel.to_excel("Excel_Sample_out.xlsx", sheet_name="Hoja1")

JSON

JSON (JavaScript Object Notation - Notación de Objetos de JavaScript) es un formato ligero de intercambio de datos. Leerlo y escribirlo es simple para humanos, mientras que para las máquinas es simple interpretarlo y generarlo.

Json Input

# los archivos pueden estar en un link de internet
df_supermarket_json = pd.read_json("http://pythonhow.com/supermarkets.json")
df_supermarket_json.sample(5)

AddressCityCountryEmployeesIDNameState
33995 23rd StSan FranciscoUSA104Ben's ShopCA 94114
2332 Hill StSan FranciscoUSA253Super RiverCalifornia 94114
03666 21st StSan FranciscoUSA81MadeiraCA 94114
41056 Sanchez StSan FranciscoUSA125SanchezCalifornia
5551 Alvarado StSan FranciscoUSA206RichvalleyCA 94114

Json output

# Para grabar
df_supermarket_json.to_json("Salida.json")

HTML

Pandas puede leer tablas de html

Es necesario instalar las librerias pip install lxml html5lib

La función pandas read_html leerá las tablas de una página web y devolverá una lista de objetos DataFrame:

data_table_web = pd.read_html(
    "https://www.runnersworld.com/races-places/a20823734/these-are-the-worlds-fastest-marathoners-and-marathon-courses/",
    header=0
)
data_table_web[0]

RunnerFinish TimePace/MileMarathon
0Kelvin Kiptum (Kenya)2:00:354:36.0Chicago, 2023
1Eliud Kipchoge (Kenya)2:01:094:37.2Berlin, 2022
2Kenenisa Bekele (Ethiopia)2:01:414:38.5Berlin, 2019
3Sisay Lemma (Ethiopia)2:01:484:38.7Valencia, 2023
4Benson Kipruto (Kenya)2:02:164:39.8Tokyo, 2024
5Birhanu Legese (Ethiopia)2:02:484:41.0Berlin, 2019
6Mosinet Geremew (Ethiopia)2:02:554:41.3London, 2019
7Timothy Kiplagat (Kenya)2:02:554:41.3Tokyo, 2024
8Dennis Kimetto (Kenya)2:02:574:41.4Berlin, 2014
9Evans Chebet (Kenya)2:03:004:41.5Valencia, 2020
data_table_web[1]

RunnerFinish TimePace/MileMarathon
0Tigist Assefa (Ethiopia)2:11:535:01.8Berlin, 2023
1Sifan Hassan (Netherlands)2:13:445:06.0Chicago, 2023
2Brigid Kosgei (Kenya)2:14:045:06.8Chicago, 2019
3NaNNaNNaNNaN
4Ruth Chepngetich (Kenya)2:14:185:07.3Chicago, 2022
5Amane Beriso (Ethiopia)2:14:585:08.9Valencia, 2022
6Paula Radcliffe (Great Britain)2:15:255:09.9London, 2003
7Worknesh Degefa (Ethiopia)2:15:515:10.9Valencia, 2023
8Sutume Kebede (Ethiopia)2:15:555:11.0Tokyo, 2024
9Tigist Ketema (Ethiopia)2:16:075:11.5Dubai, 2024
10Rosemary Wanjiru (Kenya)2:16:145:11.8Tokyo, 2024
11NaNNaNNaNNaN

SQL

El módulo pandas.io.sql proporciona una colección de contenedores de consultas para facilitar la recuperación de datos y reducir la dependencia de la API específica de DB. La abstracción de la base de datos es proporcionada por SQLAlchemy si está instalado. Además, necesitará una biblioteca de controladores para su base de datos. Ejemplos de tales controladores son psycopg2 para PostgreSQL o pymysql para MySQL. Para SQLite esto está incluido en la biblioteca estándar de Python por defecto. Puede encontrar una descripción general de los controladores admitidos para cada lenguaje SQL en los documentos de SQLAlchemy.

pip install sqlalchemy

Vea también algunos ejemplos de libros para algunas estrategias avanzadas.

las funciones claves son:

  • read_sql_table(table_name, con[, schema, …])
    • Read SQL database table into a DataFrame.
  • read_sql_query(sql, con[, index_col, …])
    • Read SQL query into a DataFrame.
  • read_sql(sql, con[, index_col, …])
    • Read SQL query or database table into a DataFrame.
  • DataFrame.to_sql(name, con[, flavor, …])
    • Write records stored in a DataFrame to a SQL database.
# librerias para crear un proceso de sql sencillo
from sqlalchemy import create_engine
# crear un proceso en memoria
engine = create_engine('sqlite:///:memory:')
data_table_web[0].to_sql("data", engine)  # grabar el dataframe en formato sql
10
sql_df = pd.read_sql('data',con=engine) # definir la conexion
sql_df

indexRunnerFinish TimePace/MileMarathon
00Kelvin Kiptum (Kenya)2:00:354:36.0Chicago, 2023
11Eliud Kipchoge (Kenya)2:01:094:37.2Berlin, 2022
22Kenenisa Bekele (Ethiopia)2:01:414:38.5Berlin, 2019
33Sisay Lemma (Ethiopia)2:01:484:38.7Valencia, 2023
44Benson Kipruto (Kenya)2:02:164:39.8Tokyo, 2024
55Birhanu Legese (Ethiopia)2:02:484:41.0Berlin, 2019
66Mosinet Geremew (Ethiopia)2:02:554:41.3London, 2019
77Timothy Kiplagat (Kenya)2:02:554:41.3Tokyo, 2024
88Dennis Kimetto (Kenya)2:02:574:41.4Berlin, 2014
99Evans Chebet (Kenya)2:03:004:41.5Valencia, 2020

Referencias

Phd. Jose R. Zapata