{"id":18675375,"url":"https://github.com/manuparra/taller-bigdata-con-r","last_synced_at":"2026-04-28T23:35:01.957Z","repository":{"id":79159452,"uuid":"342394067","full_name":"manuparra/taller-bigdata-con-r","owner":"manuparra","description":"Taller Big Data con Apache Spark + R desde Databricks cloud","archived":false,"fork":false,"pushed_at":"2021-02-26T00:23:44.000Z","size":16704,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-12-27T20:33:45.624Z","etag":null,"topics":["bigdata","cloudcomputing","databricks","r","spark","sparkr"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/manuparra.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-02-25T22:17:20.000Z","updated_at":"2023-10-27T03:13:36.000Z","dependencies_parsed_at":null,"dependency_job_id":"f3368a15-b73c-4420-8ab5-e81492589dcb","html_url":"https://github.com/manuparra/taller-bigdata-con-r","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manuparra%2Ftaller-bigdata-con-r","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manuparra%2Ftaller-bigdata-con-r/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manuparra%2Ftaller-bigdata-con-r/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manuparra%2Ftaller-bigdata-con-r/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/manuparra","download_url":"https://codeload.github.com/manuparra/taller-bigdata-con-r/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239520174,"owners_count":19652641,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bigdata","cloudcomputing","databricks","r","spark","sparkr"],"created_at":"2024-11-07T09:24:39.507Z","updated_at":"2025-11-07T05:30:39.108Z","avatar_url":"https://github.com/manuparra.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Taller Big Data con Apache Spark + R desde Databricks cloud\n\nProcesamiento de datos Big Data con Spark + R sobre DataBricks\n\nSeminarios de Especialización “Empresa Digital” - Análisis de datos para la toma de decisiones\nUniversidad de Castilla-LaMancha - España\n\nTaller impartido por: Manuel Jesús Parra Royón\n\n\n**Contenido:**\n\n- [Taller Big Data con Apache Spark + R desde Databricks cloud](#taller-big-data-con-apache-spark---r-desde-databricks-cloud)\n    + [R + Spark + Big Data](#r---spark---big-data)\n      - [Introducción](#introducción)\n      - [R](#r)\n      - [Entonces, ¿cuál es el problema? ¿Por qué no se usa para Datos Masivos?](#entonces-cuál-es-el-problema--por-qué-no-se-usa-para-datos-masivos)\n      - [Spark](#spark)\n      - [¿Por qué Spark? ¿Qué ventajas tiene?](#-por-qué-spark-qué-ventajas-tiene)\n      - [SparkR](#sparkr)\n    + [Inicio del entorno de trabajo](#inicio-del-entorno-de-trabajo)\n    + [Inicio de la sesión con Spark y R](#inicio-de-la-sesión-con-spark-y-r)\n    + [Primera prueba de con datos simples](#primera-prueba-de-con-datos-simples)\n    + [Operaciones sencillas con SparkR sobre SparkDataFrames](#operaciones-sencillas-con-sparkr-sobre-sparkdataframes)\n    + [Fuentes de datos para Big Data](#fuentes-de-datos-para-big-data)\n    + [Trabajo con ficheros en formato CSV](#trabajo-con-ficheros-en-formato-csv)\n    + [Escritura de datos o resultados](#escritura-de-datos-o-resultados)\n    + [Trabajo con datos en formato PARQUET -\u003e Igual que CSV u otros ficheros](#trabajo-con-datos-en-formato-parquet-igual-que-csv-u-otros-ficheros)\n      - [Ejercicio básico](#ejercicio-básico)\n    + [Operaciones con SparkDataFrames](#operaciones-con-sparkdataframes)\n      - [Selección de instancias y columnas](#selecci-n-de-instancias-y-columnas)\n      - [Uso de agrupación y agregación](#uso-de-agrupación-y-agregación)\n      - [Operaciones con columnas](#operaciones-con-columnas)\n      - [Añadir columnas](#añadir-columnas)\n      - [Operando con SparkSQL sobre conjuntos masivos de datos](#operando-con-sparksql-sobre-conjuntos-masivos-de-datos)\n    + [Uso de pipes con magittr](#uso-de-pipes-con-magittr)\n    + [Minería de datos](#miner-a-de-datos)\n      - [Algoritmos](#algoritmos)\n      - [Generalized Linear Model](#generalized-linear-model)\n        * [K-MEANS](#k-means)\n      - [Creación de Conjuntos de entrenamiento y prueba](#creaci-n-de-conjuntos-de-entrenamiento-y-prueba)\n      - [Persistencia de los MODELOS generados](#persistencia-de-los-modelos-generados)\n\n### R + Spark + Big Data\n\n![alt text](https://camo.githubusercontent.com/c5bfd73908238855af39f3c8536dfcc6169db4c6/68747470733a2f2f73697465732e676f6f676c652e636f6d2f736974652f6d616e7570617272612f686f6d652f537061726b526c6f676f2e706e67)\n\n#### Introducción\n\nLa tendencia más reciente en el análisis de grandes conjuntos de datos indica la necesidad de un análisis INTERACTIVO de grandes conjuntos de datos.\n\nDebido a ello se han desarrollado herramientas academicas y comerciales para trabajar de este modo con los datos.\n\nEstá claro que cada vez más el uso de herramientas como R para el análisis de datos, ya que permiten una mejora sustancial y más avanzada para el estudio de los datos. R, como sabemos, es ya hoy en día bastante popular y provee de soporte para procesamiento de datos estructurados usando dataframes y lo mejor de todo es que incluye en CRAN un número muy elevado de paquetes para análisis estadístico y visualización.\n\n- R es la herramienta de facto para el análisis de datos\n- R soporta procesamiento de datos estrcuturados dataframes\n- R tiene miles de paquetes para todo tipo de tareas: analíticas, visualización, minería de datos, ...\n\n#### R\n\nEl proyecto R, o el lenguaje R es un lenguaje de programación, un entorno de desarrollo interactivo, y un conjunto de bibliotecas de computación estadistica.\n\nR es un lenguaje interpretado y provee de soporte para ejecución condicional, bucles, etc. R también incluye caracteristicas para computación nmérica, con tipos de datos vectores, matrices, etc. Otra característica fundamental es el uso de dataframes: estructuras de datos en tablas donde cada columna está formada por elementos con su tipo de dato. Estos dataframes pueden ser manipulados para filtrado, agregación, etc.\n\n#### Entonces, ¿cuál es el problema? ¿Por qué no se usa para Datos Masivos?\n\nEl análisis de datos usando R está limitado por la cantidad de memoria disponible en una sola máquina y además R trabaja en un sólo hilo/proceso (parallel), por lo que es poco práctico usar R para grandes conjuntos de datos.\n\n#### Spark\n\nAlgunas de estas limitaciones se han abordado, a través de un mejor soporte de Entrada/Salida, la integración con Hadoop y el diseño de aplicaciones R distribuidas que se pueden integrar con los motores de Bases de Datos más extendidos\n\nPor tanto, analizamos cómo podemos escalar los programas R al tiempo que facilitamos su uso y despliegue a través de varias cargas de trabajo.\n\nHay una serie de beneficios para el diseño de un frontend R que está integrado con Spark:\n\n- Bibliotecas de soporte: Spark, contiene bilbiotecas para trabajar con fuentes de datos y SQL, Machine Learning Distrbuido, análisis de grafos, etc.\n- Fuentes de datos: Desde bases de datos, HDFS, HBase, Cassandra, JSON, CSV, Parquet, ...\n- Rendimiento: Planificación de tareas, generación de código, gestión de memoria, ...\n\nApache Spark es un motor de proposito general para procesamiento de conjuntos de datos masivos. El proyecto inicialmete introdujo el RDD, Resilient Distributed Datasets, una API para computación tolerante a fallos en un entorno de cluster.\n\nMás recientemte muchas más APIs de alto nivel están siendo desarrolladas en Spark. Estás son las siguientes:\n\n- Machine Learning Library (MLLib) una biblioteca para machine learning a gran escala.\n- GraphX, una biblioteca para procesamiento de grafos a gran escala\n- SparkSQL, una API para consultas analíticas en SQL\n\nLas bibliotecas están integradas en el CORE de Spark, por lo que Spark, puede permitir flujos de trabajos complejos, donde consultas SQL pueden ser usadas para preprocesar posteriormente los datos y analizarlos de forma avanzada con la parte de Machine Learning\n\n#### ¿Por qué Spark? ¿Qué ventajas tiene?\n\nDesde el inicio de Hadoop hace más de 10 años, poco a poco han aparecido nuevos problemas que ya no se podían resolver usando el paradigma de MapReduce. Esto ha echo que hayan aparecido nuevos sistemas para afrontar estos problemas, apareciendo :\n\n![alt text](https://camo.githubusercontent.com/0edf6ca76b4be5bc81bc3c7ba05b633ce9abe07a/68747470733a2f2f73697465732e676f6f676c652e636f6d2f736974652f6d616e7570617272612f686f6d652f666c6f72612e706e67)\n\nUna característica importante es que muchas de las aplicaciones ya existentes se han hecho compatibles con Spark y que estén surgiendo nuevas enfocadas en trabajar con Spark en áreas especificas de procesamiento de datos masivos.\n\n![alt text](https://camo.githubusercontent.com/ed13af052590448deb8f371fd38eed392bd34bed/68747470733a2f2f73697465732e676f6f676c652e636f6d2f736974652f6d616e7570617272612f686f6d652f6661756e612e706e67)\n\n\n#### SparkR\n\nSparkR está construido como un paquete en R, luego no es necesarios hacer cosas especiales para que funcione.\n\nEl componente principal de SparkR es un DDF, Distributed Data Frame, que permite procesamiento de datos estructurados utilizando la sintaxis familiar para los usuarios acostumbrados a R.\n\nPara mejorar el rendimiento, sobre grandes conjuntos de datos, SparkR provee de \"evaluación perezosa\" para operaciones sobre dataframes y utiliza además un optimizador de consultas relacionales para optimiar la ejecución.\n\n![alt text](https://camo.githubusercontent.com/0efc69b82a0a47197e9390910e55c4f41247812c/68747470733a2f2f73697465732e676f6f676c652e636f6d2f736974652f6d616e7570617272612f686f6d652f72737061726b5f617263682e706e67)\n\n\n\n### Inicio del entorno de trabajo\n\nAntes de iniciar el trabajo con Spark y R, necesitamos cargar la bilioteca de SparkR\n\n```\n# Añadimos la bibioteca\nlibrary(SparkR)\n```\n\n### Inicio de la sesión con Spark y R\n\nEste bloque no es necesario ya que Databricks ya lo habilita por defecto al iniciar el cluster. Sí es necesario cuando usas un cluster comn Spark genérico.\n```\nsparkR.session(appName=\"Primeros_Pasos\", master = \"local[*]\", sparkConfig = list(spark.driver.memory = \"1g\"))\n```\n\n### Primera prueba de con datos simples\n\nCon SparkR podemos crear un DataFrame de Spark desde un data.frame habitual usado en R.\n\nUn DataFrame es una colección distribuida de datos organizada en columnas.\n\nLos dataframes son conceptualmente equivalentes a bases de datos relacionales o a data.frames en R o Python, pero con una ventaja: son mucho más eficientes para el trabajo con grandes volumenes de datos. Los DataFramespueden ser creados desde una amplio surtido de fuentes muy diferentes. Es decir, casi cualquier cosa puede ser un dataframe, por ejemplo ficheros estructurados, tablas en HIVE, bases de datos externas o RDDs.\n\nLos RDDs son la principal abstracción de datos en Spark. Un RDD es una colección resilente y distribuida de registros. Esta es una de las claves de Spark y es uno de los componentes fundamentales del core de Spark.\n\n```\n# Vamos a usar un dataset sencillo integrado en R\n# El dataset contiene el tiempo de espera entre erupciones y duración \n# de la erupción de un geiser de Yellowstone\nclass(faithful)\n\n# Convertimos un dataframe de R en un DataFrame de Spark, que llamaremos SparkDataFrame\ndf_faithful \u003c- createDataFrame(faithful)\n\n# Vemos el tipo de dataset nuevo\nclass(df_faithful)\n\n# Visualizamos de forma rápida el contenido\nhead(df_faithful)\n\n# Usamos la función printSchema de SparkR para 'deducir' el esquema de datos (la estructura)\nprintSchema(df_faithful)\n```\n\nUn SparkDataFrame puede ser registrado como una vista temporal en SparkSQL y que permite ejecutar sentencias SQL sobre los datos. La funcionalidad de SQL permite a las aplicaciones y flujos de trabajo ejecutar consultas SQL de forma programatica, devolviendo el resultado también como SparkDataFrame.\n\nEsto es importante, ya que todas las transformaciones a los conjuntos de datos que están en formato SparkDataFrames, siguen siendo SparkDataFrames, lo que hace que toda su manipulación corra por parte de Spark con todas las ventajas que eso tiene:\n\n- Volumen masivo de datos\n- Almacenamiento distribuido\n- Resilencia\n\n###  Operaciones sencillas con SparkR sobre SparkDataFrames\n\nEn estos ejemplos vamos a tratar de ver una parte muy muy simple sobre la manipulación de los datos en el formato que entiende SparkR.\n\n```\n# Contamos los elementos a partir de un filtro normal\ncount(filter(df_faithful,\"eruptions\u003e3.0\"))\n\n# Convertimos a vista temporal de datos en SparkSQL y le damos el nombre faithful a la 'tabla'\ncreateOrReplaceTempView(df_faithful,\"faithful\")\n\n# Usamos SparkSQL para hacer consultas a los datos.\neruptions_sql \u003c- sql(\"SELECT eruptions FROM faithful WHERE eruptions \u003e= 3.0\")\n\n# Contamos el resultado\ncount(eruptions_sql)\n\n# Mostramos un resumen\nhead(eruptions_sql)\n```\n\n### Fuentes de datos para Big Data\n\n\nHoy en día el trabajo con BigData parece que siempre está asociado al ecosistema HADOOP. Hace unos años esto significaba que si también eras un buen programador en JAVA, trabajar en tal entorno, incluso un simple programa para hacer un WORDCOUNT, implicaba varias docenas de líneas de código.\n\nPero hace 6-7 años la cuestión ha cambiado gracias a Apache Spark con su API de estilo funcional. Está escrito en SCALA pero también puede ser utilizado desde Python, JAVA y como estais viendo por este Taller: también en R\n\nDentro de una sesión de Spark, las aplicaciones pueden crear SparkDataFrames desde variadas fuentes de datos, como por ejemplo: un fichero local (data.frame), desde HDFS (hdfs:///), desde tablas en HIVE o desde otras múltiples fuentes de datos (AmazonS3, etc).\n\nConcretamente las principales fuentes u orígenes de datos desde las que cargar datos son los siguientes:\n- Ficheros locales\n- Ficheros en sistemas distribuidos de almacenamiento Hadoop HDFS\n- Sistemas de almacenamiento de datos tipo HIVE\n- Desde bases de datos relacionales a través de JDBC\n- ...\n\nUna cosa son las fuentes de datos y otras cosa son los tipo de fuentes de datos. El tipo de fuente de datos puede ser visto como el formato de los datos.\n\nLos conjuntos de datos pueden están almacenados en diferentes formatos, los más utilizados para SparkR (y Spark):\n\n- Ficheros planos y CSV\n- Ficheros JSON\n- Ficheros de tipo avro (row-based)\n- Ficheros de tipo parquet (column-based)\n- Ficheros de tipo orc (column-based)\n\n### Trabajo con ficheros en formato CSV\n\nPara la lectura de datos con SparkR usamos la función read.df( )\n\n```\n# Sólo indicamos un fichero concreto .... No hay problema Spark es muy listo ! ;)\ndf \u003c- read.df(\"dbfs:/FileStore/shared_uploads/TU_USUARIO/buy_costumers_amazon01.csv\", \"csv\", header = \"true\", inferSchema = \"true\")\nprintSchema(df)\ncount(df)\nhead(df)\n```\n\n```\n# Sólo indicamos un fichero concreto .... No hay problema Spark es muy listo ! ;)\ndf \u003c- read.df(\"dbfs:/FileStore/shared_uploads/TU_USUARIO/buy_costumers_amazon01.csv\", \"csv\", header = \"true\", inferSchema = \"true\")\nprint(\"Estructura sin parsear:\")\nprintSchema(df)\n\n# Creamos un esquema para definir cual será la estructura del fichero a leer.\nschema_amazon \u003c- structType(structField(\"id\", \"integer\"),\n                     structField(\"first_name\", \"string\"),\n                     structField(\"last_name\", \"string\"),\n                     structField(\"buy_hours\", \"string\"),\n                     structField(\"amount\", \"double\"),\n                     structField(\"credit_card\", \"string\"))\n\ndf \u003c- read.df(\"dbfs:/FileStore/shared_uploads/TU_USUARIO/buy_costumers_amazon01.csv\", \"csv\", header = \"true\", schema=schema_amazon)\nprint(\"Estructura parseada:\")\nprintSchema(df)\nhead(df)\n\n```\n\n\n\nSi queremos leer todos los ficheros de un directorio sin entrar en los subdirectorios:\n\n```\n# Esto leería todos los ficheros de la carpeta pero no entraría a cada subdirectorio... Spark no eres muy listo !\ndf \u003c- read.df(\"dbfs:/FileStore/shared_uploads/TU_USUARIO/directorio/\", \"csv\", header = \"true\", inferSchema = \"true\", schema=schema_amazon)\ncount(df)\n```\n\n### Escritura de datos o resultados\n\nUna vez que hemos realizado transformaciones con los datos del SparkDataFrame, podemos dejarlo en memoria o bien pasarlo a DISCO (local) o HDFS (distribuido).\n\nLa API de fuentes de datos puede también ser usada para guardar y almacenar SparkDataFrames en múltiples formatos. Por ejemplo podemos almacenar el SparkDataDrame desde/hacia otros formatos como CSV, PARQUET usando la función write.df.\n\nEsto da mucha versatilidad, ya que independiente del tipo de fuente, podemos almacenarlo y leerlo desde cualquiera otra fuente. Como no podía ser de otra forma.\n\n```\n# Escritura desde CSV a CSV:\nwrite.df(df, path = \"resultado_df_full.csv\", source = \"csv\", mode = \"overwrite\")\n\n# Escritura desde CSV a PARQUET\nwrite.df(df, path = \"resultado_df_full.parquet\", source = \"parquet\", mode = \"overwrite\")\n```\nEn mode podemos usar 'append', 'overwrite', 'error', 'ignore'.\n\n### Trabajo con datos en formato PARQUE -\u003e Igual que CSV u otros ficheros\n\nParquet es un formato de almacenamiento en columnas disponible para cualquier proyecto dentro del ecosistema de Hadoop, enfocado en la mejora del procesamiento de datos, modelado de datos y programación.\n\nParquet está diseñado para soportar esquemas de compresión y codificación muy eficientes. Múltiples proyectos han demostrado el impacto en el rendimiento de aplicar el correcto sistema de compresión y codificación a los datos. Parquet permite que los esquemas de compresión se especifiquen a nivel de columna.\n\nEs un formato bien estructurado para ser usado para problemas de BigData.\n\nLa estructura del fichero se segmenta en N columnas partidas en M grupos de filas:\n\n\n```\n# Leemos un dataset que contiene los datos en formato Parquet\ndf_parquet \u003c- read.df(\"dbfs:/FileStore/shared_uploads/TU_USUARIO/parquet/\", \"parquet\")\n```\n\n\n```\n# Vemos la estructura del fichero y sus atributos\nprintSchema(df_parquet)\n\n```\n\n Vemos un resumen de los datos del fichero ...\n\n```\nhead(df_parquet)\n```\n\n```\n# Hacemos un pequeño cambio en el nombre de las columnas del SparkDataFrame.\ncolnames(df_parquet) \u003c- c(\"user_id\",\"cat\",\"R1\",\"R2\",\"R3\")\n```\n\nVemos de nuevo el cambio de las columnas:\n\n```\nhead(df_parquet)\n# Contamos los registros del dataset ... es pequeño, no es BigData...\ncount(df_parquet)\n```\n\nAplicamos unas transformaciones sencillas al SparkDataFrame, copiando la tabla en una Vista Temporal para poder trabajar con ella en SQL.\n\n```\n# Creamos una vista SparkDataFrame con el nombre \"tmp_parquet\".\n# Este nombre tmp_parquet es el nombre que se usará ahora.\ncreateOrReplaceTempView(df_parquet,\"tmp_parquet\")\n```\n\n\nUna vista temporal, permite trabajar con una copia temporal de los datos.\n\nContamos el número de registros:\n\n\n```\n# Usamos SparkSQL para hacer consultas a los datos.\ncount_rows \u003c- sql(\"SELECT user_id,count(user_id) as registers FROM tmp_parquet group by user_id\")\n# Cuidado como obtener las cosas en SparkR: ---\u003e Nooooooooo !!!! ;)\n# print(collect(count_rows))\n```\n\nCompara el tiempo la opción anterior y la siguiente:\n\n```\nhead(count_rows)\n```\n\n\n\nSi usamos una vista temporal, está estará disponible durante toda la sesión a no ser que se elimine la vista temporal con unpersist(....)\n\nProbamos con otro ejemplo, para saber las categorías que hay:\n\n```\n# createOrReplaceTempView(df_parquet,\"tmp_parquet\") --\u003e No volvermos a cargarla!\n# Usamos SparkSQL para hacer consultas a los datos.\ncategories \u003c- sql(\"SELECT cat FROM tmp_parquet group by cat\")\nhead(categories)\n```\n\n#### Ejercicio básico\n\n¿Cómo se calcularía el número de elementos de cada categoría?\n\n```\n# createOrReplaceTempView(df_parquet,\"tmp_parquet\")   --\u003e No volvemos a cargarla !\n# Usamos SparkSQL para hacer consultas a los datos.\ncategories_list \u003c- sql(\"SELECT cat,count(user_id) as num_users FROM tmp_parquet group by cat\")\n```\n\n```\nhead(categories_list)\n```\n\n¿Cuando usuarios distintos hay y que suma total tienen por usuario?\n\n```\n# createOrReplaceTempView(df_parquet,\"tmp_parquet\") --\u003e No volvemos a cargarla!\n# Usamos SparkSQL para hacer consultas a los datos.\ntable_summary \u003c- sql(\"SELECT user_id,SUM(R1) as sum_index FROM tmp_parquet group by user_id\")\n```\n```\ncount(table_summary)\nhead(table_summary)\n```\n\n```\nunpersist(table_summary)\n```\n\n\n**Escritura de los datos** \n\nAl igual que con los otros formatos, se pueden exportar a cualquier otro.\n\n```\n# Escritura del fichero de formato parquet a formato parquet\nwrite.df(finals, path = \"resultsfinals.parquet\", source = \"parquet\", mode = \"overwrite\")\n\n# Escritura del fichero de formato csv a formato a CSV\nwrite.df(finals, path = \"resultsfinals.csv\", source = \"csv\", mode = \"overwrite\")\n```\n\n### Operaciones con SparkDataFrames\n\nCargamos un conjunto de datos **masivo** desde el repositirio de datasets.\n\nEl dataset que vamos a usar para el procesamiento de dato masivos, corresponde con un conjunto de datos de los registros de viaje en TAXI, donde se capturan las fechas y horas de recogida y devolución de pasajeros, lugares de recogida y entrega (coordenadas), distancias de viaje, tarifas detalladas, tipos de tarifas, tipos de pago y conteos de pasajeros que van en el taxi.\n\nEl dataset tiene MUCHAS posibilidades de procesamiento y también extracción de conocimiento.\n\nEstos conjuntos de datos adjuntos fueron recopilados y proporcionados por la Comisión de Taxisde Nueva York (TLC) http://www.nyc.gov/html/tlc/html/about/trip_record_data.shtml\n\nCaracterísticas del conjunto de datos original:\n\n- El conjunto de datos NYCTaxiTrips en total tiene sobre 267GB, que pueden ser manejados sin problema por SparkR (en un cluster real, no sobre una máquina virtual sencilla).\n- En total contiene 1100 millones de registros.\n- Más información de como se gestionan 1100 millones de instancias en la siguiente web y se soluciona este problema problema real: http://toddwschneider.com/posts/analyzing-1-1-billion-nyc-taxi-and-uber-trips-with-a-vengeance/\n\nMás datasets masivos de NYCTaxiTrips en: http://www.nyc.gov/html/tlc/html/about/trip_record_data.shtml\n\nPrimero revisamos los distintos dataset que se han preparado en: \n- yellow_tripdata_2016-02_small2.csv\n- yellow_tripdata_2016-02_small3.csv\n\n```\n# Cargamos una versión reducida de los datos en CSV\ndf_nyctrips \u003c- read.df(\"dbfs:/FileStore/shared_uploads/manuparr.a@gmail.com/yellow_tripdata_2016-02_small3.csv\", \"csv\", header = \"true\", inferSchema = \"true\")\n```\n\nEstudiamos de manera superficial el dataset\n\n```\n# Comprobamos los campos del dataset\nprintSchema(df_nyctrips)\n\n# Comprobamos como son los datos:\nhead(df_nyctrips)\n\n# Contamos el total del registros:\ncount(df_nyctrips)\n```\n\n\n#### Selección de instancias y columnas\n\nPara la selección de columnas y filas, usamos select y filter.\n\nTodas las operaciones se pueden combinar para producir un nuevo dataset o SparkDataFrame. Son equivalentes a usar SPARKSQL .\n\nEstas operaciones son esenciales si queremos transformar el dataset en otra versión preprocesada del mismo.\n\n```\n# Seleccionamos sólo la columna longitud, por el id de la columna\n# Por ID de columna \nhead(select(df_nyctrips,df_nyctrips$pickup_longitude))\n```\n\n```\n# Seleccionamos sólo la columna longitud, por el nombre de la columna.\n# Por nombre de columna del dataset\nhead(select(df_nyctrips,\"pickup_longitude\"))\n```\n\n\n\nPara aplicar filtros de para las filas usamos filter que admite expresiones con operadores condicionales:\n\n```\u003c = \u003e ! \u0026 | ...```\n\n```\n# Aplicamos un filtro para ver los viajes aquellos viajes de taxi de más de 10 millas.\nhead(filter(df_nyctrips, df_nyctrips$trip_distance \u003e 10 \u0026 df_nyctrips$total_amount\u003e 20 ))\n```\n```\n# Aplicamos un filtro para ver los viajes aquellos viajes de taxi de más de 10 millas y el importe mayor de $ 20\nhead(filter(df_nyctrips, df_nyctrips$trip_distance \u003e 10 \u0026 df_nyctrips$total_amount\u003e 20 ))\n```\n```\n# Aplicamos un filtro para ver el viaje más caro en Taxi que se ha hecho:\nhead( agg(df_nyctrips ,max = max(df_nyctrips$total_amount)))\n```\n```\n# Aplicamos un filtro para ver el viaje menos caro en Taxi que se ha hecho:\nhead(agg(df_nyctrips, min = min(df_nyctrips$total_amount)))\n```\n\n#### Uso de agrupación y agregación\n\nLos SparkDataFrames soportan funciones de agregado despues de agrupar.\n\nPor ejemplo podemos:\n\n```\n# Agrupamos por Vendedor y mostramos el número de viajes.\nhead(summarize(groupBy(df_nyctrips, df_nyctrips$VendorID), count = n(df_nyctrips$VendorID)))\n```\n```\n# Agrupamos por Vendedor y mostramos el número de viajes.\nhead(summarize(groupBy(df_nyctrips, df_nyctrips$VendorID), max = max(df_nyctrips$total_amount)))\n```\n\n```\n# Agrupamos y ordenamos\nnumsum \u003c- summarize(groupBy(df_nyctrips, df_nyctrips$VendorID), num = n(df_nyctrips$VendorID))\nhead(arrange(numsum,asc(numsum$num)))\n```\n\n```\n# Agrupamos por numero de pasajeros y mostramos el numero de viajes\ntrips_passenger \u003c- summarize(groupBy(df_nyctrips, df_nyctrips$passenger_count), count = n(df_nyctrips$passenger_count))\n```\n\n```\n# Cuidado con el COLLECT !\ntrips_df \u003c- head(collect(trips_passenger))\n```\n\n```\nhead(trips_df)\n```\n\n#### Operaciones con columnas\n\nOtras operaciones muy familiares en R, corresponden con la manipulación o transformación de valores en los registros de un dataset. En este caso la manipulación es muy sencilla:\n\n```\n# Convertimos la columna de millas a kilómetros, igual que en R.\ndf_nyctrips$trip_distance \u003c- df_nyctrips$trip_distance*1.6\n```\n\n```\nhead(df_nyctrips)\n```\n\n#### Añadir columnas\n\n```\n# Usamos mutate para añadir columnas que operan con elementos de las demás columnas.\n\n# mutate(sql_nyc,  uniform = rand(10),  normal  = randn(27))\n\nhead(mutate(df_nyctrips,  uniform = rand(10),  normal  = randn(27)))\nhead(mutate(df_nyctrips,  uniform =df_nyctrips$total_amount*1.1355,  normal  = randn(27)))\n```\n\n```\n# Otro modo de hacerlo es:\nhead(withColumn(df_nyctrips,\"uniform\",rand(20)))\n```\n\n#### Operando con SparkSQL sobre conjuntos masivos de datos\n\n\n\nTodas las funciones de manejo de datos que se han usado con SparkR, pueden hacerse de una forma sencilla e intuitiva con SparkSQL\n\n```\n# sql_nyc es nuestro DataFrameSpark de SQL\ncreateOrReplaceTempView(sql_nyc,\"slqdf_filtered_nyc\")\n\n# Hacemos una consulta para extraer el viaje de mayor distancia de cada venderor.\nresults \u003c- sql(\"select VendorID, MAX(trip_distance) from slqdf_filtered_nyc GROUP BY VendorID \")\n```\n\n\n```\n# Vemos el resultado.\nhead(results)\n```\n\n\n\n\nBuscamos el total de kilómetros recorridos por cada vendedor:\n```\nresults \u003c- sql(\"select VendorID, SUM(trip_distance) from slqdf_filtered_nyc GROUP BY VendorID \")\n\n# Vemos el resultado\nhead(results)\n```\n\n\n\nCalculamos el tiempo en segundos\n```\nresults \u003c- sql(\"select VendorID, SUM(trip_time) from slqdf_filtered_nyc GROUP BY VendorID \")\n\n# Vemos los resultados\nhead(results)\n```\n\n\n\nCalculamos el tiempo en minutos\n```\nresults \u003c- sql(\"select VendorID, SUM(trip_time)/60.0 as min_trip from slqdf_filtered_nyc GROUP BY VendorID \")\n\n# Vemos los resultados\nhead(results)\n```\n\n\n\nBuscamos la ganacia total cada vendedor:\n\n```\nresults \u003c- sql(\"select VendorID, SUM(total_amount)*1.10373 as Total_Amount_Euro from slqdf_filtered_nyc GROUP BY VendorID \")\n\n# Vemos el resultado\nhead(results)\n```\n\n\n\nCalculamos la media y la desviación típica del tiempo de recorrido y ganancia por numero de personas:\n\n```\nresults \u003c- sql(\"select passenger_count, AVG(trip_time), AVG(total_amount) ,AVG(trip_distance)   \n                from slqdf_filtered_nyc \n                GROUP BY passenger_count \n                order by passenger_count ASC \")\nhead(results)\n```\n\n\n\nCoeficiente de correlación\n\n\n```\nresults \u003c- sql(\"select corr(total_amount,trip_distance) as correlation_coef\n                from \n                slqdf_filtered_nyc\")\n# Ver resultados\nhead(results)\n```\n\n\n```\nresults \u003c- sql(\"select corr(total_amount,trip_time) as correlation_coef\n                from \n                slqdf_filtered_nyc\")\nhead(results\n```\n\n```\nresults \u003c- sql(\"select corr(trip_time,trip_distance) as correlation_coef\n                from \n                slqdf_filtered_nyc\")\nhead(results)\n```\n\n\n### Uso de pipes con magittr\n\n\n\nEl paquete magrittr permite:\n\n- mejorar el tiempo de desarrollo y\n- mejorar enormemente la legibilidad y mantenibilidad del código.\n\nPara usarlo hay que importar la biblioteca magrittr dentro del proyecto y apartir de ese momentos podemos utilizar el operador\n\n```%\u003e%``` para concaternar operaciones y poder trabajar con flujos de datos y pipelines.\n\nProvee de un operador que sirve para hacer pipes con el cual se puede encauzar un valor hacia adelante dentro de una expresión o llamada a función.\n\nVeamos todas las operaciones que hemos realizado sobre los datos y su equivalente con pipes.\n\n```\n# Hacemos una copia del SparkDataFrame para usarla en una vista temporal en SQL\ncreateOrReplaceTempView(df_nyctrips,\"slqdf_filtered_nyc\")\n\n# Hacemos una selección de los registros, donde calculamos el tiempo del viaje de cada viaje\nsql_nyc \u003c- sql(\"select VendorID,INT(unix_timestamp(tpep_dropoff_datetime)- unix_timestamp(tpep_pickup_datetime)) AS trip_time,passenger_count,trip_distance,total_amount from slqdf_filtered_nyc\")\n\nhead(sql_nyc)\n```\n\n```\n# Usamos magrittr\nlibrary(magrittr)\n\n# results \u003c- sql(\"select VendorID, MAX(trip_distance) from slqdf_filtered_nyc GROUP BY VendorID \")\n#summarize(groupBy(df_nyctrips, df_nyctrips$passenger_count), count = n(df_nyctrips$passenger_count))\n\ndf_nyctrips %\u003e% \n        groupBy( df_nyctrips$passenger_count) %\u003e%\n        summarize(count = n(df_nyctrips$passenger_count)) %\u003e%\n        head()\n```\n\n```\ndf_nyctrips %\u003e% \n        groupBy( df_nyctrips$passenger_count) %\u003e%\n        summarize( avg_total_amount=avg(df_nyctrips$total_amount) ,avg_trip_distance=avg(df_nyctrips$trip_distance)) %\u003e%\n        head()\n```\n\n```\ndf_nyctrips %\u003e% \n         groupBy( df_nyctrips$passenger_count) %\u003e%\n        summarize(min = min(df_nyctrips$trip_distance),max = max(df_nyctrips$trip_distance)) %\u003e%\n        head()\n```\n\n```\ndf_nyctrips %\u003e% \n         groupBy( df_nyctrips$passenger_count, hour(df_nyctrips$tpep_pickup_datetime)) %\u003e%\n        summarize(total_pickup = n(df_nyctrips$tpep_pickup_datetime)) %\u003e%\n        head()\n```\n\n```\ncount(sql_nyc)\nnum_regs \u003c- as.integer(count(sql_nyc))\n\n# Mostramos el número de registros\nprint(num_regs)\n```\n\n### Minería de datos \n\nLa biblioteca de SparkR actualmente soporta los siguientes algoritmos de aprendizaje automático :\n- modelo lineal generalizado,\n- modelo de regresión de supervivencia con tiempo de fallo acelerado (AFT),\n- modelo Bayes Naive y\n- modelo KMeans.\n\nSparkR utiliza MLlib para entrenar el modelo. Por tanto se puede analizar el resumen del modelo ajustado, predecir y hacer predicciones sobre nuevos datos y escribir/leer el modelo para guardar / cargar los modelos ajustados.\n\nAdemás de ello, al igual que ocurre cuando usamos cualquier funcion en R, SparkR soporta el uso de fómulas, lo cual mejora bastante la adopción de SparkR para análisis de datos másivos. SparkR soporta un subconjunto de los operadores de fórmula R disponibles para el ajuste del modelo, incluyendo '~', '.', ':', '+' y '-'.\n\nDado que parte de SparkR está modelado en el paquete dplyr, ciertas funciones de SparkR comparten los mismos nombres con los de dplyr. Dependiendo del orden de carga de los dos paquetes, algunas funciones del paquete cargado primero son enmascaradas por las del paquete cargado después.\n\n```\ncov in package:stats\nfilter in package:stats\nsample in package:base\n```\n\nPor tanto hay siempre que usar el paquete que queramos usar al final de la importación de las bibliotecas para que se haga efectiva la función que queremos para SparkR.\n\n#### Algoritmos\n\nEl paquete SparkR soporta las siguientes funcionalidades de Machine Learning y Data mining\n\n\n#### Generalized Linear Model\n\nUsamos la función de R\n\n```\ngaussianDF \u003c- iris\ngaussianTestDF \u003c- iris\ngaussianGLM \u003c- glm(data = gaussianDF, Sepal.Length ~ Sepal.Width + Species, family = \"gaussian\")\n\nsummary(gaussianGLM)\n```\n\n\n\nUsamos la función para glm de SparkR\n\n\n```\nirisDF \u003c- suppressWarnings(createDataFrame(iris))\n# Fit a generalized linear model of family \"gaussian\" with spark.glm\ngaussianDF \u003c- irisDF\ngaussianTestDF \u003c- irisDF\ngaussianGLM \u003c- spark.glm(gaussianDF, Sepal_Length ~ Sepal_Width + Species, family = \"gaussian\")\n\n# Model summary\nsummary(gaussianGLM)\n```\n\n**¿Qué diferencias hay entre ambos?**\n\nCalculamos el modelo\n\n```\n# Calculamos la predicción\ngaussianPredictions \u003c- predict(gaussianGLM, gaussianTestDF)\n# Mostramos las predicciones\nshowDF(gaussianPredictions)\n\n# Usamos la función de R de glm con la familia gaussian\ngaussianGLM2 \u003c- glm(Sepal_Length ~ Sepal_Width + Species, gaussianDF, family = \"gaussian\")\nsummary(gaussianGLM2)\n\n# Ahora usamos la función de glm de spark para la familia binomial.\nbinomialDF \u003c- filter(irisDF, irisDF$Species != \"setosa\")\nbinomialTestDF \u003c- binomialDF\nbinomialGLM \u003c- spark.glm(binomialDF, Species ~ Sepal_Length + Sepal_Width, family = \"binomial\")\n\n# Imprimimos el modelo\nsummary(binomialGLM)\n\n# Obtenemos la predicción\nbinomialPredictions \u003c- predict(binomialGLM, binomialTestDF)\nshowDF(binomialPredictions)\n```\n\n##### K-MEANS\n\n\n```\nlibrary(ggplot2)\nggplot(iris, aes(Petal.Length, Petal.Width, color = Species)) + geom_point()\n\nset.seed(20)\nirisCluster \u003c- kmeans(iris[, 3:4], 3, nstart = 20)\nirisCluster\n```\n\n```\n# Ajustamos un modelo k-medias. \n\nirisDF \u003c- suppressWarnings(createDataFrame(iris))\nkmeansDF \u003c- irisDF\nkmeansTestDF \u003c- irisDF\nkmeansModel \u003c- spark.kmeans(kmeansDF, ~ Sepal_Length + Sepal_Width + Petal_Length + Petal_Width,\n                            k = 3)\n\n# Vemos el resumen\nsummary(kmeansModel)\n\n# Vemos los resultados del ajuste\nshowDF(fitted(kmeansModel))\n\n# y vemos la predicción\nkmeansPredictions \u003c- predict(kmeansModel, kmeansTestDF)\nshowDF(kmeansPredictions)\n\n# Mostramos la información de los grupos.\ntable(kmeansModel$cluster, iris$Species)\n```\n\n\n#### Creación de Conjuntos de entrenamiento y prueba\n\nExisten varias formas de hacer los conjuntos de prueba y test. Se pueden usar las funciones de muestreo (sample) que trabajan sobre los SparkDataFrames.\n\n```\ntrain_df \u003c- sample(df_training, withReplacement=FALSE, fraction=0.85, seed=42)\ntest_df \u003c- except(df_training, train_df)\n\ncount(train_df)\ncount(test_df)\n```\n\n#### Persistencia de los MODELOS generados\n\nSi necesitamos almacenar el modelo que hemos ajustado podemo hacerlo mediante el uso de la funcion write.ml. Al igual que luego podemos recuperarlo con read.ml.\n\n```\nmodelPath \u003c- tempfile(pattern = \"ml\", fileext = \".tmp\")\nwrite.ml(gaussianGLM, modelPath)\ngaussianGLM2 \u003c- read.ml(modelPat\n```\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanuparra%2Ftaller-bigdata-con-r","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmanuparra%2Ftaller-bigdata-con-r","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanuparra%2Ftaller-bigdata-con-r/lists"}