Pandas es una librería en cierto sentido similar a NumPy. Pero si NumPy únicamente contiene vectores, matrices, tensores ,etc junto con operaciones matemáticas. Con pandas tenemos mas cosas como nombrar a las columnas con un nombre , incluir un índices o generación de gráficas.
Mas información:
import pandas as pd
DataFrame
tipo=['SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD'] capacidad=[0.5, 0.5, 0.24, 0.48, 1, 0.512, 1, 0.48, 0.12, 0.96, 0.256, 0.512, 1, 2, 0.5, 2, 2, 1, 1.5, 4, 2, 4, 6, 5, 8, 10, 12, 14, 16, 18] precio=[101, 51, 27, 44, 86, 101, 138, 50, 22, 83, 41, 78, 126, 183, 91, 48, 51, 37, 55, 81, 48, 88, 187, 146, 240, 360, 387, 443, 516, 612] data=zip(tipo,capacidad,precio) columns=['tipo', 'capacidad','precio'] df1=pd.DataFrame(data, columns=columns)
También podemos crear un DataFrame especificando el listado de datos y el nombre de las columnas directamente:
df2 = pd.DataFrame([['SSD', 1, 214], ['HDD', 0.75, 123]], columns=['tipo', 'capacidad', 'precio'])
df3 = pd.concat([df1, df2], ignore_index=True)
df.to_csv("datos.csv", index=False)
index=False
ya que sino creará en disco una columna extra con el nº de la fila a modo de índice
tipo,capacidad,precio SSD,0.5,101 SSD,0.5,51 SSD,0.24,27 SSD,0.48,44 ........ HDD,14.0,443 HDD,16.0,516 HDD,18.0,612 SSD,1.0,214
df=pd.read_csv("datos.csv",sep=",")
index=False
,al leer el fichero se deberá añadir el parámetro index_col=0
df.to_csv("datos.csv") df=pd.read_csv("datos.csv",index_col=0)
import sqlalchemy connection = sqlalchemy.create_engine('mysql+pymysql://mi_usuario:mi_contrasenya@localhost:3306/mi_database') df=pd.read_sql("SELECT * FROM mi_tabla",con=connection)
Crear un DataFrame desde una base de datos relacional es tan sencillo como crear la conexión con sqlalchemy.create_engine
y luego con pandas llamar a read_sql
.
conda install -c anaconda sqlalchemy
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 31 entries, 0 to 30 Data columns (total 3 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 tipo 31 non-null object 1 capacidad 31 non-null float64 2 precio 31 non-null int64 dtypes: float64(1), int64(1), object(1) memory usage: 872.0+ bytes
df.shape
(31, 3)
df.head()
tipo capacidad precio 0 SSD 0.50 101 1 SSD 0.50 51 2 SSD 0.24 27 3 SSD 0.48 44 4 SSD 1.00 86
df.tail()
tipo capacidad precio 26 HDD 12.0 387 27 HDD 14.0 443 28 HDD 16.0 516 29 HDD 18.0 612 30 SSD 1.0 214
df.describe()
capacidad precio count 28.000000 28.000000 mean 4.092143 157.428571 std 5.209273 158.877178 min 0.120000 22.000000 25% 0.512000 50.750000 50% 1.750000 89.500000 75% 5.250000 184.000000 max 18.000000 612.000000
df.precio.mean()
157.42
df.precio.std()
158.87
df.precio.sum()
4408.0
df.precio.max()
612.0
df.precio.min()
22.0
df.corr()
capacidad precio capacidad 1.000000 0.962542 precio 0.962542 1.000000
Lo normal es que queramos acceder a los datos siempre por columnas. Así que explicaremos únicamente esa forma.
df['capacidad'] df.loc[:,'capacidad'] df.capacidad
:
df[['precio','capacidad']] df.loc[:,['precio','capacidad']]
df.loc[:,df.columns!='tipo']
df df[:] df.loc[:,:]
df.iloc[:,1]
df.iloc[:,-1]
df.iloc[:,[0,-1]]
df.columns
['tipo', 'capacidad', 'precio']
len(df.columns)
df.columns[0]
rename
. Se pasa un diccionario cuya clave es el nombre actual y el valor es el nuevo nombre.
#Cambiamos el nombre de la columna "tipo" al nuevo nombre "target" df.rename(columns={'tipo': 'target'}, inplace=True) new_df=df.rename(columns={'tipo': 'target'})
inplace=True
se hace la modificación en el propio DataFrame
y no hace falta asignarlo a otro nuevo DataFrame
target
reindex
#Ahora la columna target está al final df=df.reindex(columns=['capacidad','precio','target'])
DataFrame
a un nuevo DataFrame
velocidad
al inicio del DataFrame
datos_nueva_columna=[1000, 1250, 6500, 2500, 2750, 2500, 1000, 1500, 2250, 5500, 2750, 4250, 5000, 3750, 2500, 6500, 5250, 5250, 3250, 3500, 7250, 6250, 2250, 3500, 4250, 6000, 2000, 3000, 5250, 2500] df.insert(0,"velocidad",datos_nueva_columna)
velocidad
antes del “precio”
datos_nueva_columna=[1000, 1250, 6500, 2500, 2750, 2500, 1000, 1500, 2250, 5500, 2750, 4250, 5000, 3750, 2500, 6500, 5250, 5250, 3250, 3500, 7250, 6250, 2250, 3500, 4250, 6000, 2000, 3000, 5250, 2500] df.insert(2,"velocidad",datos_nueva_columna)
df.insert(3,"calculada",df.precio*df.capacidad)
tipo capacidad precio calculada 0 SSD 0.50 101 50.50 1 SSD 0.50 51 25.50 2 SSD 0.24 27 6.48 3 SSD 0.48 44 21.12 4 SSD 1.00 86 86.00 ...........
#Pasamos de euros a dolares df.precio=df.precio*1.13
calculada
df.drop(columns = ['calculada'], inplace = True) new_df=df.drop(columns = ['calculada'])
df[df.tipo=='SSD']
df[(df.tipo=='SSD') & (df.precio<100)]
DataFrame
así que se pueden aplicar todos los métodos de los DataFrame
.
df.tipo.unique()
array(['SSD', 'HDD'], dtype=object)
Vamos ahora a crear un DataFrame con datos inválidos.
import math tipo=[None, 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'SSD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD', 'HDD'] capacidad=[0.5, math.nan, 0.24, None, 1, 0.512, 1, 0.48, 0.12, 0.96, 0.256, 0.512, 1, 2, 0.5, 2, 2, 1, 1.5, 4, 2, 4, 6, 5, 8, 10, 12, 14, 16, 18] precio=[101, 51, math.nan, 44, None, 101, 138, 50, 22, 83, 41, 78, 126, 183, 91, 48, 51, 37, 55, 81, 48, 88, 187, 146, 240, 360, 387, 443, 516, 612] data=zip(tipo,capacidad,precio) columns=['tipo', 'capacidad','precio'] df=pd.DataFrame(data, columns=columns)
NaN
o None
de cada columna
df.isnull().sum()
tipo 1 capacidad 2 precio 2 dtype: int64
NaN
o None
df=df.dropna() df.isnull().sum()
tipo 0 capacidad 0 precio 0 dtype: int64
Con dataframes lo sencillo usar seaborn
import matplotlib.pyplot as plt import seaborn as sns figure=plt.figure(figsize=(12,8)) axes = figure.add_subplot() sns.scatterplot(x="capacidad", y="precio", hue="tipo",data=df,ax=axes)
figure=plt.figure(figsize=(16,5)) axes = figure.add_subplot(1,2,1) sns.kdeplot(x="capacidad",data=df,fill=True,ax=axes) axes = figure.add_subplot(1,2,2) sns.kdeplot(x="precio",data=df,fill=True,ax=axes)
figure=plt.figure(figsize=(16,5)) axes = figure.add_subplot(1,2,1) sns.kdeplot(x="capacidad",hue="tipo",data=df,fill=True,ax=axes) axes = figure.add_subplot(1,2,2) sns.kdeplot(x="precio",hue="tipo",data=df,fill=True,ax=axes)
figure=plt.figure(figsize=(16,5)) axes = figure.add_subplot(1,2,1) sns.histplot(x="capacidad",hue="tipo",data=df,ax=axes) axes = figure.add_subplot(1,2,2) sns.histplot(x="precio",hue="tipo",data=df,ax=axes)
pairplot=sns.pairplot(df,hue="tipo")
Crea un DataDrame con los datos que proporciona load_iris
. Recuerda que la propiedad feature_names
retorna los nombres. La columna de los tipos de flor la debes llamar tipo_flor
index=False
y mira la diferencia con el anterior fichero.Siguiendo con el DataFrame anterior imprime por pantalla:
Siguiendo con el DataFrame anterior:
Siguiendo con el DataFrame anterior imprime por pantalla:
Siguiendo con el DataFrame anterior y usando Seaborn:
Descarga el siguiente fichero tiempos_red_neuronal.zip que contiene los segundos que ha tardado en entrenarse una red neuronal según el nº de épocas y la función de activación usada
talla
a epoca
Siguiendo con el DataFrame anterior:
¿Ves algo raro en los datos?
Siguiendo con el DataFrame anterior:
Siguiendo con el DataFrame anterior:
La gráfica no deja claro cda una de las rectas. Para mejorarlo se podría anotar al final de cada recta el nombre de la función de activación tal y como se muestra en el siguiente gráfico:
Para poner texto en una gráfica se usa el método annotate y la librería adjustText - automatic label placement for matplotlib
Usando la función plot_metrics
muestra las gráficas de las pérdidas por épocas de las siguientes redes neuronales para el DataFrame de las flores:
Nº Neuronas en cada capa |
---|
2,4,2,1 |
4,8,4,1 |
8,16,8,1 |
4,8,4,2,1 |
8,16,8,4,1 |
16,32,16,8,1 |
32,64,32,8,1 |
64,128,64,8,1 |
8,16,32,64,32,16,8,1 |
Además:
Siguiendo con el DataFrame anterior:
normalizado_
. Esas 5 nuevas columnas tendrán los valores según la fórmula:$$ valor = \frac {X-min}{max-min} $$
standarizado_
. Esas 5 nuevas columnas tendrán los valores según la fórmula:$$ valor = \frac {X-media}{desviación} $$
Usando la función plot_metrics
muestra las gráficas de las pérdidas por épocas de las siguientes redes neuronales para el DataFrame de las flores:
Nº Neuronas en cada capa |
---|
2,4,2,1 |
4,8,4,1 |
8,16,8,1 |
4,8,4,2,1 |
8,16,8,4,1 |
16,32,16,8,1 |
32,64,32,8,1 |
64,128,64,8,1 |
8,16,32,64,32,16,8,1 |
Pero para cada tipo de red ,deberás entrenarla 3 veces distintas y obtener resultado distintos con:
Además:
¿Hay diferencias al usar los datos normalizados o estandarizado? ¿Cual es mejor y peor? ¿Las ventajas son las mismas independientemente de la red?