# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# # Apply, applymap & map
# Referencia: https://towardsdatascience.com/introduction-to-pandas-apply-applymap-and-map-5d3e044e93ff

import numpy as np
import pandas as pd

# ## Series methods

# ### Map

# Map values of Series according to input correspondence.
#
# Used for substituting each value in a Series with another value, that may be derived from a function, a dict or a Series.
#
# **When arg is a dictionary, values in Series that are not in the dictionary (as keys) are converted to NaN.**

s = pd.Series(['cat', 'dog', np.nan, 'rabbit'])
s

dictionary = {"cat": "kitten", "dog": "puppy"}
s.map(dictionary)

# # format

a = "Dani"
b = "Madrid"
c = 15

print("{0} vive en {1}.\nThe Bridge está en el número {2}.".format(a,b,c))

lista = ['Gabriel', 'Clara', 'Borja', "Mónica"]
lista_ciudades = ['Madrid', 'Paris']
lista_numeros = range(3)

for nombre in lista:
    for ciudad in lista_ciudades:
        for numero in lista_numeros:
            print("{0} vive en {1}.\nThe Bridge está en el número {2}.".format(nombre, ciudad, numero))
            break

# ------------------------------------------------------------------

s.map('My favourite animal is {}'.format)

s.map('My favourite animal is {}'.format, na_action='ignore')

# +
#dataframe example
# -

data = pd.DataFrame({'food': ['bacon', 'pulled pork', 'bacon',
                              'Pastrami', 'corned beef', 'Bacon',
                              'pastrami', 'honey ham', 'nova lox'],
                     'ounces': [4, 3, 12, 6, 7.5, 8, 3, 5, 6]})

meat_to_animal = {
  'bacon': 'pig',
  'pulled pork': 'pig',
  'pastrami': 'cow',
  'corned beef': 'cow',
  'honey ham': 'pig',
  'nova lox': 'salmon'
}

data['food']

# +
# en dos pasos
# -

lowercased = data['food'].str.lower()
lowercased

data['animal'] = lowercased.map(meat_to_animal)

# en un paso
data['animal2'] = data['food'].map(lambda x: meat_to_animal[x.lower()])

data

# ### Str
# Vectorized string functions for Series and Index.
#
# https://towardsdatascience.com/mastering-string-methods-in-pandas-8d3cd00b720d
#
# - [`str.contains`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.str.contains.html)
# - [`str.startswith`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.str.startswith.html#pandas.Series.str.startswith)

print([i for i in dir(pd.Series.str) if not i.startswith("_")])

data.food.str[:-1]

# ### Apply
#
# Invoke function on values of Series.
#
# Can be ufunc (a NumPy function that applies to the entire Series) or a Python function that only works on single values.

chipo = pd.read_csv("https://raw.githubusercontent.com/justmarkham/DAT8/master/data/chipotle.tsv", sep='\t')

chipo.columns

chipo['item_price'].str[1:].astype(float)

chipo.item_price.apply(lambda x: float(x[1:]))

# ## Dataframe methods

# ### Apply

# Apply a function along an axis of the DataFrame.
#
# Objects passed to the function are Series objects whose index is either the DataFrame’s index (axis=0) or the DataFrame’s columns (axis=1). By default (result_type=None), the final return type is inferred from the return type of the applied function. Otherwise, it depends on the result_type argument.

# **axis{0 or ‘index’, 1 or ‘columns’}, default 0**
#
# The second parameter axis is to specify which axis the function is applied to. 0 for applying the function to each column and 1 for applying the function to each row.

df = pd.DataFrame({"A":[1,2,3,4],
                  "B": [10,20,30,40],
                  "C": [20,40,60,80]},
                 index = ["Row 1", "Row 2", "Row 3", "Row 4"])
df


def suma_serie(row):
    return row.sum()


df.apply(suma_serie, axis = 0) # en vertical

df.apply(suma_serie, axis = 1) # en horizontal

df['D'] = df.apply(suma_serie, axis = 1)
df

df['A']

df.apply(lambda x: x.mean(), axis = 0)

df['E'] = df.apply(lambda x: x.mean(), axis = 1)

df

#la operación se aplica a toda la row
df.apply(lambda x: x**2, axis = 1)

serie_cualquiera = pd.Series([1, 10,20,31,15.5])

serie_cualquiera**2

serie_cualquiera.mean()

suma_serie(serie_cualquiera)

df.apply(suma_serie, axis = 0)

#crear otra row
df.loc['Row nueva'] = df.apply(suma_serie, axis = 0)

df

# por Series
df['J'] = df['C'].apply(lambda x: x*2)

df

# ### Applymap
# Apply a function to a Dataframe elementwise.
#
# This method applies a function that accepts and returns a scalar to every element of a DataFrame.

df.loc['Row 1'].map(np.sum)

df.applymap(np.sum)

data.dtypes

data.head()

# +
# Cuidado con aplicar la misma función a todas las celdas incluyendo aquellas columnas con tipos incompatibles para la función
# ejemplo: len() a una celda de la columna "ounces" de tipo float
# -

#solucion 1
data.select_dtypes(exclude=['float64']).applymap(lambda x: len(x))

#solucion 2
data.drop("ounces", axis = 1).applymap(lambda x: len(x))

#solucion3
data.applymap(lambda x: len(str(x)))



StarcoderdataJupyterScriptsDedupFiltered