<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Introducción a Pandas en los cuadernos de Jupyter
La estructura de Datos Serie
Arreglo unidimensional con etiquetas en los ejes (incluidas series de tiempo). Los parámetros de una Serie son
Step1:  <br>
Podemos convertir una lista en una serie y pandas asigna de manera inmediata una lista de índices que empieza en 0.
Step2:  <br>
Es importante saber como NumPy y Pandas manejan los datos faltantes. En Python tenemos el tipo None para indicar un dato faltante. Si tenemos una lista de números, Pandas automáticamente convierte este valor None en un valor designado como NaN, que significa Not a Number.
Step3:  <br>
Importamos la biblioteca NumPy. También es importante saber que NaN no es None. Cuando hacemos un test para saber si NaN es NaN tambien obtendremos False.
Step4:  <br>
Se necesita la función especial isnan de NumPy para chequear la presencia de un no número en nuestros datos.
Step5:  <br>
¿Cómo creamos una serie en Pandas? Podemos utilizar una estructura de datos diccionario con sus claves y convertirlo en una serie, donde los índices de la serie son las claves del diccionario.
Step6:  <br>
Luego, podemos chequear la lista de índices con el atributo .index
Step7:  <br>
En este otro ejemplo, pasamos directamente una lista con su conjunto de índices para crear la Serie.
Step8:  <br>
Aquí tenemos un ejemplo de un elemento nuevo en la lista de índices que no tiene un valor asignado, no existe un país asociado al índice Natación y Pandas representa este valor faltante con NaN.
Step9:  Búsqueda en una Serie
Step10:  <br>
Podemos hacer búsquedas en las series por posición de índices o por etiqueta de índices. Si queremos hacer búsqueda por ubicación numérica (empezando desde 0) utilizamos el atributo iloc. Si por otra parte, hacemos búqueda por etiqueta de índice entonces usamos el atributo loc.
Step11:  <br>
Pandas trata de que el código sea más legible. Si le pasamos por parámetro un valor numérico a la Serie esta se comportará como si la búsqueda se hace con el atributo iloc, si en cambio le pasamos un objeto, hará la búsqueda por etiqueta como con el atributo loc.
Step12:  <br>
¿Qué pasa cuando tenemos una lista de índices que son enteros?
Step13:  <br>
Cuando tenemos un caso como este es más seguro utilizar los atributos iloc o loc según sea el caso.
Step14:  <br>
Ya que sabemos hacer búsquedas en las Series, ahora vamos a trabajar con los datos (encontrar valores, resumir los datos o transformarlos).
Step15:  <br>
Una forma de trabajar es iterar sobre un conjunto de datos e invocar una operación de interés
Step16:  <br>
Con NumPy podemos tener acceso a las funciones universales binarias o unarias (vectorizadas, cálculos más rápidos). En este ejemplo, np.sum hará la suma de todos los elementos en la serie.
Step17:  <br>
También podemos generar una serie grande de números aleatorios y con el método .head() podemos desplegar un encabezado con los 5 primeros elementos de la serie y con len chequear el tamaño de la misma.
Step18:  <br>
Los cuadernos de Jupyter tienen funciones mágicas que pueden ser útiles. Una de ellas es %%timeit que nos servirá para ver cuál de los dos métodos para sumar elementos de una serie es más rápido.
Basta con tipear el símbolo % y la tecla Tab para obtener una lista de las funciones mágicas de Jupyter.
Step19:  <br>
NumPy y Pandas tienen el broadcasting, se puede aplicar una operación a cada valor de la serie y modificarla.
Step20:  <br>
Una manera poco eficiente de hacer esto es iterar sobre cada elemento de la serie para hacer la suma. El método .iteritems() devuelve un iterador sobre los pares (key, value) (clave, valor) de un diccionario, en este caso de nuestra serie s.
Step21:  <br>
Podemos agregar elementos a una serie de la siguiente forma
Step22:  <br>
Este es un ejemplo de una serie donde los valores del conjunto de índices no son únicos. Esto hace que las tablas de datos funcionen diferente y es por ello que agregar nuevos elementos debe hacerse con el método append, que en primera instancia, no modificará la serie sino que devuelve una nueva serie con los elementos que se agregaron.
Step23:  La estructura de datos DataFrame
<br>
El DataFrame o Tabla de Datos es el corazón de la biblioteca Pandas. Es el objeto primario para el análisis de datos. Es una especie de arreglo bidimensional con etiquetas en los ejes. En este ejemplo, crearemos tres diccionarios que serán luego las filas de nuestro DataFrame.
Step24:  <br>
En un DataFrame también se puede extraer información usando los atributos loc y iloc.
Step25:  <br>
También podemos chequear el tipo de dato usando la función type de Python.
Step26:  <br>
En los DataFrame también se pueden tener listas de índices no únicos. En el ejemplo, hay dos índices con el mismo nombre Tienda 1.
Step27:  <br>
También podemos seleccionar columnas agregando un parámetro extra al atributo loc.
Step28:  <br>
Usar el atributo .T para obtener la transpuesta del DataFrame o Tabla de Datos.
Step29:  <br>
Usando .T.loc[] se puede seleccionar una columna usando como parámetro la etiqueta de su nombre.
Step30:  <br>
loc también tiene soporte para rebanar o seleccionar del DataFrame con la notación []
Step31:  <br>
También podemos eliminar datos del DataFrame con la función drop(). Esta función toma un solo parámetro que es el índice del conjunto de datos que deseamos eliminar.
Step32:  <br>
Podemos ver que nuestro DataFrame original sigue intacto. Solo hicimos una extracción de información.
Step33:  <br>
También podemos hacer una copia del DataFrame con la función copy() para guardar la extracción de información.
Step34:  <br>
Podemos eliminar una columna de manera sencilla, usando simplemente la palabra clave del y el índice o nombre de la comuna.
Step35:  <br>
Finalmente, es muy sencillo agregar una columna al DataFrame.
Step36:  Lectura de un DataFrame
<br>
Usemos !cat para leer un archivo de formato CSV. Nota
Step37:  <br>
Pero ... no hay que preocuparse mucho por eso! Podemos leer este archivo en formato CSV en un DataFrame usando la función read_csv.
Step38:  <br>
Aquí podemos ignorar la primera fila del DataFrame para dejar más limpia la tabla de información no relevante.
Step39:  <br>
El atributo .columns nos permite ver el nombre de las comlumnas del DataFrame y el atributo .rename modificar el nombre.
Step40:  Haciendo búsquedas en un DataFrame
<br>
Podemos buscar en el DataFrame con una máscara Booleana qué países tienen (True) o no (False) una medalla de oro.
Step41:  <br>
La función .where() toma una máscara booleana como condición en el argumento, la aplica al DataFrame, y devuelve un DataFrame de la misma forma. En nuestro ejemplo, reemplaza con NaN los casos False y con su valor original, los casos True.
Step42:  <br>
Podemos contar cuántas países hay medallas de oro hay en total con count()
Step43:  Si contamos sobre los datos originales, veremos que hay 147 países. Cuenta los países para los cuales la máscara Booleana dio False >.<
Step44:  <br>
Podemos establecer otro tipo de condiciones para hacer búsquedas más complejas. Por ejemplo, buscar la cantidad de países que han ganado medalla de oro alguna vez.
Step45:  <br>
Buscar qué países han ganado sólo medallas de oro en Invierno y nunca en Verano.
<ASSISTANT_TASK:>
Python Code:
import pandas as pd
pd.Series?
Explanation: Introducción a Pandas en los cuadernos de Jupyter
La estructura de Datos Serie
Arreglo unidimensional con etiquetas en los ejes (incluidas series de tiempo). Los parámetros de una Serie son: data (matriz, diccionario o escalar), index (arreglo de índices), dtype (numpy.dtype o None) y copy (booleano o por defecto False)
<br>
Importamos la biblioteca Pandas
End of explanation
animales = ['Tigre', 'Oso', 'Camello']
pd.Series(animales)
numeros = [1, 2, 3]
pd.Series(numeros)
animales = ['Tigre', 'Oso', None]
pd.Series(animales)
Explanation: <br>
Podemos convertir una lista en una serie y pandas asigna de manera inmediata una lista de índices que empieza en 0.
End of explanation
numeros = [1, 2, None]
pd.Series(numeros)
Explanation: <br>
Es importante saber como NumPy y Pandas manejan los datos faltantes. En Python tenemos el tipo None para indicar un dato faltante. Si tenemos una lista de números, Pandas automáticamente convierte este valor None en un valor designado como NaN, que significa Not a Number.
End of explanation
import numpy as np
np.nan == None
np.nan == np.nan
Explanation: <br>
Importamos la biblioteca NumPy. También es importante saber que NaN no es None. Cuando hacemos un test para saber si NaN es NaN tambien obtendremos False.
End of explanation
print(np.isnan(np.nan))
print(None is None)
print(np.nan is np.nan)
Explanation: <br>
Se necesita la función especial isnan de NumPy para chequear la presencia de un no número en nuestros datos.
End of explanation
deportes = {'Capoeira': 'Brasil',
          'Rayuela': 'Chile',
          'Pelota Vasca': 'País Vasco',
          'Béisbol': 'Cuba',
           'Rugby': 'Gales',
           'Golf': 'Escocia',
           'Corrida de Toros': 'España',
           'Sumo': 'Japón'}
s = pd.Series(deportes)
s
Explanation: <br>
¿Cómo creamos una serie en Pandas? Podemos utilizar una estructura de datos diccionario con sus claves y convertirlo en una serie, donde los índices de la serie son las claves del diccionario.
End of explanation
s.index
Explanation: <br>
Luego, podemos chequear la lista de índices con el atributo .index
End of explanation
s = pd.Series(['Tigre', 'Oso', 'Camello'], index=['India', 'America', 'Africa'])
s
Explanation: <br>
En este otro ejemplo, pasamos directamente una lista con su conjunto de índices para crear la Serie.
End of explanation
deportes = {'Capoeira': 'Brasil',
          'Rayuela': 'Chile',
          'Pelota Vasca': 'País Vasco',
          'Béisbol': 'Cuba',
           'Rugby': 'Gales',
           'Golf': 'Escocia',
           'Corrida de Toros': 'España',
           'Sumo': 'Japón'}
s = pd.Series(deportes, index=['Capoeira', 'Sumo', 'Pelota Vasca',  'Natación'])
s
Explanation: <br>
Aquí tenemos un ejemplo de un elemento nuevo en la lista de índices que no tiene un valor asignado, no existe un país asociado al índice Natación y Pandas representa este valor faltante con NaN.
End of explanation
deportes = {'Capoeira': 'Brasil',
          'Rayuela': 'Chile',
          'Pelota Vasca': 'País Vasco',
          'Béisbol': 'Cuba',
           'Rugby': 'Gales',
           'Golf': 'Escocia',
           'Corrida de Toros': 'España',
           'Sumo': 'Japón'}
s = pd.Series(deportes)
s
Explanation: Búsqueda en una Serie
End of explanation
s.iloc[4]
s.loc['Pelota Vasca']
Explanation: <br>
Podemos hacer búsquedas en las series por posición de índices o por etiqueta de índices. Si queremos hacer búsqueda por ubicación numérica (empezando desde 0) utilizamos el atributo iloc. Si por otra parte, hacemos búqueda por etiqueta de índice entonces usamos el atributo loc.
End of explanation
s[4]
s['Pelota Vasca']
Explanation: <br>
Pandas trata de que el código sea más legible. Si le pasamos por parámetro un valor numérico a la Serie esta se comportará como si la búsqueda se hace con el atributo iloc, si en cambio le pasamos un objeto, hará la búsqueda por etiqueta como con el atributo loc.
End of explanation
deportes = {99: 'Brasil',
          100: 'Chile',
          101: 'País Vasco',
          102: 'Cuba',
           103: 'Gales',
           104: 'Escocia',
           105: 'España',
           106: 'Japón'}
s = pd.Series(deportes)
s
Explanation: <br>
¿Qué pasa cuando tenemos una lista de índices que son enteros?
End of explanation
s[0] #Esta instrucción no llamará s.iloc[0] como esperaríamos y va a generar un error
s.iloc[0]
s.loc[99]
Explanation: <br>
Cuando tenemos un caso como este es más seguro utilizar los atributos iloc o loc según sea el caso.
End of explanation
s = pd.Series([105.00, 223.00, 5, 102.00, 27, -126])
s
Explanation: <br>
Ya que sabemos hacer búsquedas en las Series, ahora vamos a trabajar con los datos (encontrar valores, resumir los datos o transformarlos).
End of explanation
total = 0
for elemento in s:
    total+=elemento
print(total)
Explanation: <br>
Una forma de trabajar es iterar sobre un conjunto de datos e invocar una operación de interés
End of explanation
import numpy as np
total = np.sum(s)
print(total)
Explanation: <br>
Con NumPy podemos tener acceso a las funciones universales binarias o unarias (vectorizadas, cálculos más rápidos). En este ejemplo, np.sum hará la suma de todos los elementos en la serie.
End of explanation
s = pd.Series(np.random.randint(0,1000,10000))
print(s.head())
print(len(s))
Explanation: <br>
También podemos generar una serie grande de números aleatorios y con el método .head() podemos desplegar un encabezado con los 5 primeros elementos de la serie y con len chequear el tamaño de la misma.
End of explanation
%%timeit -n 100
sumar = 0
for elemento in s:
    sumar+=elemento
%%timeit -n 100
sumar = np.sum(s)
Explanation: <br>
Los cuadernos de Jupyter tienen funciones mágicas que pueden ser útiles. Una de ellas es %%timeit que nos servirá para ver cuál de los dos métodos para sumar elementos de una serie es más rápido.
Basta con tipear el símbolo % y la tecla Tab para obtener una lista de las funciones mágicas de Jupyter.
End of explanation
s+=2 #Suma 2 a cada elemento de la serie usando broadcasting
s.head()
Explanation: <br>
NumPy y Pandas tienen el broadcasting, se puede aplicar una operación a cada valor de la serie y modificarla.
End of explanation
for etiqueta, valor in s.iteritems():
    s.set_value(etiqueta, valor+2)
s.head()
%%timeit -n 10
s = pd.Series(np.random.randint(0,1000,10000))
for etiqueta, valor in s.iteritems():
    s.loc[etiqueta]= valor+2
%%timeit -n 10
s = pd.Series(np.random.randint(0,1000,10000))
s+=2
Explanation: <br>
Una manera poco eficiente de hacer esto es iterar sobre cada elemento de la serie para hacer la suma. El método .iteritems() devuelve un iterador sobre los pares (key, value) (clave, valor) de un diccionario, en este caso de nuestra serie s.
End of explanation
import pandas as pd
s = pd.Series([1, 2, 3])
s.loc['Animal'] = 'Oso'
s
Explanation: <br>
Podemos agregar elementos a una serie de la siguiente forma:
End of explanation
deportes_originales = pd.Series({'Capoeira': 'Brasil',
          'Rayuela': 'Chile',
          'Pelota Vasca': 'País Vasco',
          'Béisbol': 'Cuba',
           'Rugby': 'Gales',
           'Golf': 'Escocia',
           'Corrida de Toros': 'España',
           'Sumo': 'Japón'})
paises_que_aman_el_beisbol = pd.Series(['Venezuela',
                                      'USA',
                                      'Cuba',
                                      'Puerto Rico',
                                       'Dominicana'], 
                                   index=['Béisbol',
                                          'Béisbol',
                                          'Béisbol',
                                          'Béisbol',
                                          'Béisbol'])
todos_los_paises = deportes_originales.append(paises_que_aman_el_beisbol)
deportes_originales
paises_que_aman_el_beisbol
todos_los_paises
todos_los_paises.loc['Béisbol']
Explanation: <br>
Este es un ejemplo de una serie donde los valores del conjunto de índices no son únicos. Esto hace que las tablas de datos funcionen diferente y es por ello que agregar nuevos elementos debe hacerse con el método append, que en primera instancia, no modificará la serie sino que devuelve una nueva serie con los elementos que se agregaron.
End of explanation
import pandas as pd
compra_1 = pd.Series({'Nombre': 'Adelis',
                        'Artículo comprado': 'Libro',
                        'Costo': 1200})
compra_2 = pd.Series({'Nombre': 'Miguel',
                        'Artículo comprado': 'Raspberry pi 3',
                        'Costo': 15000})
compra_3 = pd.Series({'Nombre': 'Jaime',
                        'Artículo comprado': 'Balón',
                        'Costo': 5000})
df = pd.DataFrame([compra_1, compra_2, compra_3], index=['Tienda 1', 'Tienda 1', 'Tienda 2'])
df.head()
Explanation: La estructura de datos DataFrame
<br>
El DataFrame o Tabla de Datos es el corazón de la biblioteca Pandas. Es el objeto primario para el análisis de datos. Es una especie de arreglo bidimensional con etiquetas en los ejes. En este ejemplo, crearemos tres diccionarios que serán luego las filas de nuestro DataFrame.
End of explanation
df.loc['Tienda 2']
Explanation: <br>
En un DataFrame también se puede extraer información usando los atributos loc y iloc.
End of explanation
type(df.loc['Tienda 2'])
Explanation: <br>
También podemos chequear el tipo de dato usando la función type de Python.
End of explanation
df.loc['Tienda 1']
Explanation: <br>
En los DataFrame también se pueden tener listas de índices no únicos. En el ejemplo, hay dos índices con el mismo nombre Tienda 1.
End of explanation
df.loc['Tienda 1', 'Costo']
Explanation: <br>
También podemos seleccionar columnas agregando un parámetro extra al atributo loc.
End of explanation
df.T
Explanation: <br>
Usar el atributo .T para obtener la transpuesta del DataFrame o Tabla de Datos.
End of explanation
df.T.loc['Costo']
df['Costo']
df.loc['Tienda 1']['Costo']
Explanation: <br>
Usando .T.loc[] se puede seleccionar una columna usando como parámetro la etiqueta de su nombre.
End of explanation
df.loc[:,['Nombre', 'Costo']]
Explanation: <br>
loc también tiene soporte para rebanar o seleccionar del DataFrame con la notación []
End of explanation
df.drop('Tienda 1')
Explanation: <br>
También podemos eliminar datos del DataFrame con la función drop(). Esta función toma un solo parámetro que es el índice del conjunto de datos que deseamos eliminar.
End of explanation
df
Explanation: <br>
Podemos ver que nuestro DataFrame original sigue intacto. Solo hicimos una extracción de información.
End of explanation
copiar_df = df.copy()
copiar_df = copiar_df.drop('Tienda 1')
copiar_df
copiar_df.drop?
Explanation: <br>
También podemos hacer una copia del DataFrame con la función copy() para guardar la extracción de información.
End of explanation
del copiar_df['Costo']
copiar_df
Explanation: <br>
Podemos eliminar una columna de manera sencilla, usando simplemente la palabra clave del y el índice o nombre de la comuna.
End of explanation
df['Ubicación'] = ['Venezuela', 'Chile', 'Argentina']
df
Explanation: <br>
Finalmente, es muy sencillo agregar una columna al DataFrame.
End of explanation
!cat olympics.csv
Explanation: Lectura de un DataFrame
<br>
Usemos !cat para leer un archivo de formato CSV. Nota: !cat funciona para Linux y Mac pero puede no funcionar para Windows :(
End of explanation
import pandas as pd
df = pd.read_csv('olympics.csv')
df.head()
Explanation: <br>
Pero ... no hay que preocuparse mucho por eso! Podemos leer este archivo en formato CSV en un DataFrame usando la función read_csv.
End of explanation
df = pd.read_csv('olympics.csv', index_col = 0, skiprows=1)
df.head()
Explanation: <br>
Aquí podemos ignorar la primera fila del DataFrame para dejar más limpia la tabla de información no relevante.
End of explanation
df.columns
for col in df.columns:
    if col[:2]=='01':
        df.rename(columns={col:'Gold' + col[4:]}, inplace=True)
    if col[:2]=='02':
        df.rename(columns={col:'Silver' + col[4:]}, inplace=True)
    if col[:2]=='03':
        df.rename(columns={col:'Bronze' + col[4:]}, inplace=True)
    if col[:1]=='№':
        df.rename(columns={col:'#' + col[1:]}, inplace=True) 
df.head()
Explanation: <br>
El atributo .columns nos permite ver el nombre de las comlumnas del DataFrame y el atributo .rename modificar el nombre.
End of explanation
df['Gold'] > 0
Explanation: Haciendo búsquedas en un DataFrame
<br>
Podemos buscar en el DataFrame con una máscara Booleana qué países tienen (True) o no (False) una medalla de oro.
End of explanation
only_gold = df.where(df['Gold'] > 0)
only_gold.head()
Explanation: <br>
La función .where() toma una máscara booleana como condición en el argumento, la aplica al DataFrame, y devuelve un DataFrame de la misma forma. En nuestro ejemplo, reemplaza con NaN los casos False y con su valor original, los casos True.
End of explanation
only_gold['Gold'].count()
Explanation: <br>
Podemos contar cuántas países hay medallas de oro hay en total con count()
End of explanation
df['Gold'].count()
Explanation: Si contamos sobre los datos originales, veremos que hay 147 países. Cuenta los países para los cuales la máscara Booleana dio False >.<
End of explanation
len(df[(df['Gold'] > 0) | (df['Gold.1'] > 0)])
Explanation: <br>
Podemos establecer otro tipo de condiciones para hacer búsquedas más complejas. Por ejemplo, buscar la cantidad de países que han ganado medalla de oro alguna vez.
End of explanation
df[(df['Gold.1'] > 0) & (df['Gold'] == 0)]
Explanation: <br>
Buscar qué países han ganado sólo medallas de oro en Invierno y nunca en Verano.
End of explanation
<END_TASK>