Tras una breve introducción en la que os mostramos el objetivo de DIA4RA y nuestra intención de hacer un recorrido por las principales herramientas que estamos empleando, ha llegado el momento de ponernos manos a la obra. Y qué mejor manera de comenzar que hacerlo por el tejado, la librería que vamos a utilizar para implementar los algoritmos que dotarán de inteligencia al robot. Como habréis adivinado por el título, se trata de Tensorflow.

TENSORFLOW Y EL CÁLCULO DE GRADIENTES

A diferencia de lo que muchos podrían pensar, esta librería desarrollada por Google no es únicamente aplicable a casos de uso de Inteligencia Artificial. En realidad, es un framework de computación numérica que, entre muchas otras posibilidades, permite el cálculo de gradientes de forma automática. Muchos algoritmos de Deep Learning emplean como base de aprendizaje la técnica de “Gradient Descent” que, a muy grandes rasgos, consiste en intentar encontrar el valor mínimo global de la función de error del problema que se pretende aprender a solucionar. Para ir avanzando en la búsqueda de ese valor mínimo, en cada paso de dicho proceso de aprendizaje se calcula el gradiente de la función de error en ese punto, con el objetivo de conocer la dirección hacia donde hay que dirigirse para ir minimizando el error cometido. Como Tensorflow facilita este cálculo y tiene a un gigante como Google manteniendo este proyecto, se ha popularizado a la hora de aplicarse en el ámbito de las Redes Neuronales Artificiales.

CÓMO FUNCIONA TENSORFLOW

Tensorflow es multi-plataforma y para ello, proporciona un motor denominado “Tensorflow Distributed Execution Engine” cuyo “core” está implementado en C++. Su objetivo es permitir la ejecución en múltiples arquitecturas como dispositivos móviles, sistemas embebidos,  CPUs, GPUs… Incluso TPUs (Tensor Processing Units), que es un HW desarrollado por Google optimizado para realizar de forma muy eficiente operaciones con “tensores”. Por encima de esta capa se asientan “frontends” en distintos lenguajes de programación como Python, C++, Java, Julia, Go, Javascript, etc. Pero, sin duda, la versión más utilizada es la de Python que además ofrece APIs con diversos niveles de abstracción. En este artículo vamos a hacer un breve recorrido por la API de Python de Bajo Nivel de Tensorflow y en los siguientes nos centraremos en una de las APIs de Alto Nivel que más se está impulsando desde el equipo de desarrolladores de Tensorflow. Esta coincide con la que estamos empleando para codificar los algoritmos en DIA4RA: la Estimator API. La principal razón de haber tomado esta elección se debe a que permite emplear el mismo código tanto para entrenar modelos y hacer inferencia en local como para subir el código al Cloud y realizar un entrenamiento distribuido y posteriormente exportar dicho modelo ya entrenado y emplearlo (servirlo) para poder realizar predicciones desde la nube. Otra API de Alto Nivel de Tensorflow bastante conocida por su simplicidad es Keras, que también se utilizará en este proyecto pero siempre combinada con la estructura de programación de la Estimator API para mantener un mismo estilo entre diferentes modelos.

API DE PYTHON DE BAJO NIVEL DE TENSORFLOW

Como ya tendréis ganas de empezar a cacharrear con Tensorflow, vamos a comenzar mostrando algunos de los componentes esenciales de su API de Bajo Nivel.

Tensores

El elemento fundamental del que toma su nombre Tensorflow es el tensor y se implementa mediante un nodo tf.Tensor. Puede definirse como un array n-dimensional  y se corresponde con su estructura básica de almacenamiento de datos. Cada tensor tiene un nombre, un rank, un shape y un tipo.

Operaciones

Los datos contenidos en los tensores se corresponden con las entradas de operaciones que realizan cálculos con dicha información. Cuando se consulta documentación de Tensorflow, a menudo se verá que se hace referencia a las operaciones empleando el término ‘ops’ y formalmente genera un nodo tf.Operation. Las operaciones son nodos que toman cero o más tensores como entrada, realizan cálculos a partir de esos datos y devuelven cero o más tensores como salida. Para instanciar una op hay que llamar a su constructor, que recibirá los tensores necesarios. Por ejemplo, una operación como tf.multiply puede tomar 2 entradas y cuando sea ejecutada devolverá el resultado de su producto.

import tensorflow as tf import numpy as np # Inicialización de arrays de numpy que actuarán como los tensores de entrada de la op a = np.array([2, 3], dtype=np.int32) b = np.array([4, 5], dtype=np.int32) # Creación de la op de multiplicación resultado = tf.multiply(a, b)

Si se desea añadir una nueva op que no esté presente entre las ofrecidas por Tensorflow, será necesario seguir los pasos indicados en esta url de la documentación oficial.

Resumiendo, el proceso conlleva realizar las siguientes acciones:

  1. Registrar la nueva operación en un fichero C++.
  2. Implementar la op en C++.
  3. De forma opcional, crear un wrapper en Python.
  4. También opcionalmente, escribir una función que calcule el gradiente de esa op.
  5. Probar dicha op.

Grafos

Un grafo está formado por un conjunto de objetos:

Los programas de Tensorflow que no emplean el modo Eager Execution (en esta serie de artículos veremos en qué consiste) se componen de 2 fases diferenciadas:

Primera fase: construcción del grafo

La primera de ellas es la construcción del grafo de operaciones. Automáticamente, Tensorflow crea un grafo por defecto. Cada vez que se declara una operación, será añadida también de forma automática al grafo por defecto (con la excepción, de la que hablaremos a continuación, de que otro grafo se haya fijado momentáneamente como el grafo por defecto).

Programando con la API de Bajo Nivel de Tensorflow

Si se define la operación “resultado” y se consulta si pertenece al grafo por defecto, la respuesta será “True”.

Pero también existe la posibilidad de crear otros grafos mediante la instrucción tf.Graph(). Además, como se comentó anteriormente, se puede establecer temporalmente uno de esos grafos (“g”) como el grafo por defecto mediante un bloque “with”. Si definimos operaciones dentro del ámbito de dicho bloque “with”, esas operaciones serán añadidas al grafo “g”.

En la siguiente captura, se ha creado un grafo “g” y se ha establecido mediante un bloque “with” como el grafo por defecto. Además se ha declarado una operación “resultado2” que será añadida al grafo “g”. Cuando se consulte si “resultado2” pertenece al grafo por defecto se obtendrá un “False”. Pero cuando se compruebe si pertenece al grafo “g” la respuesta será “True”.

Programando con la API de Bajo Nivel de Tensorflow

Un aspecto fundamental del funcionamiento de Tensorflow es que durante la fase de construcción del grafo ninguna operación es evaluada. Solo se añaden dichas operaciones al grafo o grafos. Por lo que si se intenta obtener el valor de la op “resultado” lo único que se obtendrá es la estructura de ese tensor, como puede observarse en la siguiente imagen:

Programando con la API de Bajo Nivel de Tensorflow

Segunda fase: ejecución de operaciones del grafo

La segunda de las fases de las que se compone un programa de Tensorflow es la de ejecución de las operaciones del grafo. Para llevar a cabo esta etapa será necesario crear un objeto tf.Session().

Como AIDA reclama nuestra atención, en los próximos artículos de esta serie continuaremos mostrando la forma de crear tanto sesiones como el resto de los componentes de lo que se puede considerar el Core de Tensorflow. ¡Os esperamos por aquí!

MÁSTER EXPERTO EN BIG DATA & ANALYTICS

Gracias al Master en Big Data Analytics 100% Online tendrás amplios conocimientos sobre las herramientas y técnicas analíticas necesarias para la modelización de los principales retos de negocio, con el fin de mejorar la toma de decisiones a través de los datos y el conocimiento.

Ya estamos aquí para continuar el relato donde lo dejamos en el artículo anterior de esta serie. La trama quedó en suspense después de mostrar que un programa de Tensorflow se divide en 2 fases. La primera consiste en la construcción del grafo que alberga por un lado las operaciones a realizar y por otro los tensores que contienen los valores que alimentan a dichas operaciones. La segunda etapa se basa en la creación de un objeto de sesión que permitirá ejecutar el grafo sobre dispositivos locales o remotos. Sigamos con este recorrido por los principales componentes del Core de Tensorflow.

Sesión

La clase tf.Session permite conectar un programa cliente, que actúa como frontend en alguno de los lenguajes disponibles como Python, gracias al “Tensorflow Distributed Execution Engine” de C++. Un objeto de esta clase tf.Session proporciona el entorno para ejecutar objetos tf.Operation y evaluar objetos tf.Tensor. Esto lo hace tanto en dispositivos (como CPUs, GPUs, TPUs) de la máquina local como de máquinas remotas. También proporciona el entorno para cachear el grafo que tenga asociada dicha sesión.

Como se ha comentado, en DIA4RA vamos a emplear la API de alto nivel Estimator que, entre otros beneficios, creará y gestionará el objeto tf.Session por nosotros. Además, nos permitirá abstraernos de escribir el código de bajo nivel necesario para poder realizar un entrenamiento distribuido entre múltiples máquinas. Por ello, aunque no vayamos a manejar sesiones de forma explícita en nuestro proyecto, vamos a mostrar una pequeña introducción en las siguientes líneas.

El constructor de esta clase recibe de forma opcional 3 argumentos:

Una práctica habitual a la hora de crear una sesión es la de hacerlo mediante un bloque “with” de Python. De esta forma, la sesión estará activa dentro del ámbito de dicho bloque y al salir se cerrará automáticamente y se liberarán sus recursos. En caso de no emplearse un bloque “with” será necesario cerrar explícitamente esa sesión mediante tf.Session.close para que se liberen sus recursos.

Para realizar la ejecución propiamente dicha se emplea el método tf.Session.run que recibe una lista con los tf.Operation o/y tf.Tensor que se pretenden ejecutar y que deben estar presentes en el grafo asociado a dicha sesión.

En la siguiente captura de pantalla se muestra la creación del grafo por defecto que contendrá la operación creada mediante tf.add que trabajará sobre los arrays de numpy “a” y “b” (cuyo valor se obtiene inmediatamente al no ser tensores de Tensorflow). A continuación, se genera mediante un bloque “with” la sesión “sess” y dentro de su ámbito se ejecuta empleando sess.run la operación de suma. Al finalizar el ámbito del bloque “with” se cerrará automáticamente la sesión.

Programando con la API de Bajo Nivel de Tensorflow

A continuación, se puede ver otra imagen en la que se ha creado el grafo “g1” al que se le ha añadido la operación creada mediante tf.multiply que trabajará sobre los arrays de numpy “d” y “e”. Una vez hecho eso, se crea la sesión “sess1” que operará sobre el contenido del grafo “g1” únicamente. Mediante sess1.run se ejecuta la multiplicación presente en “g1” y como la sesión no se ha creado mediante un bloque “with”, como buena práctica cuando ya no se va a emplear más dicha sesión, se cierra utilizando sess1.close.

Programando con la API de Bajo Nivel de Tensorflow

En estos ejemplos se han utilizado sesiones que trabajan sobre recursos presentes en la máquina local. La API de Bajo Nivel de Tensorflow permite que la sesión pueda acceder a dispositivos presentes en otras máquinas que trabajen conjuntamente formando un clúster permitiendo un cálculo distribuido. En DIA4RA emplearemos la abstracción de ejecución distribuida que ofrece la Estimator API para realizar entrenamientos en paralelo entre múltiples máquinas presentes en el Cloud.

Los clúster distribuidos de Tensorflow

Un clúster distribuido de Tensorflow estará formado por uno o más jobs, de forma que cada job puede contener una o más tasks. Las tasks de un job colaboran en una ejecución distribuida de un grafo. Normalmente cada task se ejecuta en una máquina diferente pero también es posible ejecutar varias tasks en la misma máquina, por ejemplo, empleando un dispositivo diferente presente en dicha máquina (si dispone de varias GPUs). Cada tarea estará asociada a un tf.train.Server que estará formado por un master para crear sesiones y por un worker para ejecutar operaciones del grafo.

Una técnica muy utilizada cuando se realiza un entrenamiento distribuido consiste en emplear procesos que actuarán como Parameter Servers. Las variables serán repartidas entre los parameter servers disponibles en función de su tamaño para balancear la carga.  Cuando un proceso worker necesite un variable almacenada en un parameter server, hará referencia directamente a ella. Cuando un worker calcule un gradiente, será enviado al parameter server que almacene esa variable concreta.

Para crear un clúster será necesario por un lado crear un objeto de la clase tf.train.ClusterSpec y uno o varios tf.train.Server.

La clase tf.train.ClusterSpec permite indicar todas las tasks del clúster. Su constructor recibirá un diccionario mapeando cada nombre de job a una lista de direcciones de red de las tasks de ese job o a otro diccionario en el que cada clave será un índice de task y su correspondiente valor será la dirección de red de dicha task.

El siguiente fragmento de código crea la configuración de un clúster formado 2 workers y 1 parameter server.

cluster = tf.train.ClusterSpec({“worker”: [“192.168.1.120:3333”, “192.168.1.121:3335”],
                                            “ps”: [“192.168.1.122:3335”]
                                            })

A continuación, lo que habrá que hacer es instanciar  los servers correspondientes a los 2 workers y al parameter server.

server0 = tf.train.Server(cluster, job_name=“worker”, task_index=0)
server1 = tf.train.Server(cluster, job_name=“worker”, task_index=1)
serverPs = tf.train.Server(cluster, job_name=“ps”, task_index=0)

El siguiente paso será emplear la función tf.device para especificar en qué proceso se colocará cada operación:

with tf.device(“/job:ps/task:0”):
    var0 = tf.Variable( … )
    var1 = tf.Variable( … )
    var2 = tf.Variable( … )
with tf.device(“/job:worker/task:0”):
    res0 = tf.matmul(var0, var1)  
with tf.device(“/job:worker/task:0”):
    res1 = tf.matmul(var1, var2)

En este punto, se crearán las sesiones necesarias y cada una de ellas se asociará con un server (2 workers y 1 parameter server).

sessPs = tf.Session(target=serverPs.target)
sess0 = tf.Session(target=server0.target)
sess1 = tf.Session(target=server1.target)

Dichas sesiones se emplearán para ejecutar las operaciones asociadas a esos servers (tasks). En un futuro artículo se presentará de forma práctica un entrenamiento distribuido empleando la API de Bajo Nivel de Tensorflow. Pero antes, vamos a continuar con el recorrido por sus componentes básicos.

Asignación de dispositivos mediante tf.device()

En Tensorflow los dispositivos disponibles para ejecutar operaciones son CPUs y GPUs. La notación que se emplea para referenciarlos es la siguiente:

La secuencia seguiría aumentándose el índice de la GPU si existiesen más de estos dispositivos. Por defecto, si una operación está implementada para poder ejecutarse tanto en CPU como en GPU, los dispositivos GPU tendrán prioridad a la hora de recibir esa operación.

En primer lugar, para visualizar los dispositivos disponibles en la máquina se podrá ejecutar el siguiente código:

from tensorflow.python.client import device_lib
device_lib.list_local_devices()

Programando con la API de Bajo Nivel de Tensorflow

Si se desea colocar una o varias operaciones en un dispositivo en concreto la forma de hacerlo será empleando un bloque “with” con la función tf.device() que recibirá el nombre de dicho dispositivo.

with tf.device(“/gpu:0”):
    a = tf.constant([2, 7, 3])

Constantes

Se trata de un tensor que tiene un valor constante que se crea mediante la función tf.constant() y dispone de los siguientes argumentos:

Programando con la API de Bajo Nivel de Tensorflow

Variables

Una variable de Tensorflow permite almacenar un tensor cuyo valor puede ser cambiado ejecutando una serie de operaciones sobre ella. Esas modificaciones son visibles desde múltiples objetos tf.Session lo que permite que diferentes workers puedan acceder al valor de una misma variable.

A bajo nivel la clase que se encarga de su implementación se trata de tf.Variable. En cuanto a la creación de variables la forma recomendada es mediante la función tf.get_variable, que recibe el nombre de dicha variable y su shape entre otros argumentos opcionales como su valor inicial.

var1 = tf.get_variable(“test”, [2, 1, 4], dtype=tf.int64)

Ese comando creará una variable llamada “test” de 3 dimensiones y shape [2, 1, 4], cuyos valores serán de tipo tf.int64 (en caso de no indicarse el parámetro dtype, el tipo por defecto será tf.float32) y su valor inicial se establece por defecto a partir a partir de la distribución aleatoria determinada por tf.glorot_uniform_initializer.

Esta función (también llamada inicialización Xavier) generará muestras aleatorias entre [-a, a], donde:

Si se desea indicar un initializer en concreto se puede hacer de la siguiente forma:

var2 = tf.get_variable(“test2”, [5, 2, 4, 1], dtype=tf.int32, initializer=tf.zeros_initializer)

En caso de que el initializer sea un tf.Tensor entonces no habrá que indicar el shape en el constructor de tf.get_variable ya que lo inferirá a partir del shape de ese initializer ([2, 3]):

var4 = tf.get_variable(“test4”, initializer=tf.constant([2,3]))

Las “collections” de Tensorflow son listas con nombre de tensores u otros objetos como variables. Cuando se crea una variable se añadirá por defecto en las colecciones tf.GraphKeys.TRAINABLE_VARIABLES (son las variables para las que Tensorflow calculará sus gradientes) y tf.GraphKeys.GLOBAL_VARIABLES (variables que pueden ser compartidas entre múltiples dispositivos).

Para hacer que una variable no sea tenida en cuenta a la hora de calcular los gradientes habría que pasar el parámetro “trainable=False” a la hora de su creación.

var5 = tf.get_variable(“test5”, [4, 2], trainable=False)

Se pueden crear collections personalizadas utilizando cualquier cadena como nombre. Para añadir un objeto ya creado a una colección se empleará el método tf.add_to_collection.

tf.add_to_collection(“col1”, var4)

La forma de conocer todos los objetos de una collection es mediante la siguiente función:

tf.get_collection(“col1”)

Hasta este punto hemos visto cómo crear variables y cómo unirlas a collections. Pero antes de poder utilizar una variable hay que añadir una operación al grafo para que la inicialice explícitamente, lo que permite evitar que se vuelvan a ejecutar initializers que pueden consumir un tiempo importante, por ejemplo, al volver a cargar un modelo desde un “checkpoint”.

La función que emplearemos para inicializar una única variable será:

sess = tf.Session()
sess.run(var1.initializer)

Pero como ir inicializando variable por variable puede ser muy tedioso, hay una función que viene a nuestro rescate, tf.global_variables_initializer(). Se encarga de añadir una única operación al grafo que, cuando sea ejecutada, inicializará todas las variables presentes en la collection  tf.GraphKeys.GLOBAL_VARIABLES.

init = tf.global_variables_initializer()
sess1 = tf.Session()
sess1.run(init)

Esta función no asegura el orden en que serán inicializadas las variables. De forma que si hay variables que dependen de otras y no estamos seguros de si ya han sido inicializadas, una forma de programar de forma segura es empleando en la variable dependiente la función var_de_la_que_se_depende.initialized_value().

a = tf.get_variable(“a”, [1,2], initializer=tf.zeros_initializer())
b = tf.get_varible(“b”, initializer=a.initialized_value() * 2)

Si se quiere asignar un nuevo valor a una variable se podrán emplear la familia de funciones assign, assign_add.

sum = a.assign(a + 7.0)
sum2 = a.assign_add(8.0)

La instrucción tf.get_variable puede encontrarse en un bloque de código (una función) que puede ser ejecutado repetidas veces. No quedaría claro si lo que se pretende es volver a crear la misma variable o reutilizarla. Una forma de solucionar esto es creando una variable dentro de un bloque “with” con tf.variable_scope (eso añadirá el nombre del variable_scope al principio del nombre de la variable) y cuando se quiera reutilizar dicha variable, la instrucción tf.get_variable se incluirá en el interior de  un tf.variable_scope con el mismo nombre que cuando se creó pero que además recibirá el parámetro "reuse=True".

En caso de no utilizar el flag "reuse=True", si la variable ya había sido previamente creada mediante una llamada a get_variable, al volver a intentar crearla se obtendrá una excepción o si no se creó mediante una llamada a get_variable. Esto permite evitar reutilizar variables por error. Una vez establecido reuse a True ya no se puede poner a False dentro del bloque. También se puede fijar el flag reuse a True dentro del bloque llamando a scope.reuse_variables().

A continuación, vamos a ver un ejemplo de utilización de la función get_variable para crear una variable compartida si no existe o reutilizarla en caso de que exista. Esto se controla dentro del scope "relu". Si se definen otros variable scopes dentro del actual, heredarán el flag "reuse=True".

Las variables creadas usando get_variable siempre se nombran utilizando el nombre de su variable scope como prefijo. Por ejemplo, relu/threshold. Si se crea un scope con un nombre que ya había sido utilizado por otro scope, se añadirá un sufijo "índice" para que el nombre sea único.

Se definirá una función "relu()" que reutilizará una variable relu/threashold. Dicha variable será creada fuera de la función inicializándola a 0.0. A continuación se construirán 5 relus llamando 5 veces a la función "relu()".

tf.reset_default_graph()

def relu(X):
    with tf.variable_scope("relu", reuse=True): # Reutilización de la variable threshold
        threshold = tf.get_variable("threshold", shape=(), initializer=tf.constant_initializer(0.0))
        w_shape = int(X.get_shape()[1]), 1
        w = tf.Variable(tf.random_normal(w_shape), name="weights")
        b = tf.Variable(0.0, name="bias")
        linear = tf.add(tf.matmul(X, w), b, name="linear")
        return tf.maximum(linear, threshold, name="max")

X = tf.placeholder(tf.float32, shape=(None, n_features), name="X")
with tf.variable_scope("relu"): # Creación de la variable threshold
    threshold = tf.get_variable("threshold", shape=(), initializer=tf.constant_initializer(0.0))
relus = [relu(X) for i in range(5)]
output = tf.add_n(relus, name="output")

Placeholders

Un tf.placeholder es una estructura que almacenará datos pero dichos datos serán cargados en tiempo de ejecución. Por tanto, nos permitirá definir un almacén de información que podrá ser añadido al grafo sin tener que alimentarlo hasta que se cree una sesión y se desee ejecutar operaciones que dependan de este placeholder.

Para ello, el método sess.run deberá recibir como parámetro además de las operaciones a ejecutar, un argumento llamado feed_dict que será un diccionario donde cada clave será el nombre de un placeholder y su correspondiente valor será justamente el valor que queramos que reciba esa estructura.

import tensorflow as tf

a = tf.placeholder(“float”, None)
b = a + 7

with tf.Session() as sess:
    r = sess.run(b, feed_dict={a:[6,3]})

Como se ha podido apreciar, no es necesario definir estáticamente un tamaño para los datos que albergará un tf.placeholder. También puede tener cualquier número de dimensiones y cuando alguna de sus dimensiones sea “None”, significa que puede tener cualquier número de elementos en ella.

import tensorflow as tf

a = tf.placeholder(“float”, [None, 2])
b = a + 7

with tf.Session() as sess:
    r = sess.run(b, feed_dict={a:[[1, 4], [3, 5], [7, 9]]})

---

Hasta aquí este breve repaso a los componentes básicos del Core de Tensorflow. En próximos artículos continuaremos viendo APIs de más alto nivel de este potente framework de Google.

 

dia4ra cdtiEl proyecto empresarial de DATAHACK CONSULTING SL., denominado “DESARROLLO DE INTELIGENCIA ARTIFICIAL EN ROBOTS APLICADOS AL TRATAMIENTO DEL ALZHEIMER Y LA DEMENCIA” y número de expediente 00104725 / SNEO-20171211 ha sido subvencionado por el CENTRO PARA EL DESARROLLO TECNOLÓGICO INDUSTRIAL (CDTI)

MÁSTER EXPERTO EN BIG DATA & ANALYTICS

Gracias al Master en Big Data Analytics 100% Online tendrás amplios conocimientos sobre las herramientas y técnicas analíticas necesarias para la modelización de los principales retos de negocio, con el fin de mejorar la toma de decisiones a través de los datos y el conocimiento.

R es un entorno y lenguaje de programación, distribuido bajo la licencia GNU GPL, que se creó como un dialecto libre del lenguaje S

Algunas de las características de R:

Extensible:

Los usuarios lo pueden extender definiendo sus propias funciones, aparte de las de las numerosas bibliotecas preconstruidas que tiene. La mayor parte de ellas están escritas en R, aunque para algoritmos computacionalmente exigentes es posible desarrollarlas en C, C++ o Fortran. Como es un proyecto colaborativo y abierto, los propios usuarios pueden publicar paquetes que extienden su configuración básica.

Funcional

Las funciones en R se pueden manipular igual que los vectores. Además puedes asignar las funciones a variables, almacenarlas en listas, devolverlas como resultados de otras funciones o incluso pasarlas como argumentos de otras funciones

Orientado a Objetos:

¡Sí! Además de ser funcional, es orientado a objetos, en realidad es una mezcla de ambos paradigmas. En el caso de del segundo de ellos, R nos permite modelar conceptos del mundo real relevantes a nuestro problema, representándolos como clases y objetos que podemos hacer que interactúen entre sí.

Integrable:

Ofrece múltiples posibilidades para atacar a datos almacenados en distintos tipos de bases de datos. También presenta múltiples bindings y paquetes que permiten a R interactuar con otros lenguajes (como Perl, Ruby o Python) e intercambiar objetos con ellos.

Gráficos avanzados:

Existen librerías para R que permiten generar una extensa variedad de gráficos, desde la completísima ggplot2hasta otras más simples pero también potentes como corrplot

Diferentes Interfaces gráficos:

Si bien R se puede utilizar a través de línea de comandos, existen varios editores gráficos muy interesantes capaces de correr en Windows, Linux y MacOS. Desctacamos especialmente R Studio y R Commander.

Interpretado y no compilado:

A diferencia de C, C++ ó Java, no tenemos que compilar nuestro código, sino que el intérprete de R lo ejecuta directamente. Lo curioso de esto es que, puesto que muchas de sus rutinas computacionalmente más exigentes están escritas en C ó C++, muchas veces, sin que nos demos cuenta, se estará ejecutando, entre bambalinas, código compilado en esos lenguajes.

Basado en memoria:

R mantiene todos los objetos que definimos en nuestro programa en la memoria de nuestra máquina. Por ello, es importante entender cómo gestiona la memoria, para poder optimizar nuestro código. Así evitamos, por ejemplo, copias innecesarias de objetos que pueden ralentizarlo y hacer llegar a un límite nuestra máquina.

Qué podemos hacer con R:

Este lenguaje de programación fue concebido para el análisis estadístico, aunque también se utiliza en la minería y análisis de datos, investigación biomédica, bioinformática, machine learning… Esto es porque proporciona un amplio abanico de herramientas estadísticas y gráficas, además de tener una gran potencia como herramienta de cálculo.

MÁSTER EXPERTO EN BIG DATA & ANALYTICS

Gracias al Master en Big Data Analytics 100% Online tendrás amplios conocimientos sobre las herramientas y técnicas analíticas necesarias para la modelización de los principales retos de negocio, con el fin de mejorar la toma de decisiones a través de los datos y el conocimiento.

chevron-down