<jupyter_start><jupyter_text>Pandas I DataFrame Documentación https://pandas.pydata.org/pandas-docs/stable/reference/frame.html Representa una estructura de datos **tabular** que contiene una colección de columnas, cada una de las cuales tiene un tipo de datos determinado (number, string, boolean, etc.).Podemos pensar un objeto `DataFrame` como un diccionario de `Series` "alineadas" (que comparten el mismo índice).Una instancia de DataFrame tiene **índices de columnas y de filas**.  ![Image](img/dataframe.jpg)  `DataFrame` como un diccionario de `Series` "alineadas"Un `DataFrame` es un tipo de datos análogo a `Series` en dos dimensiones. Como ejemplo, generemos un DataFrame con datos de área y población para distintos estados combinando dos series.1) Generemos un objeto `Series` con el área de algunos estados a partir de un diccionario:<jupyter_code>import pandas as pd
import numpy as np
area_dict = {'California': 423967, 'Texas': 695662, 'New York': 141297,
             'Florida': 170312, 'Illinois': 149995}
area = pd.Series(area_dict)
area<jupyter_output><empty_output><jupyter_text>2) Generemos un objeto `Series` con la población de algunos estados a partir de listas:<jupyter_code>states_list = ['Illinois','Texas','New York', 'Florida', 'California']
states_pop = [12882135, 26448193, 19651127, 19552860, 38332521]
population = pd.Series(states_pop, index= states_list)
population<jupyter_output><empty_output><jupyter_text>Generamos un objeto `DataFrame` a partir de los dos objetos `Series` generados en los puntos anteriores:<jupyter_code>states = pd.DataFrame({'population': population,
                       'area': area})
states<jupyter_output><empty_output><jupyter_text>Al igual que Series, un DataFrame posee un atributo index:<jupyter_code>states.index<jupyter_output><empty_output><jupyter_text>Además, tiene un atributo columns, que es un objeto de tipo Index conteniendo las etiquetas de columnas:<jupyter_code>states.columns<jupyter_output><empty_output><jupyter_text>Pueden observar que tanto los nombres de filas como los nombres de columnas son objetos del tipo `Index`.  DataFrame como un diccionario especializadoDe forma similar, podemos pensar auna instancia de `DataFrame` como un diccionario:     * Un diccionario mapea una key con un valor* Un `DataFrame` mapea un nombre de columna con una `Series` de datos.    Por ejemplo, pedir el atributo `area` del `DataFrame` `states` devuelve una instancia de `Series`.<jupyter_code>states['area']
states.area
print(type(states['area']))
print(type(states.area))
states['area'] is states.area
states['area'] == states.area<jupyter_output><empty_output><jupyter_text>¿Qué diferencia hay entre == y is ?   Constructor Documentaciónhttps://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html  Desde una instancia de `Series`:[volver a TOC](section_toc)<jupyter_code>pd.DataFrame(population, columns=['population'])<jupyter_output><empty_output><jupyter_text>Desde una lista de `dicts`[volver a TOC](section_toc)<jupyter_code>dict_0 = {'a': 0, 'b': 0}
dict_1 = {'a': 1, 'b': 2}
dict_2 = {'a': 2, 'b': 4}

data = [dict_0, dict_1, dict_2]

pd.DataFrame(data)<jupyter_output><empty_output><jupyter_text>Otra forma de construir lo mismo, usando listas por comprensión:<jupyter_code>data = [{'a': i, 'b': 2 * i}
        for i in range(3)]

print(data)

pd.DataFrame(data)<jupyter_output>[{'a': 0, 'b': 0}, {'a': 1, 'b': 2}, {'a': 2, 'b': 4}]<jupyter_text>Incluso si alguna key no tiene un valor asociado en el diccionario, Pandas completa con NaN el valor:<jupyter_code>pd.DataFrame([{'a': 1, 'b': 2}, {'b': 3, 'c': 4}])<jupyter_output><empty_output><jupyter_text>Desde un array `Numpy` de dos dimensiones:[volver a TOC](section_toc)<jupyter_code>array_2d = np.random.rand(3, 2)
# veamos qué hay en la variable array_2d:
print(array_2d)

columns_names = ['foo', 'bar']
rows_names = ['a', 'b', 'c']

pd.DataFrame(array_2d, columns=columns_names, index=rows_names)<jupyter_output>[[0.5642287  0.56617184]
 [0.12333605 0.08352266]
 [0.43328948 0.3986582 ]]<jupyter_text>Selección de datos en `DataFrame`[volver a TOC](section_toc)Vamos a ver ahora distintas formas de seleccionar elementos en instancias de `DataFrame`Comencemos creando el objeto `data`:<jupyter_code>area = pd.Series({'California': 423967, 'Texas': 695662,
                  'New York': 141297, 'Florida': 170312,
                  'Illinois': 149995})
pop = pd.Series({'California': 38332521, 'Texas': 26448193,
                 'New York': 19651127, 'Florida': 19552860,
                 'Illinois': 12882135})
data = pd.DataFrame({'area':area, 'pop':pop})
data<jupyter_output><empty_output><jupyter_text>Primeros n elementos, últimos n elementos[volver a TOC](section_toc)Puede accederse a los primeros n elementos del DataFrame con el método df.head(n). Del mismo modo, puede aplicarse el método df.tail(n) para acceder a los últimos elementos del DataFrame:<jupyter_code>data.head(2)
data.tail(3)<jupyter_output><empty_output><jupyter_text>Muestra aleatoria de n elementos[volver a TOC](section_toc)Con el método df.sample(n) obtenemos una muestra aleatória de n elementos:<jupyter_code>data.sample(2)<jupyter_output><empty_output><jupyter_text>Columnas[volver a TOC](section_toc)    Podemos acceder a las Series individuales que forman las columnas del DataFrame de forma análoga a un diccionario de varias formas:* Vía el nombre de la columna:<jupyter_code>data['area']<jupyter_output><empty_output><jupyter_text>* Como atributo:<jupyter_code>data.area<jupyter_output><empty_output><jupyter_text>Ambas formas son equivalentes:<jupyter_code>data['area'] is data.area<jupyter_output><empty_output><jupyter_text>`values` devuelve los valores de todos los elementos que conforman el objeto `DataFrame` como un objeto `numpy.ndarray`:<jupyter_code>data.values<jupyter_output><empty_output><jupyter_text>Indexación[volver a TOC](section_toc)    Vamos a indexar un objeto `DataFrame` con dos índices, uno para las filas y el otro para las columnas.    Las formas de indexar que vimos en arrays y es series sirven también para dataframes.Recordemos cuáles son:       loc iloc<jupyter_code>data.iloc[:3, :2]
data.loc[:'Illinois', :'pop']<jupyter_output><empty_output><jupyter_text>Boolean masking<jupyter_code>data.loc[data.area > 423000, :]<jupyter_output><empty_output><jupyter_text>Fancy indexing<jupyter_code>data.loc[:, ['pop', 'area']]<jupyter_output><empty_output><jupyter_text>Combinando boolean masking y fancy indexing<jupyter_code>data.loc[data.area > 423000, ['pop', 'area']]<jupyter_output><empty_output><jupyter_text>Algunas convenciones adicionales para indexarHasta ahora vimos cómo indexar un objeto `DataFrame` con un índice sobre filas y otro sobre columnas. Podemos tambien indexarlos usando sólo un índice que se interpreta según el detalle que vemos a continuación. En general, "fancy indexing" refiere a columnas, mientras que "slicing" refiere a filas:<jupyter_code>data[['area', 'area']]
data['Florida':'Illinois']<jupyter_output><empty_output><jupyter_text>Slicing puede referir filas por posición, en lugar de índices:<jupyter_code>data[1:3]<jupyter_output><empty_output><jupyter_text>Boolean masking se interpretada por defecto sobre filas:<jupyter_code>data[data.area > 423000]<jupyter_output><empty_output><jupyter_text>Moficación de valores[volver a TOC](section_toc) Podemos crear una nueva columna en un objeto DataFrame como el resultado de una operación sobre otros elementos del objeto:<jupyter_code>data['density'] = data['pop'] / data['area']
data<jupyter_output><empty_output><jupyter_text>Cualquiera de las formas de indexar que vimos puede ser usada para asignar o modificar valores:<jupyter_code>data.iloc[0, 2] = 90
data<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11357483563233209, 'fraction_numerical': 0.03261570194662885, 'mean_word_length': 6.789156626506024, 'pattern_counts': {'":': 0, '<': 107, '<?xml version=': 0, '>': 110, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '27', 'dir': 'jupyter-structured-clean-dedup', 'id': '612228', 'license': 'MIT', 'n_tokens_mistral': 2957, 'n_tokens_neox': 2743, 'n_words': 733, 'path': 'Code/4-pandas/2_dataframe.ipynb', 'repo_name': 'Flor91/Data-Science', 'size': '7757'}