{"id":794,"date":"2009-05-03T18:12:03","date_gmt":"2009-05-03T16:12:03","guid":{"rendered":"http:\/\/host.marblestation.com\/?p=794"},"modified":"2012-04-26T16:18:56","modified_gmt":"2012-04-26T14:18:56","slug":"r-estadistica-y-tratamiento-masivo-de-datos-alternativa-a-sas-acl-e-idea","status":"publish","type":"post","link":"https:\/\/www.marblestation.com\/?p=794","title":{"rendered":"R, estad\u00edstica y tratamiento masivo de datos (alternativa a SAS, ACL e IDEA)"},"content":{"rendered":"<p><img decoding=\"async\" src=\"http:\/\/www.r-project.org\/Rlogo.jpg\" align=\"right\"\/>En el \u00faltimo art\u00edculo hemos visto <a href=\"http:\/\/www.marblestation.com\/?p=761\">AWK como herramienta para el tratamiento masivo de datos<\/a>, donde hemos demostrado que pod\u00eda ser una alternativa parcial a otras herramientas comerciales como <a href=\"http:\/\/www.sas.com\/\">SAS<\/a>, <a href=\"http:\/\/www.acl.com\/\">ACL<\/a> o <a href=\"http:\/\/www.audimation.com\/\">IDEA<\/a> (muy utilizadas en el mundo de la Auditor\u00eda). AWK es una soluci\u00f3n parcial dado que \u00fanicamente nos proporciona funcionalidades para hacer un tratamiento b\u00e1sico sobre los ficheros (p.ej. sumarizaciones, cruces de datos, operaciones matem\u00e1ticas simples, etc), sin embargo no tenemos las caracter\u00edsticas estad\u00edsticas que si podemos encontrar en las herramientas comerciales.<\/p>\n<p>Afortunadamente para todas esas funcionalidades podemos apoyarnos en R: <a href=\"http:\/\/www.r-project.org\/\">R<\/a> es un lenguaje de programaci&oacute;n que permite llevar a cabo an&aacute;lisis estad&iacute;sticos avanzados, entendiendo por por estad&iacute;stica como la ciencia de recoger y analizar datos con el prop&oacute;sito de sacar conclusiones y tomar decisiones.<\/p>\n<p>Con R tambi\u00e9n podemos realizar c&aacute;lculos num&eacute;ricos, aunque para esas tareas tambi\u00e9n vale la pena echar un vistazo a <a href=\"http:\/\/www.gnu.org\/software\/octave\/\">Octave<\/a>.<\/p>\n<p>Aparte de las potentes caracter&iacute;sticas de R, existen multitud de <a href=\"http:\/\/cran.r-project.org\/web\/views\/index.html\">paquetes<\/a> que ampl&iacute;an las funcionalidades: desde dedicados al an&aacute;lisis de datos psicol&oacute;gicos hasta financieros.<\/p>\n<p>Al igual que AWK, R no ofrece una interfaz gr\u00e1fica tan potente como las herramientas comerciales que comentavamos, aunque podemos apoyarnos en determinados mecanismos que nos har\u00e1n la vida m\u00e1s f\u00e1cil a la hora de tratar la informaci\u00f3n (p.ej. utilizando MySQL Query Browser) como veremos en las correspondientes secciones del art\u00edculo.<\/p>\n<p>Para aprender a utilizar R mediante esta gu\u00eda es muy recomendable replicar todos los ejemplos y visualizar los resultados directamente. \u00danicamente leyendo el art\u00edculo es m\u00e1s dif\u00edcil entender el funcionamiento completo de la herramienta.<\/p>\n<p>De antemano pido disculpas si soy inexacto o cometo alg\u00fan tipo de error en las explicaciones estad\u00edsticas, no soy un experto en esa materia y estar\u00e9 muy agradecido si detect\u00e1is incorrecciones y las hac\u00e9is llegar v\u00eda comentario o correo. <\/p>\n<p>Finalmente, destacar que para la elaboraci\u00f3n del art\u00edculo me he basado en diversos tutoriales que he encontrado por Internet, especialmente <a href=\"http:\/\/cran.r-project.org\/doc\/contrib\/Verzani-SimpleR.pdf\">simpleR<\/a>, con los cuales he ido aprendido a utilizar R de forma paralela a la redacci\u00f3n de esta gu\u00eda.<br \/>\n<!--more--><\/p>\n<h3>\u00cdndice de contenidos<\/h3>\n<p STYLE=\"margin-bottom: 0cm\"><a href=\"#0011\">Instalaci&oacute;n<\/a><\/p>\n<p STYLE=\"margin-bottom: 0cm\"><a href=\"#0012\">Introducci&oacute;n<\/a><\/p>\n<p STYLE=\"margin-bottom: 0cm\"><a href=\"#0013\">Estructuras simples de datos<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#0021\">N&uacute;meros<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#0022\">Booleanos<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#0023\">Cadenas<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#0024\">Fechas<\/a><\/p>\n<p STYLE=\"margin-bottom: 0cm\"><a href=\"#0014\">Estructuras complejas de datos<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#0025\">Vectores<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#0026\">Matrices<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#0027\">Data Frames<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#0028\">Listas<\/a><\/p>\n<p STYLE=\"margin-bottom: 0cm\"><a href=\"#0015\">Introducci&oacute;n manual de datos<\/a><\/p>\n<p STYLE=\"margin-bottom: 0cm\"><a href=\"#0016\">Librer&iacute;as y datos de ejemplo<\/a><\/p>\n<p STYLE=\"margin-bottom: 0cm\"><a href=\"#0017\">Importar\/exportar datos<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#0029\">Ficheros<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#00210\">Bases de Datos: MySQL<\/a><\/p>\n<p STYLE=\"margin-bottom: 0cm\"><a href=\"#0018\">Distribuciones de probabilidad<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#00211\">Generaci&oacute;n de n&uacute;meros aleatorios<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#00212\">Muestreo aleatorio<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#00213\">Generaci&oacute;n de n&uacute;meros secuenciales<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#00214\">Probabilidades<\/a><\/p>\n<p STYLE=\"margin-bottom: 0cm\"><a href=\"#0019\">Visualizaci&oacute;n de datos de una variable<\/a><\/p>\n<p STYLE=\"margin-bottom: 0cm\"><a href=\"#00110\">Visualizaci&oacute;n de datos de dos variables<\/a><\/p>\n<p STYLE=\"margin-bottom: 0cm\"><a href=\"#00111\">Identificar puntos en un gr&aacute;fico<\/a><\/p>\n<p STYLE=\"margin-bottom: 0cm\"><a href=\"#00112\">Identificar la distribuci&oacute;n de los datos<\/a><\/p>\n<p STYLE=\"margin-bottom: 0cm\"><a href=\"#00113\">Diferentes formas de entender la probabilidad<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#00215\">Probabilidades frecuentista<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#00216\">Probabilidades bayesienas o basadas en evidencias<\/a><\/p>\n<p STYLE=\"margin-bottom: 0cm\"><a href=\"#00114\">Pruebas estad&iacute;sticas<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#00217\">Prueba de distribuci&oacute;n normal<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#00218\">Prueba de proporci&oacute;n<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#00219\">Pruebas sobre la media<\/a><\/p>\n<p STYLE=\"margin-left: 1cm; margin-bottom: 0cm\">T-Test: Datos con distribuci&oacute;n normal<\/p>\n<p STYLE=\"margin-left: 1.5cm; margin-bottom: 0cm\">Una variable<\/p>\n<p STYLE=\"margin-left: 1.5cm; margin-bottom: 0cm\">Dos variables\t26<\/p>\n<p STYLE=\"margin-left: 1cm; margin-bottom: 0cm\">Simulaciones sobre el T-Test<\/p>\n<p STYLE=\"margin-left: 1cm; margin-bottom: 0cm\">Wilcoxon Test: Datos con distribuci&oacute;n diferente a la normal<\/p>\n<p STYLE=\"margin-left: 1cm; margin-bottom: 0cm\">ANOVA \/ Kruskal<\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#00220\">Prueba sobre la varianza<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#00221\">Prueba de independencia<\/a><\/p>\n<p STYLE=\"margin-left: 1cm; margin-bottom: 0cm\">Coeficiente de Pearson: Datos con distribuci&oacute;n normal<\/p>\n<p STYLE=\"margin-left: 1cm; margin-bottom: 0cm\">M&eacute;todos no param&eacute;tricos: Datos con distribuci&oacute;n diferente a la normal<\/p>\n<p STYLE=\"margin-bottom: 0cm\"><a href=\"#00115\">An&aacute;lisis de regresiones<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#00222\">Regresiones lineales simples<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#00223\">Regresiones lineales m&uacute;ltiples<\/a><\/p>\n<p STYLE=\"margin-bottom: 0cm\"><a href=\"#00116\">Estandarizar y escalar<\/a><\/p>\n<p STYLE=\"margin-bottom: 0cm\"><a href=\"#00117\">T&eacute;cnicas para identificar fraude<\/a><\/p>\n<p STYLE=\"margin-bottom: 0cm\"><a href=\"#00118\">Programaci&oacute;n<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#00224\">Estructuras de control<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#00225\">Definici&oacute;n de funciones<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#00226\">Depurar \/ Debug<\/a><\/p>\n<p STYLE=\"margin-left: 0.5cm; margin-bottom: 0cm\"><a href=\"#00227\">Optimizaci&oacute;n \/ Profiling<\/a><\/p>\n<h3><a name=\"0011\">Instalaci&oacute;n<\/a><\/h3>\n<p>La instalaci&oacute;n de R en Ubuntu GNU\/Linux no puede ser m&aacute;s sencilla:<\/p>\n<pre>\r\nsudo apt-get install r-base-core\r\n<\/pre>\n<p>Para plataformas Windows, debemos descargar el instalador de la p&aacute;gina del projecto R: <a HREF=\"http:\/\/www.r-project.org\/\">http:\/\/www.r-project.org\/<\/a><\/p>\n<h3><a name=\"0012\">Introducci&oacute;n<\/a><\/h3>\n<p>Para interactuar con R se dispone de una potente linea de comandos: <\/p>\n<pre>\r\n$ R \r\n\r\nR version 2.6.2 (2008-02-08) \r\nCopyright (C) 2008 The R Foundation for Statistical Computing \r\nISBN 3-900051-07-0 \r\n\r\nR es un software libre y viene sin GARANTIA ALGUNA. \r\nUsted puede redistribuirlo bajo ciertas circunstancias. \r\nEscriba 'license()' o 'licence()' para detalles de distribucion. \r\n\r\nR es un proyecto colaborativo con muchos contribuyentes. \r\nEscriba 'contributors()' para obtener m\u00e1s informaci\u00f3n y \r\n'citation()' para saber c\u00f3mo citar R o paquetes de R en publicaciones. \r\n\r\nEscriba 'demo()' para demostraciones, 'help()' para el sistema on-line de ayuda, \r\no 'help.start()' para abrir el sistema de ayuda HTML con su navegador. \r\nEscriba 'q()' para salir de R. \r\n\r\n> \r\n<\/pre>\n<p>Para salir de la consola basta con ejecutar &quot;q()&quot;, entonces R nos permite grabar la sesi&oacute;n actual (historial de comandos y datos cargados). <\/p>\n<p>Con todos los comandos que veremos podemos utilizar la funci&oacute;n &#8216;help&#8217; para obtener los detalles de su funcionamiento, por ejemplo: help(read.csv) o ?help<\/p>\n<p>En caso de que no recordemos un comando exacto podemos utilizar &quot;apropos(parte_del_comando)&quot; para que el sistema liste posibles candidatos: <\/p>\n<pre>\r\n> apropos(\"rank\") \r\n[1] \"dsignrank\" \"psignrank\" \"qsignrank\" \"rank\"      \"rsignrank\" \r\n<\/pre>\n<h3><a name=\"0013\">Estructuras simples de datos<\/a><\/h3>\n<p>R permite utilizar variables con tipado din&aacute;mico, es decir, no tenemos que declarar las variables y explicitar que tipo de valores van a contener. Los nombres de las variables puede ser cualquier cadena que empiece por un car&aacute;cter. Veremos habitualmente el uso de puntos en lugar de subrayado\/underscore para separar palabras y que las variables sean m&aacute;s autoexplicativas, por ejemplo transferencias.nacionales. Por tanto, si vemos esa nomenclatura no tiene porque tratarse de un m&eacute;todo\/atributo de un objeto (como pasa en otros lenguajes), sino que puede ser perfectamente una simple variable. Para declarar y asignar un valor a una variable se puede utilizar tanto &#8216;=&#8217; como &#8216;&lt;-&#8216;:<\/p>\n<pre>\r\ncontador = 0\r\ncontador < - 1\r\n<\/pre>\n<p>Una variable puede contener una estructura de datos simple o compleja.<\/p>\n<h4><a name=\"0021\">N&uacute;meros<\/a><\/h4>\n<p>R permite el uso de num&eacute;ricos enteros o decimales, estos &uacute;ltimos separados por puntos:<\/p>\n<pre>\r\nx = 1\r\ny = 2.5\r\n<\/pre>\n<p>Sobre los valores num&eacute;ricos se pueden realizar las habituales operaciones aritm&eacute;ticas, entre las que se encuentran: + * \/ &#8211; ^<\/p>\n<pre>\r\nz = (x + y ^ 2) - .5\r\n<\/pre>\n<p>Los n&uacute;meros decimales entre 0 y 1 podemos especificarlos sin indicar el 0 (p.ej. 0.5 =&gt; .5).<\/p>\n<h4><a name=\"0022\">Booleanos<\/a><\/h4>\n<p>Una variable booleana &uacute;nicamente puede contener 2 valores: TRUE o FALSE (abreviadas tambi&eacute;n como T o F)<\/p>\n<pre>\r\nx = TRUE\r\ny = FALSE\r\n<\/pre>\n<p>Si utilizamos expresiones condicionales, su resultado ser&aacute; un valor booleano (p.ej. 17 %in% 1:100). Los operadores disponibles son los siguientes: &lt; &lt;= &gt; &gt;= == != <\/p>\n<p>Por otra parte, podemos combinar varios valores booleanos o expresiones condicionales mediante el uso de negaciones, &ldquo;ands&rdquo; y &ldquo;or&rdquo;:  ! &amp; | <\/p>\n<h4><a name=\"0023\">Cadenas<\/a><\/h4>\n<p>Para el tratamiento de variable que contienen cadenas o de las cadenas directamente nos pueden ser de utilidad las siguientes funciones:<\/p>\n<pre>\r\n# Impresi\u00f3n \r\ncat(\"Cadena!\\n\") \r\n\r\n# Concatenaci\u00f3n separada por nada \r\npaste(\"Cadena\", \"!\", sep=\"\") \r\n\r\n> s = c(\"Hello\", \" \", \"World\", \"!\") \r\n> paste(s, collapse=\"\") \r\n[1] \"Hello World!\" \r\n\r\n# Longitud de una cadena \r\n> nchar(\"Hello World!\") \r\n[1] 12 \r\n\r\n# Substring de la posici\u00f3n 4 a la 6 \r\n> s = \"Hello World\" \r\n> substring(s, 4, 6) \r\n[1] \"lo \" \r\n\r\n# Separa una cadena en campos, devuelve una lista \r\n> s = \"foo, bar, baz\" \r\n> x = strsplit(s, \", \") \r\n> x[[1]] # Vector \r\n[1] \"foo\" \"bar\" \"baz\" \r\n> x[[1]][1] # Elemento 1 \r\n[1] \"foo\" \r\n\r\n# Busca elementos que cumplan una expresi\u00f3n regular \r\n> s = c(\"hola\", \"adios\") \r\n> grep(\"^a\", s) \r\n[1] 2 \r\n> grep(\"^a\", s, value=T) \r\n[1] \"adios\" \r\n\r\n# O elementos que cumpla aproximadamente una expresi\u00f3n regular \r\n> agrep (\"abc\", c(\"abbc\", \"jdfja\", \"cba\")) \r\n[1] 1 \r\n\r\n# Buscamos una expresi\u00f3n regular en una cadena \r\n> x = regexpr(\"o\", \"Hello\") \r\n> x[1] # Posici\u00f3n donde empieza la cadena encontrada \r\n> attr(x, \"match.length\") # Longitud de la cadena encontrada \r\n\r\n# Reemplaza todos los ; por , \r\n> gsub(\";\", \",\", \"dato1;dato2;dato3\") \r\n[1] \"dato1,dato2,dato3\" \r\n\r\n# Reemplaza solo el primer ; por , \r\n> sub(\";\", \",\", \"dato1;dato2;dato3\") \r\n[1] \"dato1,dato2;dato3\" \r\n<\/pre>\n<h4><a name=\"0024\">Fechas<\/a><\/h4>\n<p>R proporciona un tipo de variable especial para las fechas, para las cuales nos puede resultar de utilidad las siguientes funciones:<\/p>\n<pre>\r\n# Convertir cadena a fecha \r\n> a = as.Date(\"01\/02\/03\", format=\"%y\/%m\/%d\") \r\n\r\n# Diferencia de fechas en dias \r\n> b = as.Date(\"01\/02\/03\", format=\"%y\/%d\/%m\") \r\n> a - b \r\nTime difference of -27 days \r\n\r\n# Fecha actual + 15 dias \r\n> Sys.Date() + 15 \r\n[1] \"2009-03-08\" \r\n\r\n# Convertir fecha a cadena con un formato determinado \r\n> format(Sys.Date(), format=\"%A, %d %B %Y\") \r\n[1] \"s\u00e1bado, 21 febrero 2009\" \r\n\r\n# Extraer el mes \r\n> format( Sys.Date(), format=\"%m\" ) \r\n[1] \"02\" \r\n\r\n# Secuencia de fechas desde Enero 2005 a Julio 2005 mes a mes \r\n> seq(as.Date(\"2005-01-01\"), as.Date(\"2005-07-01\"), by=\"month\") \r\n[1] \"2005-01-01\" \"2005-02-01\" \"2005-03-01\" \"2005-04-01\" \"2005-05-01\" \r\n[6] \"2005-06-01\" \"2005-07-01\" \r\n\r\n# Recorrer la secuencia \r\n> dates = seq(as.Date(\"2005-01-01\"), as.Date(\"2005-07-01\"), by=\"month\") \r\n> for (i in 1:length(dates)) { \r\n  d = as.Date(as.character(dates[i])) # Hay que convertir o solo visualizaremos un numero \r\n  cat(paste(d, \"\\n\", sep=\"\")) \r\n} \r\n<\/pre>\n<h3><a name=\"0014\">Estructuras complejas de datos<\/a><\/h3>\n<p>En R disponemos de las siguientes estructuras complejas de datos fundamentales:<\/p>\n<ul>\n<li>Vectores: 1<br \/>\n\tdimensi&oacute;n <\/p>\n<\/li>\n<li>Matrices\/Arrays: 2<br \/>\n\to m&aacute;s dimensiones <\/p>\n<\/li>\n<li>Data Frames: 2<br \/>\n\tdimensiones donde cada columna puede ser de un tipo diferente<br \/>\n\t(cadenas, n&uacute;meros, fechas y booleanos) <\/p>\n<\/li>\n<li>Listas: pueden<br \/>\n\tcontener cualquiera de las estructuras anteriores .\n<\/li>\n<\/ul>\n<p>Para que R pueda trabajar con los datos, estos deben ser cargados en memoria. Para listar lo que actualmente existe en memoria utilizamos &quot;ls()&quot;:<\/p>\n<pre>\r\n> datos = \"test\"\r\n> ls() \r\n[1] \"datos\" \r\n<\/pre>\n<p>Cuando queramos dejar de trabajar con un conjunto de datos y no los necesitemos en memoria, podemos eliminarlos mediante &quot;rm(datos)&quot;. <\/p>\n<p>Por otra parte, en todas las estructuras podemos utilizar las funciones: <\/p>\n<pre>\r\n> x = 5\r\n> str(x) # Explica la estructura de x \r\n> summary(x) # Sumariza la informaci\u00f3n contenida en x \r\n<\/pre>\n<h4><a name=\"0025\">Vectores<\/a><\/h4>\n<p>Veamos las funciones relacionadas con los vectores:<\/p>\n<ul>\n<li>Creaci&oacute;n<\/li>\n<\/ul>\n<pre>\r\nx = seq(-1, 1, by=.1)\t# Creamos un vector con n\u00fameros desde -1 al 1 sumando 0.1 \r\nnames(x) = letters[1:length(x)] # Ponemos nombre a las coordenadas x[\"a\"], x[1] \r\n\r\nx = c(1, 2, 3) # Creamos un vector con los datos indicados\r\nx = c(a=1, b=2, c=3) # Datos y nombres simult\u00e1neamente \r\n\r\n&gt; rep(1,10) \r\n [1] 1 1 1 1 1 1 1 1 1 1 \r\n&gt; rep(1:5,3) \r\n [1] 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 \r\n&gt; rep(1:5,each=3) # Repite del 1 al 5 cada elemento 3 veces \r\n [1] 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 \r\n<\/pre>\n<ul>\n<li VALUE=1>Filtros<\/li>\n<\/ul>\n<pre>\r\n&gt; x[\"a\"] # Elemento \"a\" \r\n\r\n&gt; x[1]\t# Elemento 1 \r\n\r\n&gt; x[5:10] # Elementos 5 al 10 \r\n[1] -0.6 -0.5 -0.4 -0.3 -0.2 -0.1 \r\n\r\n&gt; x[c(5,7:10)] # Elemento 5 y del 7 al 10 \r\n[1] -0.6 -0.4 -0.3 -0.2 -0.1 \r\n\r\n&gt; x[-(5:10)]   # Todos menos los elementos del 5 al 10 \r\n [1] -1.0 -0.9 -0.8 -0.7  0.0  0.1  0.2  0.3  0.4  0.5  0.6  0.7  0.8  0.9  1.0 \r\n\r\n&gt; x[ x&gt;0 ]  # Los valores superiores a 0 \r\n [1] 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 \r\n<\/pre>\n<ul>\n<li VALUE=1>Operaciones<\/li>\n<\/ul>\n<pre>\r\n&gt; x&gt;0 # Devuelve vector con el resultado de aplicar la condici\u00f3n \r\n [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE \r\n[13]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE \r\n\r\n&gt; x = rnorm(10) \r\n&gt; sort(x) # Orden de menor a mayor \r\n [1] -1.4159893 -1.1159279 -1.0598020 -0.2314716  0.3117607  0.5376470 \r\n [7]  0.6922798  0.9316789  0.9761509  1.1022298 \r\n&gt; rev(sort(x)) # Orden inverso \r\n [1]  1.1022298  0.9761509  0.9316789  0.6922798  0.5376470  0.3117607 \r\n [7] -0.2314716 -1.0598020 -1.1159279 -1.4159893 \r\n&gt; o = order(x) # Orden de menor a mayor, pero devuelve el indice de los elementos \r\n&gt; o \r\n [1]  3  1  9  6  4  7  8 10  2  5 \r\n&gt; x[ o[1:3] ] # Asi podemos acceder a los valores \r\n[1] -1.415989 -1.115928 -1.059802 \r\n\r\n&gt; x = sample(1:5, 10, replace=T) \r\n&gt; unique(x) # Elimina duplicados (no necesita que el vector sea ordenado previamente) \r\n[1] 1 4 5 3 \r\n\r\n# Busquemos que elementos son igual a 0 y en que posici\u00f3n se encuentran: \r\n&gt; x.test = c(1, 2, 0, 3, 2, 0, 0, 1)\r\n&gt; x.test == 0 \r\n[1] FALSE FALSE  TRUE FALSE FALSE  TRUE  TRUE FALSE \r\n&gt; which(x.test == 0) \r\n[1] 3 6 7 \r\n\r\n# Para concatenar dos vectores: \r\n&gt; c(c(1,2,3), c(4,5,6)) \r\n[1] 1 2 3 4 5 6 \r\n\r\n# O sumar sus elementos: \r\n&gt; c(c(1,2,3) + c(4,5,6)) \r\n[1] 5 7 9 \r\n<\/pre>\n<ul>\n<li>C&aacute;lculos <\/li>\n<\/ul>\n<pre>\r\n&gt; min(x)\t# M\u00ednimo \r\n&gt; max(x)\t# M\u00e1ximo \r\n&gt; cummax(c(5,5,4,7,7,3))\t# M\u00e1ximo visto al llegar a cada elemento \r\n[1] 5 5 5 7 7 7 \r\n&gt; cummin(c(5,5,4,7,7,3))\t# M\u00ednimo visto al llegar a cada elemento \r\n[1] 5 5 4 4 4 3 \r\n&gt; sum(x)\t# Suma \r\n&gt; length(x)\t# Longitud \r\n&gt; round(x)\t# Redondeo de cada elemento \r\n&gt; round(x, digits=2)\t# Redondeo de cada elemento a 2 decimales \r\n&gt; rank(x)\t# Devuelve la posici\u00f3n de cada elemento si estuviese ordenado el vector de menor a mayor (p.ej. 9 15 7 =&gt; segundo tercero primero =&gt; 2 3 1)Rango \r\n&gt; median(x)\t# Mediana: valor de la variable que deja el mismo n\u00famero de datos antes y despu\u00e9s que \u00e9l, una vez ordenados estos \r\n&gt; mean(x)\t# Media aritmetica: suma de todos dividida entre el n\u00famero de elementos \r\n# Esperanza: \r\n#   - Suma del producto de la probabilidad de cada suceso por el valor de dicho suceso. \r\n#   - Por ejemplo, en un juego de azar el valor esperado es el beneficio medio. \r\n#   - Si todos los sucesos son de igual probabilidad la esperanza es la *media aritm\u00e9tica*. \r\n&gt; var(x)\t# Varianza: dispersi\u00f3n de una variable aleatoria respecto a su *esperanza* \r\n&gt; sd(x)\t\t# Desviaci\u00f3n est\u00e1ndar: media de las distancias que tienen los datos respecto de su media aritm\u00e9tica (raiz cuadrada de la varianza = sqrt(var(x))) \r\n&gt; mad(x)\t# Desviaci\u00f3n media normalizada respecto a la mediana (m\u00e1s resistente a outliers\/valores extremos que la desviaci\u00f3n est\u00e1ndar) \r\n&gt; cor(x, x)\t# Correlaci\u00f3n por coeficiente de Pearson: fuerza y direcci\u00f3n de una relaci\u00f3n lineal entre dos variables aleatorias (obviamente la correlaci\u00f3n del ejemplo es total y en la misma direcci\u00f3n dado que son los mismos n\u00fameros: 1) \r\n<\/pre>\n<ul>\n<li>Cuartiles: en diversas ocasiones haremos menci&oacute;n a los cuartiles de un conjunto de datos, estos corresponden a los siguientes elementos:\n<ul>\n<li>Q1: Los valores inferiores a Q1 representan el 25% de la poblaci&oacute;n <\/li>\n<li>Q2: Igual a la media<\/li>\n<li>Q3: Los valores\tinferiores a Q3 representan el 75% de la poblaci&oacute;n <\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<pre>\r\n&gt; quantile(x) \r\n&gt; summary(x) \r\n\tMin.  1st Qu.   Median     Mean  3rd Qu.     Max. \r\n-2.70600 -0.56750  0.10400  0.08912  0.72590  2.65400 \r\n&gt; IQR(x)  # Diferencia entre el primer y tercer cuantil (Q1 y Q3). M\u00e1s resistente a outliers\/valores extremos que la media. \r\n<\/pre>\n<ul>\n<li VALUE=1>Factores: vector con datos cualitativos<\/li>\n<\/ul>\n<pre>\r\n&gt; x = factor( sample(c(\"Yes\", \"No\", \"Perhaps\"), 20, replace=T) ) \r\n&gt; table(x)\t# Sumarizamos (numero de ocurrrencias de cada factor) \r\nx \r\n\t No Perhaps     Yes \r\n\t  5       8       7 \r\n&gt; levels(x)\t# Listamos los valores posibles \r\n[1] \"No\"      \"Perhaps\" \"Yes\"    \r\n<\/pre>\n<ul>\n<li VALUE=1>Valores no disponibles (No Available)<\/li>\n<\/ul>\n<pre>\r\n&gt; x = c(1,5,9,NA,2) \r\n&gt; na.omit(x) # Limpia los valores NA \r\n&gt; is.na(x) # Comprueba si es NA (TRUE\/FALSE) \r\n<\/pre>\n<ul>\n<li VALUE=1>Infinito<\/li>\n<\/ul>\n<pre>\r\n&gt; log(0) \r\n[1] -Inf \r\n&gt; is.infinite(log(0)) \r\n[1] TRUE \r\n<\/pre>\n<h4><a name=\"0026\">Matrices<\/a><\/h4>\n<p>En una matriz todos los datos deben ser del mismo tipo, es decir: cadenas, n&uacute;meros o booleanos.<\/p>\n<ul>\n<li>Creaci&oacute;n<\/li>\n<\/ul>\n<pre>\r\n&gt; m = matrix( c(1,2,3,4), nrow=2 ) # Creamos una matriz num\u00e9rica \r\n&gt; m \r\n\t [,1] [,2] \r\n[1,]    1    3 \r\n[2,]    2    4 \r\n\t \r\n&gt; m = cbind( c(1,2), c(3,4) ) # Identico a la anterior \r\n&gt; m = rbind( c(1,2), c(3,4) ) # Idem \r\n<\/pre>\n<ul>\n<li VALUE=1>Operaciones<\/li>\n<\/ul>\n<pre>\r\n# Producto (Fila1: 1*2 + 3*1, Fila2: 2*2 + 4*1 ) \r\n&gt; m %*% matrix( c(2,1), nrow=2 ) \r\n     [,1] \r\n[1,]    5 \r\n[2,]    8 \r\n\r\n&gt; det(m) # Determinante \r\n&gt; t(m) # Transposici\u00f3n \r\n\t [,1] [,2] \r\n[1,]    1    2 \r\n[2,]    3    4 \r\n\r\n&gt; solve(m) # Inversa \r\n\t [,1] [,2] \r\n[1,]   -2  1.5 \r\n[2,]    1 -0.5 \r\n\r\n&gt; diag(c(1,2)) # Diagonal \r\n\t [,1] [,2] \r\n[1,]    1    0 \r\n[2,]    0    2 \r\n\r\n&gt; diag(rep(1,2)) # Matriz identidad \r\n\t [,1] [,2] \r\n[1,]    1    0 \r\n[2,]    0    1 \r\n<\/pre>\n<h4><a name=\"0027\">Data Frames<\/a><\/h4>\n<p>Hasta el momento hemos visto como trabajar con un vector o un par de vectores relacionados, pero tambi&eacute;n es habitual tener que hacer tratamiento sobre tablas que contienen m&aacute;s de una columna (m&aacute;s de un vector en definitiva). Para facilitar esta tarea, R dispone de los denominados data frames.<\/p>\n<p>En un Data Frame cada columna puede ser de un tipo diferente: cadenas, n&uacute;meros, fechas o booleanos. Por otra parte, esta estructura de datos permite realizar toda una serie de operaciones de gran utilidad como cruces entre 2 dataframes o sumarizaciones.<\/p>\n<ul>\n<li>Creaci&oacute;n<\/li>\n<\/ul>\n<pre>\r\n&gt; peso = c(75, 98, 67, 80) \r\n&gt; altura = c(1.75, 1.89, 1.61, 1.77) \r\n&gt; sexo = c(\"F\",\"F\",\"M\",\"F\") \r\n&gt; personas = data.frame(peso,altura,sexo) # Construye un dataframe con los 3 vectores y establece como nombre de columna el de las variables\r\n&gt; personas \r\n  peso altura sexo \r\n1   75   1.75    F \r\n2   98   1.89    F \r\n3   67   1.61    M \r\n4   80   1.77    F \r\n&gt; rm(peso) ; rm(altura); rm(sexo)\r\n\r\n&gt; df = data.frame(c(1, 2, 3), c(7, 3, 4)) # Sin nombres de columna\r\n&gt; df = data.frame(col1 = c(1, 2, 3), col2 = c(7, 3, 4)) # Con nombres de columna \r\n<\/pre>\n<ul>\n<li VALUE=1>Acceso a elementos<\/li>\n<\/ul>\n<pre>\r\n# Muestra la columna 1 \r\n&gt; df$col1 \r\n&gt; df[,1] \r\n&gt; df[[\"col1\"]] \r\n&gt; personas[2]\t# Columna 2 \r\n       altura \r\nMaria    1.75 \r\nAlicia   1.89 \r\nPedro    1.61 \r\nJudith   1.77 \r\n\r\n&gt; personas[,2]\t# Fila 2 \r\n[1] 1.75 1.89 1.61 1.77 \r\n\r\n&gt; personas[\"Maria\", \"altura\"] \r\n[1] 1.75 \r\n&gt; personas$altura \r\n[1] 1.75 1.89 1.61 1.77 \r\n<\/pre>\n<ul>\n<li VALUE=1>Filas y\tcolumnas<\/li>\n<\/ul>\n<pre>\r\n&gt; dim(df)\t# Numero de columnas y filas \r\n&gt; names(df) # Nombres de columnas \r\n&gt; row.names(df) # Nombres de filas \r\n\r\n# Por defecto, las filas se enumeran del 1..n pero tambi&eacute;n podr&iacute;amos asignar nombres\r\n&gt; row.names(personas)=c(&quot;Maria&quot;,&quot;Alicia&quot;,&quot;Pedro&quot;,&quot;Judith&quot;)\r\n\r\n&gt; personas \r\n       peso\r\naltura sexo \r\nMaria\r\n   75   1.75    F \r\nAlicia\r\n  98   1.89    F \r\nPedro\r\n   67   1.61    M \r\nJudith\r\n  80   1.77    F\r\n\r\n# Acceso a las columnas como variables \r\n&gt; attach(df) \r\n&gt; col1 \r\n&gt; dettach(df) \r\n<\/pre>\n<ul>\n<li VALUE=1>Filtros<\/li>\n<\/ul>\n<pre>\r\n&gt; personas[personas$sexo == 'F',] \r\n       peso\r\naltura sexo \r\nMaria\r\n   75   1.75    F \r\nAlicia\r\n  98   1.89    F \r\nJudith\r\n  80   1.77    F \r\n\r\n&gt; personas[personas$sexo == 'F' &amp; personas$altura &gt; 1.75,] \r\n       peso\r\naltura sexo \r\nAlicia\r\n  98   1.89    F \r\nJudith\r\n  80   1.77    F \r\n\r\n\r\n&gt; attach(personas) \r\n&gt; personas[sexo == 'F' &amp; altura &gt; 1.75,] \r\n&gt; detach(personas)\r\n<\/pre>\n<ul>\n<li>Agrupaci&oacute;n y n&uacute;mero de ocurrencias:<\/li>\n<\/ul>\n<pre>\r\n&gt; attach(personas)\r\n&gt; table(sexo)\t# Contabiliza ocurrencias por sexo \r\nsexo\r\n\r\nF\r\nM \r\n3\r\n1 \r\n&gt; table(sexo, peso)\t# Contabiliza ocurrencias por sexo y peso \r\n    peso\r\n\r\nsexo\r\n67 75 80 98 \r\n   F\r\n 0  1  1  1 \r\n   M\r\n 1  0  0  0 \r\n&gt; detach(personas)\r\n<\/pre>\n<ul>\n<li>Cruces<\/li>\n<\/ul>\n<pre>\r\n&gt; x = data.frame(id = c(1, 2, 3, 4), datos = c(70, 30, 40, 100)) \r\n&gt; y = data.frame(id = c(1, 2, 3, 5), datos = c(.5, .3, .2, .1)) \r\n\r\n# Si no se especifica &quot;by&quot;, el cruce se realiza por el\r\n# resultado de intersect(names(x), names(y)) \r\n# Si queremos cruzar por campos con nombres diferentes en cada lado,\r\n# podemos usar &quot;by.x&quot; y &quot;by.y&quot; \r\n&gt; merge(x, y, by=c(&quot;id&quot;))\t # Inner Join \r\n\t\r\n id datos.x datos.y \r\n\t1\r\n 1      70     0.5 \r\n\t2\r\n 2      30     0.3 \r\n\t3\r\n 3      40     0.2 \r\n&gt; merge(x, y, by=c(&quot;id&quot;), all.x = TRUE) # Left Join \r\n\t\r\n id datos.x datos.y \r\n\t1\r\n 1      70     0.5 \r\n\t2\r\n 2      30     0.3 \r\n\t3\r\n 3      40     0.2 \r\n\t4\r\n 4     100      NA \r\n&gt; merge(x, y, by=c(&quot;id&quot;), all.y = TRUE) # Right Join \r\n\t\r\n id datos.x datos.y \r\n\t1\r\n 1      70     0.5 \r\n\t2\r\n 2      30     0.3 \r\n\t3\r\n 3      40     0.2 \r\n\t4\r\n 5      NA     0.1 \r\n&gt; merge(x, y, by=c(&quot;id&quot;), all = TRUE) # Outer Join \r\n\t\r\n id datos.x datos.y \r\n\t1\r\n 1      70     0.5 \r\n\t2\r\n 2      30     0.3 \r\n\t3\r\n 3      40     0.2 \r\n\t4\r\n 4     100      NA \r\n\t5\r\n 5      NA     0.1 \r\n<\/pre>\n<ul>\n<li>Sumarizaciones <\/li>\n<\/ul>\n<pre>\r\n&gt; z = data.frame(id = c(1, 2, 2, 4, 5, 4), datos1 = c(70, 30, 40, 100,\r\n22, 33), datos2 = runif(6)) \r\n\r\n&gt; aggregate(z[,2:length(z)], by=list(z$id), FUN=sum) # FUN puede ser\r\n# cualquier funcion de R (sum, mean...) o definida por nosotros \r\n\t\r\n Group.1 datos1    datos2 \r\n\t1\r\n      1     70 0.6584459 \r\n\t2\r\n      2     70 0.4219876 \r\n\t3\r\n      4    133 0.8075231 \r\n\t4\r\n      5     22 0.5956466 \r\n<\/pre>\n<ul>\n<li>Otros tratamientos en conjunto <\/li>\n<\/ul>\n<pre>\r\n# Aplicar &quot;mean&quot; cogiendo las filas (1) como argumento \r\n&gt; apply(z, 1, FUN=mean) \r\n[1]\r\n23.870088 10.987341 14.264821 34.780961  9.259135 12.448966 \r\n\r\n# Aplicar &quot;mean&quot; cogiendo las filas (2) como argumento \r\n&gt; apply(z, 2, FUN=mean) \r\n\t\r\n id   datos1   datos2 \r\n\t\r\n3.00000 49.16667  0.63899 \r\n\r\n# Sumar 1 a todos los elementos \r\n&gt; z + 1 \r\n\t\r\n id datos1   datos2 \r\n\t1\r\n 2     71 1.610265 \r\n\t2\r\n 3     31 1.962024 \r\n\t3\r\n 3     41 1.794464 \r\n\t4\r\n 5    101 1.342882 \r\n\t5\r\n 6     23 1.777406 \r\n\t6\r\n 5     34 1.346899 \r\n<\/pre>\n<h4><a name=\"0028\">Listas<\/a><\/h4>\n<p>Una lista puede contener vectores, matrices y data frames:<\/p>\n<ul>\n<li>Creaci&oacute;n<\/li>\n<\/ul>\n<pre>\r\n&gt; h = list() \r\n<\/pre>\n<ul>\n<li>Acceso a elementos<\/li>\n<\/ul>\n<pre>\r\n&gt; h[[&quot;a&quot;]] = 1\t# Acceso a elemento mediante doble corchete\r\n[[]] \r\n&gt; h[[&quot;b&quot;]] = c(1, 2, 3) \r\n&gt; h[[&quot;a&quot;]] = NULL # Borra un elemento \r\n<\/pre>\n<h3><a name=\"0015\">Introducci&oacute;n manual de datos<\/a><\/h3>\n<p>Para introducir r&aacute;pidamente datos en peque&ntilde;os vectores podemos utilizar la funcion &quot;c&quot; tal y como hemos visto en la secci&oacute;n anterior: <\/p>\n<pre>\r\n&gt; x = c(2,3,0,3,1,0,0,1) \r\n&gt; x \r\n[1]\r\n2 3 0 3 1 0 0 1 \r\n<\/pre>\n<p>Esto nos generar&iacute;a un vector denominado x con 8 valores. Tambi&eacute;n podr&iacute;amos utilizar la funci&oacute;n scan() que nos facilita la vida a la hora de hacer copy\/pastes: <\/p>\n<pre>\r\n&gt; x = scan() \r\n1:\r\n3 4 1 1 3 4 3 3 1 3 2 1 2 1 2 3 2 3 1 1 1 1 4 3 1 \r\n26:\r\n\r\nRead\r\n25 items \r\n<\/pre>\n<p>Esta funci&oacute;n lee todos los elementos que le indiquemos hasta que se encuentra una linea en blanco. <\/p>\n<p>Por otra parte, podemos crear y editar gr&aacute;ficamente un vector mediante: <\/p>\n<pre>\r\n&gt; data.entry(x2=c(NA)) # Creamos el vector num&eacute;rico x2 \r\n&gt; data.entry(x3=c(&ldquo;&rdquo;)) # Creamos el vector de cadenas x2 \r\n&gt; x = edit(as.data.frame(NULL)) # Creamos un dataframe\r\n<\/pre>\n<p>O editamos un\/os vector\/es ya existente\/s:<\/p>\n<pre>\r\n&gt; x = c(1, 2)\r\n&gt; y = c(&ldquo;a&rdquo;, &ldquo;b&rdquo;)\r\n&gt; data.entry(x) # Editamos x (variable ya existente) formateado en una\r\ntabla \r\n&gt; data.entry(x, y) # Editamos x e y (variables existentes)\r\n<\/pre>\n<p>Tambi&eacute;n podemos editar visualmente un dataframe mediante el comando &ldquo;edit&rdquo;:<\/p>\n<pre>\r\n&gt; x = data.frame(c(1,2), c(&quot;a&quot;,&quot;b&quot;)) \r\n&gt; x = edit(x) \r\n<\/pre>\n<h3><a name=\"0016\">Librer&iacute;as y datos de ejemplo<\/a><\/h3>\n<p>Como hemos comentado en la introducci&oacute;n, R dispone de una inmensa cantidad de librer&iacute;as y paquetes con funciones y datos preparados para todo tipo de an&aacute;lisis. Ver listado completo en:<a HREF=\"http:\/\/cran.r-project.org\/web\/views\/index.html\">http:\/\/cran.r-project.org\/web\/views\/index.html<\/a><\/p>\n<p>En Ubuntu GNU\/Linux se almacenan los paquetes instalados en el directorio &quot;\/usr\/lib\/R\/library\/&quot;, y para instalar nuevos debemos o bien utilizar el sistema de paquetes (buscar paquetes con &quot;aptitude search r-cran&quot;) o bien descargandolo y descomprimiendolo en el directorio anterior.<\/p>\n<p>Para la plataforma Windows, los paquetes se almacenan habitualmente en el directorio donde se haya realizado la instalaci&oacute;n de R (p.ej. &quot;c:\\Program files\\R\\&quot;), en la carpeta library. En este caso, la interfaz gr&aacute;fica Rgui nos permite instalar paquetes nuevos de CRAN autom&aacute;ticamente, o en su defecto tendremos que descargarlos y descomprimirlos en el directorio indicado.<\/p>\n<p>Para listar las librer&iacute;as disponibles podemos utilizar &quot;library&quot; sin argumento, y cuando necesitemos hacer uso de una de ellas tendremos que especificarlo para que sea cargada:<\/p>\n<pre>\r\n&gt; library(MASS) \r\n<\/pre>\n<p>Por otra parte, tanto las librer&iacute;as de R acostumbran a incorporar datos de ejemplo que podemos listar con el comando &quot;data()&quot;, para despu&eacute;s cargar un conjunto de datos:<\/p>\n<pre>\r\n&gt; data(EuStockMarkets) \r\n<\/pre>\n<p>A partir de ese momento podremos acceder a los datos por su nombre, por ejemplo &quot;EuStockMarkets&quot;.<\/p>\n<h3><a name=\"0017\">Importar\/exportar datos<\/a><\/h3>\n<h4><a name=\"0029\">Ficheros<\/a><\/h4>\n<p>En R es muy habitual trabajar con ficheros CSV (campos delimitados por ,) para as&iacute; poder ser utilizado f&aacute;cilmente en hojas de c&aacute;lculo: Veamos como podr&iacute;amos exportar a dicho formato:<\/p>\n<pre>\r\n# Exportar \r\n&gt; df = data.frame(runif(10), runif(10), runif(10)) \r\n&gt; names(df) = c(&quot;dato1&quot;, &quot;dato2&quot;, &quot;dato3&quot;)\r\n\r\n&gt; write.table(df, file = &quot;dataframe1.csv&quot;, sep = &quot;,&quot;,\r\ncol.names = NA, qmethod = &quot;double&quot;)\t# Con id\/nombres de filas \r\n&gt; write.table(df, file = &quot;dataframe2.csv&quot;, sep = &quot;,&quot;,\r\nrow.names = FALSE, qmethod = &quot;double&quot;) # Sin id\/nombre de filas \r\n<\/pre>\n<p>La importaci&oacute;n seria igual de sencilla:<\/p>\n<pre>\r\n# Importar de nuevo a R \r\n&gt; read.table(&quot;dataframe1.csv&quot;, header = TRUE, sep = &quot;,&quot;,\r\nrow.names = 1) # Con id\/nombres de filas \r\n&gt; read.table(&quot;dataframe2.csv&quot;, header = TRUE, sep = &quot;,&quot;)\r\n# Sin id\/nombres de filas \r\n<\/pre>\n<p>La funci&oacute;n read.table es muy vers&aacute;til y permite multitud de opciones que nos permitir&iacute;an cargar pr&aacute;cticamente cualquier fichero con campos delimitados por un signo (ver ayuda ?read.table).<\/p>\n<p>En caso de que queramos cargar un fichero con campos de longitud fija (sin separaci&oacute;n por signo), podemos utilizar la siguiente funci&oacute;n:<\/p>\n<pre>\r\n# Importa una tabla de 3 columnas de 5, 10 y 3 caracteres\r\nrespectivamente \r\n&gt; read.fwf(ff, widths=c(5,10,3)) \r\n<\/pre>\n<p>En ambos casos podemos utilizar el argumento colClasses para indicar el tipo de elemento que hay en cada columna. Si no se especifica R los intenta inferir, pero hay casos en los que nos interesar&aacute; especificarlos. Por ejemplo: <\/p>\n<pre>\r\n&gt; read.table(&quot;test.csv&quot;, header = TRUE, sep = &quot;,&quot;,\r\ncolClasses=&quot;character&quot;) \r\n&gt; read.table(&quot;test.csv&quot;, header = TRUE, sep = &quot;,&quot;,\r\nrow.names = 1, colClasses=c(&quot;Date&quot;, &quot;character&quot;,\r\nrep(10, &quot;numeric&quot;))) \r\n<\/pre>\n<p>Veamos un ejemplo de fichero: <\/p>\n<pre>\r\nMes Dia Edad Dato1 Dato2 \r\nJan 13 25 15 115 \r\nFeb 15 32 24 226 \r\nMar 15 24 34 228 \r\nApr 31 52 63 420 \r\nMay 16 34 29 208 \r\nJun 31 42 75 492 \r\nJul 24 34 67 436 \r\nAug 15 34 47 316 \r\nSep 13 55 37 277 \r\nOct 29 54 68 525 \r\nNov 20 87 82 577 \r\nDec 17 35 61 401 \r\nJan 21 36 64 620 \r\nFeb 26 58 80 652 \r\nMar 24 75 70 495 \r\nApr 21 70 74 514 \r\n<\/pre>\n<p>Si el anterior fichero tiene por nombre &quot;sample&quot;, ejecutariamos: <\/p>\n<pre>\r\ndatos = read.csv(&quot;sample&quot;, header=TRUE, sep=&quot; &quot;,\r\nquote=&quot;&quot;) \r\n<\/pre>\n<p>En lugar del nombre del fichero, podr&iacute;amos indicar file.choose() para que R nos pregunte el fichero que queremos cargar.<\/p>\n<h4><a name=\"00210\">Bases de Datos: MySQL<\/a><\/h4>\n<p>R almacena todos los datasets que cargamos o generamos en memoria, esto puede suponer una limitaci&oacute;n si queremos trabajar con una cantidad de informaci&oacute;n que supera la memoria RAM de nuestro sistema (actualmente, esto significa que los datos deben ser realmente muy muy grandes como para que sea una limitaci&oacute;n). <\/p>\n<p>Podr&iacute;amos trabajar importando y exportando continuamente ficheros CSV, pero no resulta eficiente a la larga. Como puntos de mejora, podemos apoyarnos en una BBDD para almacenar la informaci&oacute;n en disco y &uacute;nicamente cargar a memoria aquello que necesitemos. Lo recomendable es utilizar R con MySQL, no obstante tambi&eacute;n existen librer&iacute;as para acceder a otras BBDD (p.ej. SQLite pero se desaconseja por problemas de corrupci&oacute;n de datos y las propias limitaciones de la BBDD). <\/p>\n<p>Para instalar la libreria rmysql en Ubuntu GNU\/Linux: <\/p>\n<pre>\r\napt-get install r-cran-rmysql \r\n<\/pre>\n<p>En Windows podemos hacerlo f&aacute;cilmente tambi&eacute;n a trav&eacute;s de la interfaz gr&aacute;fica Rgui. <\/p>\n<p>Para poder trabajar, necesitaremos tambi&eacute;n la BBDD Mysql. Para Ubuntu GNU\/Linux podemos utilizar:<\/p>\n<pre>\r\napt-get install mysql-client mysql-server mysql-query-browser mysql-admin\r\n<\/pre>\n<p>En Windows lo mejor es bajarnos la versi&oacute;n no instalable de <a HREF=\"http:\/\/dev.mysql.com\/downloads\/mysql\/5.1.html#win32\">MySQL<\/a> y <a HREF=\"http:\/\/dev.mysql.com\/downloads\/gui-tools\/\">>MySQL GUI Tools<\/a>.<\/p>\n<p>Una vez bajado, lo descomprimimos y podemos iniciar la BBDD ejecutando bin\/mysqld.exe, as&iacute; como acceder a la misma mediante &quot;bin\/mysql.exe&quot;.<\/p>\n<p>Para poder empezar a trabajar, debemos crear una BBDD llamada en MySQL que, por ejemplo, podemos llamar &quot;R&quot;: <\/p>\n<pre>\r\n\t# mysql \r\n\tWelcome to the MySQL monitor.  Commands end with ; or \\g. \r\n\tYour MySQL connection id is 14 \r\n\tServer version: 5.0.51a-3ubuntu5.4 (Ubuntu) \r\n\r\n\tType 'help;' or '\\h' for help. Type '\\c' to clear the buffer. \r\n\r\n\tmysql&gt; CREATE DATABASE R; \r\n\tQuery OK, 1 row affected (0.00 sec) \r\n\r\n\tmysql&gt; quit \r\n\tBye \r\n<\/pre>\n<p>Esta tarea tambi&eacute;n podemos hacerlo desde la interfaz gr&aacute;fica MySQL Admin o el Query Browser, conectando contra localhost y usuario &quot;root&quot; (sin contrase&ntilde;a).<\/p>\n<p>Par acceder a la BBDD desde R: <\/p>\n<pre>\r\n&gt; Sys.setenv(MYSQL_HOME=&quot;C:\/Users\/xxx\/Documents\/NoBackup\/Applications\/MySQL\/mysql-5.1.31-win32&quot;)\r\n# Solo en Windows\r\n&gt; library(RMySQL) \r\nLoading\r\nrequired package: DBI \r\n\r\n# Conectamos y seleccionamos la BBDD &quot;R&quot; \r\n&gt; con = dbConnect(dbDriver(&quot;MySQL&quot;), dbname = &quot;R&quot;,\r\nuser=&quot;root&quot;, host=&quot;localhost&quot;) \r\n<\/pre>\n<p>&Uacute;nicamente en el caso de Windows tenemos que establecer la variable de entorno MYSQL_HOME apuntando al directorio donde hayamos descomprimido\/instalado la MySQL.<\/p>\n<p>Vamos a crear una tabla que contenga un dataframe de R y a continuaci&oacute;n lo descargamos de la memoria:<\/p>\n<pre>\r\n# Creamos un data frame \r\n&gt; x = data.frame(c(1,2,3), c(5200, 1300, 3400), c(&quot;Juan&quot;,\r\n&quot;Judith&quot;, &quot;Ana&quot;)) \r\n&gt; names(x) = c(&quot;id&quot;, &quot;datos&quot;, &quot;nombre&quot;) \r\n\r\n# Creamos una tabla con el data frame anterior \r\n&gt; dbWriteTable(con, &quot;Datos&quot;, x) \r\n\r\n# Eliminamos el data frame de la memoria \r\n&gt; rm(x) \r\n<\/pre>\n<p>Ahora vamos a recuperar el dataframe leyendo la informaci&oacute;n de la BBDD:<\/p>\n<pre>\r\n# Recuperamos de la tabla el dataframe \r\n&gt; x = dbReadTable(con, &quot;Datos&quot;) \r\n\r\n# Listamos los campos de la tabla &quot;Datos \r\n&gt; dbListFields(con, &quot;Datos&quot;) \r\n<\/pre>\n<p>Tambi&eacute;n podemos construir dataframes a partir de consultas SQL, esto nos permite aprovechar la potencia de MySQL para hacer filtros, JOINs, sumarizaciones, etc (aunque todas esas operaciones tambi&eacute;n las podemos hacer con R sin depender de la BBDD):<\/p>\n<pre>\r\n# Construimos un dataframe a partir de una consulta \r\n&gt; x = dbGetQuery(con, &quot;SELECT id, nombre FROM Datos WHERE datos &gt;\r\n2000&quot;) \r\n<\/pre>\n<p>Otras operaciones:<\/p>\n<pre>\r\n# Listado de tablas \r\n&gt; dbListTables(con) \r\n\r\n# Enviamos una sentencia DROP\/CREATE\/... que no devuelve informaci&oacute;n\r\n\r\n#  en este caso borramos la tabla Datos \r\n&gt; dbSendQuery(&quot;DROP TABLE Datos&quot;) \r\n\r\n# Desconectamos \r\n&gt; dbDisconnect(con) \r\n<\/pre>\n<p>Finalmente, otro punto interesante de utilizar MySQL es que podemos usar el Query Browser gr&aacute;fico y acceder al contenido de las tablas y mediante SQL realizar filtros r&aacute;pidos, ordenaci&oacute;n de datos, exportar a Excel\/CSV, etc. Esto puede ser de gran utilidad para entender los datos de forma m&aacute;s r&aacute;pida sin depender de la consola de R.<\/p>\n<h3><a name=\"0018\">Distribuciones de probabilidad<\/a><\/h3>\n<p>Para cada distribuci&oacute;n de probabilidad disponible R pone a nuestro servicio 4 tipos de funciones:<\/p>\n<ul>\n<li>r: generaci&oacute;n de n&uacute;meros aleatorios<\/li>\n<li>p: probabilidades<\/li>\n<li>d: funci&oacute;n de densidad<\/li>\n<li>q: cuantiles<\/li>\n<\/ul>\n<p>Por ejemplo, para la distribuci&oacute;n uniforme tenemos las funciones runif, punif, dunif y qunif. <\/p>\n<h4><a name=\"00211\">Generaci&oacute;n de n&uacute;meros aleatorios<\/a><\/h4>\n<p>Ser&aacute; habitual que utilicemos las funciones de generaci&oacute;n de n&uacute;meros aleatorios de R para construir vectores\/matrices\/data frames con n&uacute;meros que siguen una distribuci&oacute;n determinada.<\/p>\n<p>En esta secci&oacute;n vamos a tratar con las funciones &#8216;r&#8217; para la generaci&oacute;n de n&uacute;meros y las &#8216;d&#8217; (densidad) para el dibujo de gr&aacute;ficas (que nos facilitar&aacute;n entender las distribuciones).<\/p>\n<p>Como gr&aacute;ficas generaremos histogramas y curvas para las distribuciones de n&uacute;meros continuos y puntos para las discretas:<\/p>\n<ul>\n<li>Distribuciones de n&uacute;meros continuos<\/li>\n<\/ul>\n<pre>\r\n# Uniforme (misma probabilidad para todos los n\u00fameros) \r\n&gt; x=runif(100, 0, 1) \r\n&gt; hist(x,probability=TRUE,col=gray(.9),main=\"uniform on [0,1]\") \r\n&gt; curve(dunif(x,0,1),add=T) # Densidad \r\n\r\n# Normal = Gaussiana \r\n&gt; x=rnorm(100, mean=50, sd=25) # 100 n\u00fameros de media situada en 100 (en lugar de 0) y desviaci\u00f3n estandar de 25 \r\n&gt; hist(x,probability=TRUE,col=gray(.9),main=\"normal mu=0,sigma=1\") \r\n&gt; curve(dnorm(x, mean=50, sd=25),add=T) # Densidad\r\n\r\n# Exponencial \r\n&gt; x=rexp(100,50) # 100 n\u00fameros con media en 50 \r\n&gt; hist(x,probability=TRUE,col=gray(.9),main=\"exponential mean=2500\") \r\n&gt; curve(dexp(x,50),add=T) # Densidad\r\n\r\n## Chi cuadrado con 1 grado de libertad \r\n&gt; rchisq(100, 1) \r\n\r\n# Dibujamos Chi cuadrado con varios grados de libertad \r\n&gt; curve(dchisq(x,1), xlim=c(0,10), ylim=c(0,.6), col='red', lwd=3) \r\n&gt; curve(dchisq(x,2), add=T, col='green', lwd=3) \r\n&gt; curve(dchisq(x,3), add=T, col='blue', lwd=3) \r\n&gt; curve(dchisq(x,5), add=T, col='orange', lwd=3) \r\n\r\n## Student's T \r\n&gt; rt(100, 1) \r\n\r\n# Dibujamos varios grados de libertad \r\n&gt; curve( dt(x,1), xlim=c(-3,3), ylim=c(0,.4), col='red', lwd=2 ) \r\n&gt; curve( dt(x,2), add=T, col='blue', lwd=2 ) \r\n&gt; curve( dt(x,5), add=T, col='green', lwd=2 ) \r\n&gt; curve( dt(x,10), add=T, col='orange', lwd=2 ) \r\n&gt; curve( dnorm(x), add=T, lwd=3, lty=3 ) \r\n\r\n## Fisher's F \r\n&gt; rf(100, 1, 1) \r\n\r\n&gt; curve(df(x,1,1), xlim=c(0,2), ylim=c(0,.8), lty=2) \r\n&gt; curve(df(x,3,1), add=T) \r\n&gt; curve(df(x,6,1), add=T, lwd=3) \r\n&gt; curve(df(x,3,3), add=T, col='red') \r\n&gt; curve(df(x,6,3), add=T, lwd=3, col='red') \r\n&gt; curve(df(x,3,6), add=T, col='blue') \r\n&gt; curve(df(x,6,6), add=T, lwd=3, col='blue') \r\n\r\n## Lognormal law \r\n&gt; rlnorm(100) \r\n\r\n&gt; curve(dlnorm(x), xlim=c(-.2,5), lwd=3, main=\"Log-normal distribution\") \r\n<\/pre>\n<ul>\n<li>Distribuciones de n&uacute;meros discretos<\/li>\n<\/ul>\n<pre>\r\n# Muestreo con repetici\u00f3n y probabilidad uniforme\r\nx = sample(1:100, 10, replace=T) # 10 n\u00famero del 1 al 100\r\n\r\n# Binomial\r\n&gt; n = 20 \r\n&gt; p = 0.5 \r\n&gt; x = rbinom(100, n, p) # 100 n\u00fameros: 20 intentos con una probabilidad de exito de cada intento del 50% (se suman el n\u00famero de exitos) \r\n&gt; hist(x,probability=TRUE,) \r\n\r\n# Dibujamos los puntos donde se encontrar\u00eda la densidad de la distribuci\u00f3n \r\n&gt; xvals=0:n \r\n&gt; points(xvals,dbinom(xvals,n,p),type=\"h\",lwd=3) # Linea \r\n&gt; points(xvals,dbinom(xvals,n,p),type=\"p\",lwd=3) # Punto \r\n\r\n# Hypergeometric \r\n&gt; x = rhyper(100, 300, 100, 100) \r\n&gt; hist(x,probability=TRUE,) \r\n\r\n# Poisson \r\n&gt; x = rpois(100, 1) \r\n&gt; hist(x,probability=TRUE,) \r\n\r\n# Geometrica \r\n&gt; x = rgeom(100, .5) \r\n&gt; hist(x,probability=TRUE,) \r\n\r\n# Binomial negativa \r\n&gt; x = rnbinom(100, 10, .25) \r\n&gt; hist(x,probability=TRUE,) \r\n<\/pre>\n<h4><a name=\"00212\">Muestreo aleatorio<\/a><\/h4>\n<p>Las funciones de la secci&oacute;n anterior generan n&uacute;meros aleatorios que pueden repetirse, sin embargo si queremos hacer un muestreo necesitamos una funci&oacute;n que nos permita generar una serie de n&uacute;meros aleatorios no repetidos (p.ej. Como cuando tenemos 10 bolas en un bombo y vamos extray&eacute;ndolas, el primer n&uacute;mero que sale no se volver&aacute; a repetir). Para esto utilizaremos la funci&oacute;n sample, la cual ya aparec&iacute;a en la secci&oacute;n anterior pero con el argumento &quot;replace=T&quot; que hace variar su comportamiento. Por ejemplo cogemos 10 n&uacute;meros entre 1 y 100 donde todos tienen las mismas probabilidades de ser elegidos: <\/p>\n<pre>\r\n&gt; sample(1:100,10) \r\n [1]\r\n53 99 63 92 60 87 54 25 51 73 \r\n<\/pre>\n<p>Con esta funci&oacute;n podemos extraer filas de una matriz, utilizando los n&uacute;meros generados como indices: <\/p>\n<pre>\r\n&gt; personas[sample(1:length(personas), 2),] \r\npeso altura sexo \r\n1  75   1.75    F \r\n3  67   1.61    M \r\n<\/pre>\n<h4><a name=\"00213\">Generaci&oacute;n de n&uacute;meros secuenciales<\/a><\/h4>\n<p>Si en lugar de n&uacute;meros aleatorios queremos generar secuencias, podemos utilizar las siguientes notaciones: <\/p>\n<pre>\r\n&gt; x = 1:10 \r\n [1]  1  2  3  4  5  6  7  8  9 10 \r\n&gt; x = seq(1, 10, 2) # N\u00fameros del 1 al 10 con incrementos de 2 \r\n[1] 1 3 5 7 9 \r\n&gt; x = letters[1:11] \r\n[1] \"a\" \"b\" \"c\" \"d\" \"e\" \"f\" \"g\" \"h\" \"i\" \"j\" \"k\" \r\n<\/pre>\n<h4><a name=\"00214\">Probabilidades<\/a><\/h4>\n<p>Con las funciones &#8216;p&#8217; y &#8216;q&#8217; podemos responder preguntas del siguiente tipo:<\/p>\n<ul>\n<li>&iquest;Cual es la probabilidad que en una distribuci&oacute;n normal con media en 0 y desviaci&oacute;n est&aacute;ndar 1 un n&uacute;mero sea inferior a 0.7?<\/li>\n<\/ul>\n<pre>\r\n&gt; pnorm(.7, mean=0, sd=1) \r\n[1] 0.7580363\r\n<\/pre>\n<ul>\n<li>&iquest;Y que sea superior a 0.7? <\/li>\n<\/ul>\n<pre>\r\n&gt; pnorm(.7,lower.tail=F) \r\n[1] 0.2419637 \r\n<\/pre>\n<ul>\n<li>Que valor limita el &aacute;rea que representa un 75% de probabilidades (&aacute;rea de la derecha): <\/li>\n<\/ul>\n<pre>\r\n&gt; qnorm(.75) \r\n[1] 0.6744898 \r\n<\/pre>\n<h3><a name=\"0019\">Visualizaci&oacute;n de datos de una variable<\/a><\/h3>\n<ul>\n<li>Gr&aacute;ficos tipo tarta: Genera tantas divisiones de la tarta como elementos en el vector.<\/li>\n<\/ul>\n<pre>\r\n&gt; gastos = c(Gimnasio=60, Dietas=345, Alquiler=800, Transporte=200) \r\n&gt; pie(gastos) \r\n<\/pre>\n<ul>\n<li>Gr&aacute;ficos de barras: Visualiza tantas barras como elementos existen en el vector.<\/li>\n<\/ul>\n<pre>\r\n&gt; gastos = c(Gimnasio=60, Dietas=345, Alquiler=800, Transporte=200) \r\n&gt; barplot(gastos) \r\n<\/pre>\n<ul>\n<li>Histogramas: Muestra un n&uacute;mero determinado de barras, donde cada una representa un rango y la &ldquo;altura&rdquo; depende del n&uacute;mero de elementos del vector que se encuentran en dicho rango. Nos permiten ver donde se concentran los n&uacute;meros.\n<p>\tEn el caso de pruebas de datos, un histograma nos puede servir para mostrar claramente donde se concentran las diferencias detectadas.<\/li>\n<\/ul>\n<pre>\r\n&gt; transferencias=abs(rnorm(100, mean=100, sd=50)) \r\n&gt; hist(transferencias) # En el eje Y se visualiza el n&uacute;mero de\r\n# ocurrencias\r\n&gt; hist(transferencias, probability=TRUE) # En el eje Y se visualizan\r\n# las probabilidades\r\n&gt; hist(transferencias, breaks=4) # Los datos se agrupan en 5 (hay 4\r\ndivisiones)\r\n<\/pre>\n<ul>\n<li VALUE=1>Histogramas con marcas de ocurrencia<\/li>\n<\/ul>\n<pre>\r\n&gt; hist(transferencias) # En el eje Y se visualiza el n&uacute;mero de ocurrencias\r\n&gt; rug(transferencias) # Marcas con las ocurrencias\r\n<\/pre>\n<ul>\n<li VALUE=1>Histogramas con linea de densidad: facilita la identificaci&oacute;n de la distribuci&oacute;n de probabilidad.<\/li>\n<\/ul>\n<pre>\r\n&gt; hist(transferencias, probability=TRUE) # Para visualizar la densidad\r\n# se requiere que el histograma refleje la probabilidad\r\n&gt; lines(density(transferencias), col=&quot;red&quot;, lwd=3) # Linea\r\n# con la densidad de probabilidad\r\n<\/pre>\n<ul>\n<li>Boxplot: Visualiza los siguientes elementos de abajo a arriba (o izquierda a derecha)\n<ul>\n<li>M&iacute;nimo<\/li>\n<li>Q1<\/li>\n<li>La mediana<\/li>\n<li>Q3<\/li>\n<li>Q3+1,5*IQR<\/li>\n<li>Puntos extremadamente separados<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<pre>\r\n&gt; transferencias.nacionales=abs(rnorm(100, mean=130, sd=50)) \r\n&gt; transferencias.internacionales=abs(rnorm(100, mean=150, sd=60)) \r\n&gt; transferencias.nacionales[1] = 310 \r\n&gt; transferencias.nacionales[2] = 280 \r\n&gt; transferencias.internacionales[1] = 350\r\n&gt; boxplot(transferencias.nacionales, transferencias.internacionales,\r\nnames=c(&quot;Nacionales&quot;, &quot;Internacionales&quot;)), horizontal=TRUE) \r\n<\/pre>\n<ul>\n<li>Histograma y boxplot simult&aacute;neos: Nos permite observar la distribuci&oacute;n de probabilidad y los quantiles, media, etc.<\/li>\n<\/ul>\n<pre>\r\n&quot;hist.and.boxplot\" &lt;- \r\n  function (x,...) { \r\n    ## Plot both the histogram and the boxplot \r\n    ## to show relationship easily. \r\n    op&lt;-par(no.readonly=TRUE) \r\n    on.exit(par(op)) \r\n    layout(matrix(c(1,2),2,1),heights=c(3,1)) \r\n    par(mai=c(1,1,1,1)\/2) \r\n    hist(x,xlab=FALSE,col=gray(0.95),yaxt='n',...) \r\n    rug(x) \r\n    boxplot(x,horizontal=TRUE) \r\n  } \r\n<\/pre>\n<pre>\r\n&gt; transferencias=abs(rnorm(100, mean=100, sd=50)) \r\n&gt; hist.and.boxplot(transferencias) \r\n<\/pre>\n<ul>\n<li>Stemplot: stemplot es un gr&aacute;fico en modo texto similar al histograma pero invertido lateralmente, &uacute;til para conjuntos de datos peque&ntilde;os:<\/li>\n<\/ul>\n<pre>\r\n&gt; x = rnorm(100)\r\n&gt; stem(x) \r\n\r\n  The decimal point is at the | \r\n\r\n  -3 | 0 \r\n  -2 | \r\n  -1 | 975443333222110 \r\n  -0 | 998888666666555544333333322222211000 \r\n   0 | 11222222223333344455667779 \r\n   1 | 001223334444666677 \r\n   2 | 016 \r\n   3 | 4 \r\n<\/pre>\n<ul>\n\tComo se puede observar, en el ejemplo debemos considerar que la coma empieza en la | y por tanto tenemos un punto en -3 (-3.0), ninguno en -2, varios en -1 (-1.9, -1.7, -1.5, 2 puntos -1.4, etc.) y as&iacute; sucesivamente. El gr&aacute;fico es m&aacute;s representativo si inclinamos la cabeza hacia la derecha.\n<\/ul>\n<ul>\n<li VALUE=1>Histograma y boxplot simult&aacute;neos:<\/li>\n<\/ul>\n<pre>\r\n\"plot.hist.and.box\" &lt;- \r\n  function (x,...) { \r\n    ## Plot both the histogram and the boxplot \r\n    ## to show relationship easily. \r\n    op&lt;-par(no.readonly=TRUE) \r\n    on.exit(par(op)) \r\n    layout(matrix(c(1,2),2,1),heights=c(3,1)) \r\n    par(mai=c(1,1,1,1)\/2) \r\n    hist(x,xlab=FALSE,col=gray(0.95),yaxt='n',...) \r\n    rug(x) \r\n    boxplot(x,horizontal=TRUE) \r\n  } \r\n<\/pre>\n<pre>\r\n&gt; x = rnorm(100)\r\n&gt; plot.hist.and.box(x) \r\n<\/pre>\n<h3><a name=\"00110\">Visualizaci&oacute;n de datos de dos variables<\/a><\/h3>\n<ul>\n<li VALUE=1>Gr&aacute;ficos\tde barras: Imaginemos que tenemos dos variables clasificadas, la primera de ella corresponde a si la persona es fumadora o no y la segunda al n&uacute;mero de horas que dedica al estudio (1 = menos de 5 horas, 2 = entre 5 y 10 horas, 3 = m&aacute;s de 3 horas): <\/li>\n<\/ul>\n<pre>\r\n&gt; fumador = c(\"S\",\"N\",\"N\",\"S\",\"N\",\"S\",\"S\",\"S\",\"N\",\"S\") \r\n&gt; estudio = c(1,2,2,3,3,1,2,1,3,2) \r\n&gt; t = table(fumador,estudio) # Genera tabla de contingencias\r\n&gt; t \r\n\t   estudio \r\nfumador 1 2 3 \r\n\t  N 0 2 2 \r\n\t  S 3 2 1 \r\n<\/pre>\n<ul>\n\tComo observamos, podemos utilizar de nuevo la funci&oacute;n table() para contabilizar el n&uacute;mero de apariciones de cada categor&iacute;a. Si queremos conocer la probabilidad de caer en cada una de las parejas de categor&iacute;as:\n<\/ul>\n<pre>\r\n&gt; options(digits=3) # Limitamos a 3 decimales como m\u00e1ximo \r\n&gt; prop.table(t) # Todos los importes de la tabla anterior sumaran 1 \r\n\t   estudio \r\nfumador   1   2   3 \r\n\t  N 0.0 0.2 0.2 \r\n\t  S 0.3 0.2 0.1 \r\n<\/pre>\n<ul>\n\tPara visualizar la informaci&oacute;n mediante un gr&aacute;fico de barras:\n<\/ul>\n<pre>\r\n&gt; barplot(table(estudio,fumador),main=&quot;Horas de estudio segun fumador\/no fumador&quot;, \r\n+ beside=TRUE, # Separar las categorias en varias barras \r\n+ legend.text=c(&quot;Menos 5 horas&quot;,&quot;5-10&quot;,&quot;M&aacute;s de 10 horas&quot;)) \r\n<\/pre>\n<ul>\n<li>Puntos en un plano: Dadas las coordenadas X e Y de un conjunto de puntos, dibujamos sobre un plano.<\/li>\n<\/ul>\n<pre>\r\n&gt; punto.espacio = data.frame(x=c(1, 5, 10), y=c(200, 50, 100)) \r\n&gt; puntos.espacio\r\n   x   y \r\n1  1 200 \r\n2  5  50 \r\n3 10 100 \r\n&gt; plot(puntos.espacio)\r\n<\/pre>\n<ul>\n<li>Puntos en un plano con linea de regresi&oacute;n: Si entendemos que X es un valor que controlamos (p.ej. tabletas de chocolate que comemos) e Y un valor que medimos (p.ej. grado de felicidad), podemos utilizar una regresi&oacute;n lineal para predecir las Y para un valor desconocido de X (p.ej. cual sera mi grado de felicidad si como 20 tabletas de chocolate).\n<p>\tVeamos como podemos dibujar una linea en nuestro gr&aacute;fico que corresponda con la regresi&oacute;n lineal:<\/li>\n<\/ul>\n<pre>\r\n&gt; x.chocolate = c(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) \r\n&gt; y.felicidad = c(4, 7, 10, 6, NA, NA, NA, 1, 2, 1)\r\n&gt; plot(x.chocolate, y.felicidad) \r\n&gt; abline(lm(y.felicidad ~ x.chocolate), col=&quot;red&quot;) # lm =\r\nlinear model (variable y como funci&oacute;n lineal de x) \r\n<\/pre>\n<ul>\n<li>Puntos en un plano con linea de regresi&oacute;n resistente: linea con capacidad de &quot;resistir&quot; a la influencia de un porcentaje determinado de datos muy dispersos (p.ej. reducir el efecto que tiene 2 datos puntuales extremos):<\/li>\n<\/ul>\n<pre>\r\n&gt; library(MASS) # Cargamos un paquete que contiene la funci&oacute;n rlm \r\n&gt; x.chocolate = c(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) \r\n&gt; y.felicidad = c(4, 7, 10, 6, NA, NA, NA, 1, 2, 1)\r\n&gt; plot(x.chocolate, y.felicidad) \r\n&gt; abline(lm(y.felicidad ~ x.chocolate), col=&quot;red&quot;) # Linea de regresi&oacute;n \r\n&gt; abline(rlm(y.felicidad ~ x.chocolate), col=&quot;red&quot;, lty=2) \r\n# Linea de regresi&oacute;n resistente\r\n<\/pre>\n<ul>\n<li>Puntos en un plano con linea de regresi&oacute;n e histogramas de X e Y<\/li>\n<\/ul>\n<pre>\r\n\"scatterplot\" &lt;- \r\n  function(x,y,...) { \r\n\tdef.par = par(no.readonly = TRUE)# save default, for resetting... \r\n\tn&lt;-length(x) \r\n\txhist = hist(x,sqrt(n), plot=FALSE) \r\n\tyhist = hist(y, sqrt(n), plot=FALSE) \r\n\ttop = max(c(xhist$counts, yhist$counts)) \r\n\txrange = c(min(x),max(x)) \r\n\tyrange = c(min(y),max(y)) \r\n\tnf = layout(matrix(c(2,0,1,3),2,2,TRUE), c(3,1), c(1,3), TRUE) \r\n\tlayout.show(nf) \r\n\r\n\tpar(mar=c(3,3,1,1)) \r\n\tplot(x, y, xlim=xrange, ylim=yrange, xlab=\"x\", ylab=\"y\",...) \r\n\tabline(lm(y~x)) \r\n\tpar(mar=c(0,3,1,1)) \r\n\tbarplot(xhist$counts, axes=FALSE, ylim=c(0, top), space=0,col=gray(.95)) \r\n\tpar(mar=c(3,0,1,1)) \r\n\tbarplot(yhist$counts, axes=FALSE, xlim=c(0, top), \r\n\t        space=0,col=gray(.95), horiz=TRUE) \r\n\r\n\tpar(def.par)#- reset to default \r\n  } \r\n<\/pre>\n<pre>\r\n&gt; x = abs(rnorm(100, mean=100, sd=50) )\r\n&gt; y = rexp(100, rate=.1) \r\n&gt; scatterplot(x, y) \r\n<\/pre>\n<ul>\n<li>Agrupa en categor&iacute;as y visualiza boxplot (M&iacute;nimo, Q1, mediana, Q3, Q3+1,5*IQR, outliers):<\/li>\n<\/ul>\n<pre>\r\n&gt; x = runif(10) # Valores\r\n&gt; y = c(1, 1, 1, 2, 2, 1, 2, 3, 3, 2) # Categorias\r\n&gt; boxplot(x ~ y) \r\n<\/pre>\n<h3><a name=\"00111\">Identificar puntos en un gr&aacute;fico<\/a><\/h3>\n<p>Mostramos un gr&aacute;fico a partir de unos datos: <\/p>\n<pre>\r\n  &gt; x = runif(100) \r\n  &gt; y = runif(100) \r\n  &gt; plot(x,y) \r\n<\/pre>\n<p>A continuaci&oacute;n utilizamos &#8216;identify&#8217; para indicar que queremos localizar 1 punto: <\/p>\n<pre>\r\n  &gt; identify(x, y, n=1) # Hacemos click en el gr&aacute;fico y nos\r\ndevuelve el indice del punto \r\n  [1] 56 \r\n<\/pre>\n<p>Para obtener los valores del punto, utilizamos el indice en los vectores usados para el gr&aacute;fico: <\/p>\n<pre>\r\n  &gt; c(x[56],y[56]) \r\n  [1] 0.2514029 0.9420260 \r\n<\/pre>\n<h3><a name=\"00112\">Identificar la distribuci&oacute;n de los datos<\/a><\/h3>\n<p>Determinadas pruebas estad&iacute;sticas que podemos hacer implican que los datos se encuentran repartidos probabilisticamente seg&uacute;n una distribuci&oacute;n determinada. Por ejemplo, los T-Tests son &uacute;tiles cuando tenemos datos que siguen una distribuci&oacute;n normal (gaussiana), pero no cuando son uniformes. Por eso es importante conocer que herramientas tenemos para identificar la potencial distribuci&oacute;n que describe mejor a nuestros datos.<\/p>\n<p>Una primera validaci&oacute;n podria ser la ejecuci&oacute;n de la prueba Shapiro-Wilk que nos permite comprobar si una distribuci&oacute;n es normal (ver secci&oacute;n &quot;Pruebas estad&iacute;sticas&quot;). Pero tambi&eacute;n podemos apoyar nuestro an&aacute;lisis en gr&aacute;ficos que nos ayudaran a identificar o confirmar la distribuci&oacute;n. La siguiente funci&oacute;n que nos permite visualizar el histograma y densidad de unos datos conjuntamente con la densidad teorica de una distribuci&oacute;n determinada: <\/p>\n<pre>\r\nhist.density = function(x, FUN=dnorm, ...) { \r\n  hist(x, probability=TRUE, breaks=20, col=\"light blue\") \r\n  rug(jitter(x, 5)) \r\n  # Densidad de x \r\n  points(density(x), type='l', lwd=3, col='red') \r\n  # Densidad teorica de una distribuci\u00f3n concreta \r\n  f = function(t) { \r\n\t# t =&gt; Graph's X \r\n\tFUN(t, ... ) \r\n  } \r\n  curve(f, add=T, col=\"red\", lwd=3, lty=2) \r\n} \r\n<\/pre>\n<p>Probamos a comparar un par de conjuntos de datos contra la distribuci&oacute;n normal: <\/p>\n<pre>\r\nx = rnorm(100) hist.density(x, FUN=dnorm, mean=mean(x), sd=sd(x)) \r\nx = rexp(100) hist.density(x, FUN=dnorm, mean=mean(x), sd=sd(x)) \r\n<\/pre>\n<p>Y ahora, contra la exponencial: <\/p>\n<pre>\r\nx = rnorm(100) hist.density(rnorm(100), FUN=dexp) \r\nx = rexp(100) hist.density(rexp(100), FUN=dexp) \r\n<\/pre>\n<p>Otra t&eacute;cnica que podemos utilizar es la visualizaci&oacute;n del Quartil-Quartil plot:<\/p>\n<pre>\r\nqq = function (y, ylim, quantiles=qnorm, \r\n\tmain = \"Q-Q Plot\", xlab = \"Theoretical Quantiles\", \r\n\tylab = \"Sample Quantiles\", plot.it = TRUE, ...) \r\n{ \r\n  y = y[!is.na(y)] \r\n  if (0 == (n = length(y))) \r\n\tstop(\"y is empty\") \r\n  if (missing(ylim)) \r\n\tylim = range(y) \r\n  x = quantiles(ppoints(n))[order(order(y))] \r\n  if (plot.it) \r\n\tplot(x, y, main = main, xlab = xlab, ylab = ylab, ylim = ylim, \r\n\t\t  ...) \r\n  # From qqline \r\n  y = quantile(y, c(0.25, 0.75)) \r\n  x = quantiles(c(0.25, 0.75)) \r\n  slope = diff(y)\/diff(x) \r\n  int = y[1] - slope * x[1] \r\n  abline(int, slope, ...) \r\n  invisible(list(x = x, y = y)) \r\n} \r\n<\/pre>\n<p>La anterior funci&oacute;n dibujara el QQ plot de los datos actuales y la linea que une el primer y tercer cuartil de los mismos. Las reglas para interpretar el gr&aacute;fico son las siguientes: <\/p>\n<p>1.- Si la parte izquierda se encuentra por ENCIMA de la linea =&gt; la distribuci&oacute;n de los datos es MAYOR en la izquierda que la de la distribuci&oacute;n comparada <\/p>\n<p>2.- Si la parte izquierda se encuentra por DEBAJO de la linea =&gt; la distribuci&oacute;n de los datos es MENOR en la izquierda que la de la distribuci&oacute;n comparada <\/p>\n<p>3.- Si la parte derecha se encuentra por ENCIMA de la linea =&gt; la distribuci&oacute;n de los datos es MENOR en la derecha que la de la distribuci&oacute;n comparada <\/p>\n<p>4.- Si la parte derecha se encuentra por DEBAJO de la linea =&gt; la distribuci&oacute;n de los datos es MAYOR en la derecha que la de la distribuci&oacute;n comparada <\/p>\n<p>Probamos a comparar unos datos contra la distribuci&oacute;n uniforme, exponencial y normal: <\/p>\n<pre>\r\nqq(runif(100), quantiles=qunif) # La linea se solapa con los puntos \r\nqq(runif(100), quantiles=qexp) # Concentraciones diferentes \r\nqq(runif(100), quantiles=qnorm) \r\n<\/pre>\n<h3><a name=\"00113\">Diferentes formas de entender la probabilidad<\/a><\/h3>\n<h4><a name=\"00215\">Probabilidades frecuentista<\/a><\/h4>\n<p>Asociados a sistemas f&iacute;sicos aleatorios como la ruleta rusa, los dados o los &aacute;tomos reactivos. En estos sistemas un tipo de evento tiende a ocurrir con una frecuencia persistente. Las probabilidades de frecuencia intentan describir justamente estas frecuencias estables. <\/p>\n<p>Las 2 teor&iacute;as principales: <\/p>\n<ul>\n<li>Teor&iacute;as de la frecuencia probabil&iacute;stica: la probabilidad es la frecuencia relativa con la que se da un suceso, en el l&iacute;mite de un n&uacute;mero muy grande de sucesos.<\/li>\n<li>Teor&iacute;as de la propensi&oacute;n probabil&iacute;stica: la probabilidad es una propensi&oacute;n o tendencia f&iacute;sica de un tipo de evento, por ejemplo que al lanzar muchas veces (teor&iacute;a de los grandes n&uacute;meros) una moneda al aire, el 50% de veces saldr&aacute; cara y el 50% cruz. Dado que seg&uacute;n las teor&iacute;as de la frecuencia probabil&iacute;stica no existe una frecuencia en el lanzamiento de una moneda, solo en un grupo de lanzamientos, las teor&iacute;as de la propensi&oacute;n hablan de tendencia\/propensi&oacute;n en un &uacute;nico lanzamiento.<\/li>\n<\/ul>\n<p>La mayor parte de funciones de R que veremos en este documento parten de este enfoque.<\/p>\n<h4><a name=\"00216\">Probabilidades bayesienas o basadas en evidencias<\/a><\/h4>\n<p>Los estad&iacute;sticos de la escuela bayesiana aceptan la existencia e importancia de las probabilidades f&iacute;sicas, pero consideran que el c&aacute;lculo de probabilidades basadas en evidencias tambi&eacute;n es v&aacute;lido y necesario. Estos entienden la probabilidad en base a 2 interpretaciones diferentes: <\/p>\n<ul>\n<li>Interpretaci&oacute;n subjetiva: Se interpreta la probabilidad como el nivel de creencia de un individuo sobre una proposici&oacute;n.<\/li>\n<li>Interpretaci&oacute;n objetiva: Las reglas de la estad&iacute;stica bayesiana pueden ser justificadas, racionalizadas e interpretadas como una extensi&oacute;n de la l&oacute;gica aristot&eacute;lica. Esta supone que la mente reproduce s&oacute;lo la realidad, la existencia de las cosas tal y como son.<\/li>\n<\/ul>\n<p>La inferencia bayesiana usa un estimador num&eacute;rico del grado de creencia en una hip&oacute;tesis a&uacute;n antes de observar la evidencia y calcula un estimador num&eacute;rico del grado de creencia en la hip&oacute;tesis despu&eacute;s de haber observado la evidencia. Veamos un ejemplo: <\/p>\n<ul>\n<li>Probabilidad subjetiva: El 80% de los correos que contienen la palabra &quot;free&quot;\ty &quot;drugs&quot; son SPAM.<\/li>\n<li>Nueva evidencia: Recibimos un email que contiene &quot;free&quot; y &quot;drugs&quot;.<\/li>\n<li>Probabilidad: &iquest;El nuevo email es SPAM? Hay una probabilidad del 80% de que el mensaje sea SPAM. <\/li>\n<li>Despu&eacute;s de observar la nueva evidencia: Comprobamos si el mensaje realmente es SPAM y se ajustan las probabilidades anteriormente calculadas. <\/li>\n<\/ul>\n<p>La probabilidad subjetiva inicial puede estar basada en una creencia soportada por estudios sobre los correos basura que circulan por internet, pero no es una probabilidad emp&iacute;rica. No sabemos que tipo de correo recibimos en nuestro buz&oacute;n, quiz&aacute;s trabajamos en el sector farmac&eacute;utico y por tanto es habitual recibir correos con la palabra &quot;drugs&quot;. Sin embargo, la probabilidad bayesiana tiene la capacidad de &quot;aprender&quot; y ajustarse a las evidencias que se van observando. De hecho podr&iacute;amos incluir f&aacute;cilmente la evaluaci&oacute;n de m&aacute;s variables (no solo la existencia de &quot;drugs&quot; y &quot;free&quot;).<\/p>\n<p>Por otra parte, los m&eacute;todos bayesianos permiten incorporar de forma natural cualquier tipo de informaci&oacute;n previa. Si tuvi&eacute;semos mensajes de SPAM que hemos recibido, podr&iacute;amos calcular las probabilidades iniciales. <\/p>\n<p>En esencia, los seguidores de la estad&iacute;stica tradicional s&oacute;lo admiten probabilidades basadas en experimentos repetibles y que tengan una confirmaci&oacute;n emp&iacute;rica mientras que los llamados estad&iacute;sticos bayesianos permiten probabilidades subjetivas. <\/p>\n<p>Es importante tener en cuenta que las probabilidades bayesianas abren un debate sobre si contribuyen con justificaciones v&aacute;lidas o simplemente creencias, dado que con la misma informaci&oacute;n las personas pueden tener diferentes interpretaciones en funci&oacute;n de su grado de creencia previa. <\/p>\n<h3><a name=\"00114\">Pruebas estad&iacute;sticas<\/a><\/h3>\n<p>R nos pemite efectuar pruebas estad&iacute;sticas, las cuales parten de 2 hipotesis: <\/p>\n<ul>\n<li>Hipotesis nula (H0): por ejemplo, el tabaco no incrementa el riesgo de cancer.<\/li>\n<li>Hipotesis alternativa (H1): por ejemplo, puede ser sim&eacute;trica como &quot;el tabaco incrementa\/decrementa el riesgo de cancer&quot; o asim&eacute;trica &quot;el tabaco incrementa el riesgo de cancer&quot;. En la segunda ya estamos eliminando una posibilidad y por tanto debemos hacerlo con cuidado. <\/li>\n<\/ul>\n<p>Una prueba nunca nos dir&aacute; si una hipotesis es cierta, sino que refutaran la hipotesis o fallaran en la refutaci&oacute;n (&quot;K. Popper: we never prove that something is true, we merely continuously try to prove it wrong and fail to do so&quot;). <\/p>\n<p>Otra clasificaci&oacute;n posible de las hipotesis en funci&oacute;n de los par&aacute;metros que conocemos:<\/p>\n<ul>\n<li>Hipotesis simple: por ejemplo, queremos testear si una muestra procede de una poblaci&oacute;n de la cual conocemos su distribuci&oacute;n y su media y varianza.<\/li>\n<li>Hipotesis compuesta: si H1 es cierto, conocemos la distribuci&oacute;n pero no la varianza. <\/li>\n<\/ul>\n<p>En las pruebas estad&iacute;sticas podemos cometer dos tipos de errores:<\/p>\n<ul>\n<li>Error del tipo I: Refutar incorrectamente la hipotesis nula<\/li>\n<li>Error del tipo II: No refutar la hipotesis nula, cuando se deberia refutar. <\/li>\n<\/ul>\n<p>Cuando realicemos las pruebas, tambi&eacute;n obtendremos el intervalo de confianza en el cual podremos asegurar que se encuentra un par&aacute;metro (p.ej. media, varianza, etc.) de la poblaci&oacute;n a la que pertenece la muestra que estamos analizando. El intervalo tiene adem&aacute;s asociado un porcentaje de probabilidades de que sea correcto, habitualmente se trabaja con el 95%.<\/p>\n<p>Finalmente, las pruebas siempre generar&aacute;n un p-Value, que corresponde con la probabilidad de cometer el error de refutar incorrectamente la hip&oacute;tesis nula (tipo I). Lo que significa que si p-value es muy peque&ntilde;o, refutaremos la hip&oacute;tesis nula.<\/p>\n<p>Antes de realizar ninguna prueba se establece el limite (alpha) a partir del cual p-value refutar&aacute; la hip&oacute;tesis nula. Es habitual utilizar el limite 0.05, es decir, si es inferior a 0.05 entonces refutaremos la hip&oacute;tesis.<\/p>\n<p>Existen multitud de pruebas, entre las que podemos encontrar:<\/p>\n<table WIDTH=100% BORDER=1 BORDERCOLOR=\"#000000\" CELLPADDING=4 CELLSPACING=0>\n<col WIDTH=85*>\n\t<\/col>\n<col WIDTH=85*>\n\t<\/col>\n<col WIDTH=85*>\n<tr VALIGN=TOP>\n<td WIDTH=33% BGCOLOR=\"#333366\">\n\t\t\t<font COLOR=\"#ffffff\"><b>Objetivo<\/b><\/font>\n\t\t<\/td>\n<td WIDTH=33% BGCOLOR=\"#333366\">\n\t\t\t<font COLOR=\"#ffffff\"><b>Test param&eacute;trico<\/b><\/font>\n\t\t<\/td>\n<td WIDTH=33% BGCOLOR=\"#333366\">\n\t\t\t<font COLOR=\"#ffffff\"><b>Test no param&eacute;trico<\/b><\/font>\n\t\t<\/td>\n<\/tr>\n<tr VALIGN=TOP>\n<td WIDTH=33%>\n\t\t\t<b>Comparar 2 medias<\/b>\n\t\t<\/td>\n<td WIDTH=33%>\n\t\t\tStudent&#8217;s T test\n\t\t<\/td>\n<td WIDTH=33%>\n\t\t\tWilcoxon&#8217;s U test\n\t\t<\/td>\n<\/tr>\n<tr VALIGN=TOP>\n<td WIDTH=33%>\n\t\t\t<b>Comparar m&aacute;s de 2 medias<\/b>\n\t\t<\/td>\n<td WIDTH=33%>\n\t\t\tANOVA\n\t\t<\/td>\n<td WIDTH=33%>\n\t\t\tKruskal-Wallis test\n\t\t<\/td>\n<\/tr>\n<tr VALIGN=TOP>\n<td WIDTH=33%>\n\t\t\t<b>Comparar 2 varianzas<\/b>\n\t\t<\/td>\n<td WIDTH=33%>\n\t\t\tFisher&#8217;s F Test\n\t\t<\/td>\n<td WIDTH=33%>\n\t\t\tAnsari-Bradley o Mood test\n\t\t<\/td>\n<\/tr>\n<tr VALIGN=TOP>\n<td WIDTH=33%>\n\t\t\t<b>Comparar m&aacute;s de 2 varianzas<\/b>\n\t\t<\/td>\n<td WIDTH=33%>\n\t\t\tBarlett test\n\t\t<\/td>\n<td WIDTH=33%>\n\t\t\tFligner test\n\t\t<\/td>\n<\/tr>\n<\/col>\n<\/table>\n<p>Otros conceptos importantes:<\/p>\n<ul>\n<li>Robustez: un test es robusto si es valido cuando las suposiciones dejan de cumplirse<\/li>\n<li>Resistencia: un valor (media, mediana, varianza&#8230;) es resistente si no depende de valores extremos (outliers). Por ejemplo, la media no es resistente y la mediana si. Por ejemplo, como estimadores robustos tenemos:\n<ul>\n<li>Ubicaci&oacute;n (media): trimmed mean, median <\/li>\n<li>Dispersi&oacute;n (desviaci&oacute;n estandar): IQR, MAD, Sn, L-moments, MCD <\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h4><a name=\"00217\">Prueba de distribuci&oacute;n normal<\/a><\/h4>\n<p>El test Shapiro-Wilk nos permite probar si un conjunto de datos tiene una distribuci&oacute;n normal (gausiana). Para ello definimos que la hip&oacute;tesis nula es que la distribuci&oacute;n es la normal y solo la refutaremos si el p-value es superior a 0.05: <\/p>\n<pre>\r\nshapiro.test(rnorm(100))$p.value\r\n\r\n[1] 0.4749011 # &gt; 0.05 no podemos refutar \r\n\r\nshapiro.test(runif(100))$p.value\r\n\r\n[1] 0.005700384 # &lt; 0.05 refutamos, no es normal \r\n<\/pre>\n<h4><a name=\"00218\">Prueba de proporci&oacute;n <\/a><\/h4>\n<p>Supongamos que hacemos un muestreo y seleccionamos 100 expedientes hipotecarios de una entidad y de estos, 42 no tienen adjunta documentaci&oacute;n sobre el an&aacute;lisis del riesgo efectuado. Esto lo podr&iacute;amos traducir en 3 afirmaciones diferentes (de menor a mayor exactitud): <\/p>\n<ul>\n<li>El 42% de los expedientes est&aacute;n incompletos<\/li>\n<li>El 42% de los expedientes est&aacute;n incompletos con un margen de error del 9%<\/li>\n<li>El 42% de los expedientes est&aacute;n incompletos con un margen de error del 9% y una confianza del 95% <\/li>\n<\/ul>\n<p>La &uacute;ltima afirmaci&oacute;n que es la m&aacute;s correcta estad&iacute;sticamente, para llegar a ella podemos utilizar el test de proporci&oacute;n de R: <\/p>\n<pre>\r\n&gt; prop.test(42, 100, conf.level=0.95) \r\n\r\n\t1-sample proportions test with continuity correction \r\n\r\ndata:  42 out of 100, null probability 0.5 \r\nX-squared = 2.25, df = 1, p-value = 0.1336 \r\nalternative hypothesis: true p is not equal to 0.5 \r\n95 percent confidence interval: \r\n 0.3233236 0.5228954 \r\nsample estimates: \r\n   p \r\n0.42 \r\n<\/pre>\n<p>Veamos otro ejemplo: En el mes de Diciembre la entidad dispone de 20 pr&eacute;stamos, y mediante una auditor&iacute;a se detecta que 5 pr&eacute;stamos presentan diferencias entre lo que deber&iacute;a haberse liquidado por inter&eacute;s y lo liquidado realmente. Suponemos que las diferencias se encuentran distribuidas bajo la *normal* con la media en el 0, es decir la mayor&iacute;a de liquidaciones de intereses no presentan diferencias y en caso contrario, &eacute;stas est&aacute;n m&aacute;s pr&oacute;ximas al 0 que a diferencias m&aacute;s distantes (p.ej. es m&aacute;s probable que el sistema se equivoque de unos pocos euros que de miles de euros). <\/p>\n<p>Informaci&oacute;n de los 5 pr&eacute;stamos: <\/p>\n<pre>\r\n&gt; # Capital pendiente de los pr\u00e9stamos \r\n&gt; capital = c(2000,2700,2100,2600,2900,3000,3300,2100,2700,2100,2100,2400,2500,2600,2400,2200,1900,2700,1800,2600) \r\n\r\n&gt; # TAE (se debe dividir entre 12 para obtener el nominal mensual) \r\n&gt; interes = c(0.042,0.037,0.038,0.040,0.049,0.044,0.028,0.042,0.045,0.036,0.031,0.042,0.038,0.041,0.039,0.047,0.045,0.036,0.032,0.040) \r\n\r\n&gt; liquidacion.sistema = c(7.00,8.10,6.65,8.67,11.24,11.00,7.39,7.35,10.12,6.10,5.09,8.40,7.92,8.88,7.80,8.62,7.12,8.10,4.80,8.67) \r\n\r\n&gt; liquidacion.teorica = round(capital * (interes\/12), 2) \r\n&gt; diferencias = liquidacion.teorica - liquidacion.sistema \r\n&gt; diferencias.porcentuales  = round(diferencias \/ liquidacion.teorica, 4) \r\n&gt; prestamos = data.frame(capital, interes, liquidacion.sistema, liquidacion.teorica, diferencias, diferencias.porcentuales) \r\n&gt; prestamos \r\n\t   capital interes liquidacion.sistema liquidacion.teorica diferencias \r\n\t1     2000   0.042                7.00                7.00        0.00 \r\n\t2     2700   0.037                8.10                8.32        0.22 \r\n\t3     2100   0.038                6.65                6.65        0.00 \r\n\t4     2600   0.040                8.67                8.67        0.00 \r\n\t5     2900   0.049               11.24               11.84        0.60 \r\n\t6     3000   0.044               11.00               11.00        0.00 \r\n\t7     3300   0.028                7.39                7.70        0.31 \r\n\t8     2100   0.042                7.35                7.35        0.00 \r\n\t9     2700   0.045               10.12               10.12        0.00 \r\n\t10    2100   0.036                6.10                6.30        0.20 \r\n\t11    2100   0.031                5.09                5.42        0.33 \r\n\t12    2400   0.042                8.40                8.40        0.00 \r\n\t13    2500   0.038                7.92                7.92        0.00 \r\n\t14    2600   0.041                8.88                8.88        0.00 \r\n\t15    2400   0.039                7.80                7.80        0.00 \r\n\t16    2200   0.047                8.62                8.62        0.00 \r\n\t17    1900   0.045                7.12                7.12        0.00 \r\n\t18    2700   0.036                8.10                8.10        0.00 \r\n\t19    1800   0.032                4.80                4.80        0.00 \r\n\t20    2600   0.040                8.67                8.67        0.00 \r\n<\/pre>\n<p>Con esta informaci&oacute;n podemos afirmar que para el mes de Diciembre: <\/p>\n<ul>\n<li>El 25% de los pr&eacute;stamos (5 de 20) presentan diferencias en la liquidaci&oacute;n de los pr&eacute;stamos.<\/li>\n<li>La liquidaci&oacute;n de intereses presenta una diferencia media de 0.08 &euro; (1,05%) para la totalidad de los pr&eacute;stamos. <\/li>\n<\/ul>\n<pre>\r\n&gt; mean(diferencias) \r\n[1] 0.083 \r\n&gt; mean(diferencias.porcentuales) \r\n[1] 0.0105\r\n<\/pre>\n<p>Sin embargo, las auditorias son anuales y abarcan 12 meses, por tanto lo que hemos hecho nosotros ha sido coger una muestra de la totalidad de liquidaciones que se efect&uacute;an durante todo un a&ntilde;o. As&iacute; que si queremos extrapolar estas conclusiones podr&iacute;amos decir:<\/p>\n<ul>\n<li>El 25% de las liquidaciones de pr&eacute;stamos (supongamos que durante todo el\ta&ntilde;o hemos tenido los mismos 20) presentan diferencias.<\/li>\n<li>Estas diferencias presentan una media de 0.08 &euro; (1,05%), por tanto la diferencia anual asciende a 19,20&euro; (0.08&euro; x 20 pr&eacute;stamos x 12 meses).<\/li>\n<\/ul>\n<p>No obstante, estas afirmaciones no son exactas en t&eacute;rminos estad&iacute;sticos. Lo correcto seria en primer lugar definir un porcentaje de confianza de nuestra extrapolaci&oacute;n (p.ej. 95% de probabilidades de que la extrapolaci&oacute;n sea cierta) y a partir de ah&iacute; identificar el margen de error resultante. En el caso del n&uacute;mero de liquidaciones, tenemos 5 liquidaciones que liquidan incorrectamente sobre 20 que hemos validado: <\/p>\n<pre>\r\n&gt; prop.test(5, 20, conf.level=0.95) \r\n\r\n\t1-sample proportions test with continuity correction \r\n\r\ndata:  5 out of 20, null probability 0.5 \r\nX-squared = 4.05, df = 1, p-value = 0.04417 \r\nalternative hypothesis: true p is not equal to 0.5 \r\n95 percent confidence interval: \r\n 0.0959326 0.4941155 \r\nsample estimates: \r\n   p \r\n0.25 \r\n<\/pre>\n<p>En el test de proporci&oacute;n hemos indicado que 5 de una muestra de 20 cumplen una hip&oacute;tesis (liquidaciones incorrectas) y queremos saber el intervalo\/margen de error para una confianza del 95%, es decir, un 95% de probabilidades de que nuestra extrapolaci&oacute;n al resto de la poblaci&oacute;n sea cierta. La funci&oacute;n ha dado como resultado que entre el 9,59% y el 49,41% de los expedientes (margen de error del 39,81%) ser&aacute;n incompletos con una confianza del 95%. <\/p>\n<p>Por tanto, podemos afirmar que el 25% de las liquidaciones son incorrectas con un margen de error del 39,81% y una confianza del 95%. Como se puede observar, el margen de error es considerable y podr&iacute;amos disminuirlo bajando el grado de confianza (p.ej. 90%) o ampliando la muestra. Por ejemplo, si hubi&eacute;semos validado 2000 liquidaciones y hubi&eacute;semos identificado 500 err&oacute;neas: <\/p>\n<pre>\r\n&gt; prop.test(500, 2000, conf.level=0.95) \r\n\r\n\t1-sample proportions test with continuity correction \r\n\r\ndata:  500 out of 2000, null probability 0.5 \r\nX-squared = 499.0005, df = 1, p-value &lt; 2.2e-16 \r\nalternative hypothesis: true p is not equal to 0.5 \r\n95 percent confidence interval: \r\n 0.2312709 0.2697002 \r\nsample estimates: \r\n   p \r\n0.25\r\n<\/pre>\n<p>El porcentaje sigue siendo del 25% pero el margen de error ha disminuido considerablemente hasta llegar a un 3,84% (entre 23,12% y 26,97%). Como es obvio, entre m&aacute;s grande sea la muestra, m&aacute;s fiable ser&aacute;n los resultados y las posibles extrapolaciones. <\/p>\n<p>En cuanto a la segunda extrapolaci&oacute;n sobre las diferencias medias, tendremos que realizar la prueba que se describe en la siguiente secci&oacute;n<\/p>\n<h4><a name=\"00219\">Pruebas sobre la media<\/a><\/h4>\n<p>Las pruebas sobre la media nos pueden resultar de utilidad para, entre otros, los siguientes objetivos:<\/p>\n<ul>\n<li>Tenemos unos resultados sobre una muestra referentes a la media (p.ej. diferencias\/errores en el c&aacute;lculo de las n&oacute;minas del mes de Junio) y queremos realizar una extrapolaci&oacute;n a toda la poblaci&oacute;n (p.ej. las n&oacute;minas de todo el a&ntilde;o).<\/li>\n<li>Si tenemos 2 muestras diferentes y queremos saber si ambas pertenecen a la misma poblaci&oacute;n, podemos utilizar las pruebas para validar si ambas extrapolan a la misma media.<\/li>\n<\/ul>\n<h5>T-Test: Datos con distribuci&oacute;n normal<\/h5>\n<h6>Una variable<\/h6>\n<p>En el ejemplo de la secci&oacute;n de &quot;Pruebas de proporci&oacute;n&quot; afirm&aacute;bamos que <i>&quot;las diferencias presentan una media de 0.08 &euro; (1,05%), por tanto la diferencia anual asciende a 19,20&euro; (0.08&euro; x 20 pr&eacute;stamos x 12 meses)&quot;<\/i>. Esta extrapolaci&oacute;n no es exacta y  mediante el uso del T-Test y a partir de las diferencias encontradas vamos a extraer el margen de error de la media para una confianza del 95%: <\/p>\n<pre>\r\n&gt; t.test(diferencias, conf.level = 0.95) \r\n\r\n\tOne Sample t-test \r\n\r\ndata:  diferencias \r\nt = 2.2532, df = 19, p-value = 0.03625 \r\nalternative hypothesis: true mean is not equal to 0 \r\n95 percent confidence interval: \r\n 0.005901257 0.160098743 \r\nsample estimates: \r\nmean of x \r\n\t0.083\r\n<\/pre>\n<p>Podemos afirmar que la diferencia media sera de 0.08 &euro; con un margen de error del 15,41% (0,01&euro; al 0,16&euro;) y una confianza del 95%. Es decir, en el peor de los casos tendremos una diferencia anual de 38,4&euro; (0.16&euro; x 20 liquidaciones mensuales x 12 meses) y en el peor 2,4 &euro;. De nuevo, para reducir el margen de error podemos decrementar el margen de confianza o incrementar la muestra. <\/p>\n<p>Veamos otro ejemplo, generamos 10 valores de distribuci&oacute;n normal pero con una media aleatoria desconocida: <\/p>\n<pre>\r\nn = 10 \r\nm = rnorm(1) \r\nx = m + rnorm(n) # Desplazamos la media \r\n<\/pre>\n<p>Partiendo de que conocemos que la poblaci&oacute;n tiene una distribuci&oacute;n normal y desconocemos su media, vamos a testear la muestra contra las siguientes hip&oacute;tesis: <\/p>\n<ul>\n<li>Hip&oacute;tesis nula (H0): La media es 0<\/li>\n<li>Hip&oacute;tesis altenrativa (H1): La media no es 0 <\/li>\n<\/ul>\n<pre>\r\n&gt; t.test(x) \r\n\r\n\t\tOne Sample t-test \r\n\r\ndata:  x \r\nt = -1.4372, df = 9, p-value = 0.1845 \r\nalternative hypothesis: true mean is not equal to 0 \r\n95 percent confidence interval: \r\n -1.2043513  0.2685511 \r\nsample estimates: \r\n mean of x \r\n-0.4679001 \r\n<\/pre>\n<p>La probabilidad de falsar H0 incorrectamente es del 18,45%, como no es inferior a 0.05 no podemos refutar H0. <\/p>\n<p>Probemos con una muestra m&aacute;s amplia: <\/p>\n<pre>\r\nn = 1000 \r\n# m = rnorm(1) # Mantenemos la misma desviaci\u00f3n \r\nx = m + rnorm(n) # Desplazamos la media \r\n&gt; t.test(x) \r\n\r\n\t\tOne Sample t-test \r\n\r\ndata:  x \r\nt = -19.7442, df = 999, p-value &lt; 2.2e-16 \r\nalternative hypothesis: true mean is not equal to 0 \r\n95 percent confidence interval: \r\n -0.6541373 -0.5358651 \r\nsample estimates: \r\n mean of x \r\n-0.5950012\r\n<\/pre>\n<p>Ahora tenemos un p-value muy inferior a 0.05, por tanto podemos refutar H0. Estos ejemplos nos sirven para demostrar la importancia del tama&ntilde;o de las muestras dado que nos pueden hacer extraer conclusiones incorrectas (en nuestra ejecuci&oacute;n m = -0.5964069 y por tanto H0 es realmente falso). <\/p>\n<p>Veamos otro ejemplo: Un fabricante de coches dice que un determinado modelo tiene un consumo de 25 litros por cada 100 KM, se pregunta a un grupo de 10 usuarios y se obtiene una media de 22 litros con una desviaci&oacute;n est&aacute;ndar de 1.5. &iquest;Soportan estos datos la afirmaci&oacute;n del fabricante? <\/p>\n<p>En este caso, la hip&oacute;tesis nula seria que la media es igual a 25 y la alternativa que no es igual: <\/p>\n<pre>\r\n&gt; consumo = rnorm(100, mean=22, sd=1.5) \r\n&gt; t.test(consumo, conf.level=.95, mu=25) \r\n\r\n\tOne Sample t-test \r\n\r\ndata:  consumo \r\nt = -17.6998, df = 99, p-value &lt; 2.2e-16 \r\nalternative hypothesis: true mean is not equal to 25 \r\n95 percent confidence interval: \r\n 21.97223 22.58265 \r\nsample estimates: \r\nmean of x \r\n 22.27744 \r\n<\/pre>\n<p>El p-value es inferior a 0.05 y por tanto tendriamos que refutar la hipotesis nula. Es decir, los datos no soportan la afirmaci&oacute;n del fabricante de que el coche consume 25 litros por cada 100 KM.<\/p>\n<h6>Dos variables<\/h6>\n<p>Hasta ahora hemos evaluado una &uacute;nica muestra, veamos un ejemplo con un par de conjuntos de datos. Imaginemos que hemos realizado un experimento sobre el tiempo de recuperaci&oacute;n de un paciente a partir de un nuevo medicamento y para ello hemos constituido 2 grupos:<\/p>\n<pre>\r\n&gt; x = c(15, 10, 13, 7, 9, 8, 21, 9, 14, 8) \r\n&gt; y = c(15, 14, 12, 8, 14, 7, 16, 10, 15, 12) \r\n<\/pre>\n<p>Al grupo X se le ha suministrado el f&aacute;rmaco, al grupo Y &uacute;nicamente un placebo. Los n&uacute;meros corresponden a los d&iacute;as de recuperaci&oacute;n despu&eacute;s de suministrar el f&aacute;rmaco\/placebo.<\/p>\n<p>Nuestra hip&oacute;tesis nula ser&aacute; que ambos grupos tienen la misma media y varianza, mientras que la hip&oacute;tesis alternativa es que el grupo de X (el del f&aacute;rmaco) tiene una media inferior (descartamos que el f&aacute;rmaco perjudique y provoque una media superior):<\/p>\n<pre>\r\n&gt; t.test(x,y,alt=\"less\",var.equal=TRUE) \r\n\r\n\tTwo Sample t-test \r\n\r\ndata:  x and y \r\nt = -0.5331, df = 18, p-value = 0.3002 \r\nalternative hypothesis: true difference in means is less than 0 \r\n95 percent confidence interval: \r\n     -Inf 2.027436 \r\nsample estimates: \r\nmean of x mean of y \r\n     11.4      12.3 \r\n<\/pre>\n<p>P-value es superior a 0.05 y por tanto, no podemos refutar que tienen la misma media (el f&aacute;rmaco no presenta ninguna mejora).<\/p>\n<p>En caso de que tengamos 2 conjuntos de datos relacionados, por ejemplo 2 profesores que han evaluado los mismos 10 ex&aacute;menes, utilizaremos el argumento &ldquo;paired&rdquo;:<\/p>\n<pre>\r\n&gt; x = c(3, 0, 5, 2, 5, 5, 5, 4, 4, 5) \r\n&gt; y = c(2, 1, 4, 1, 4, 3, 3, 2, 3, 5) \r\n&gt; t.test(x,y,paired=TRUE) \r\n     Paired t-test \r\ndata: x and y \r\nt = 3.3541, df = 9, p-value = 0.008468 \r\nalternative hypothesis: true difference in means is not equal to 0 \r\n95 percent confidence interval: \r\n 0.3255550 1.6744450 \r\nsample estimates: \r\nmean of the differences\r\n<\/pre>\n<p>En este caso el p-value es inferior a 0.05 y por tanto podemos refutar la hipotesis nula: las medias son iguales y los profesores han evaluado igual.<\/p>\n<h5>Simulaciones sobre el T-Test<\/h5>\n<p>Hagamos una simulaci&oacute;n de N casos para observar cuantos casos no refutar&iacute;amos H0 (media en 0) para muestras que tienen la media diferente de 0 y son de distribuci&oacute;n normal: <\/p>\n<pre>\r\nN = 1000 \r\nn = 3 \r\nv = c() \r\nfor (i in 1:N) { \r\n  x = rnorm(n, mean=-25) # La media de la distribuci\u00f3n esta en -25 \r\n  v = append(v, t.test(x)$p.value) \r\n} \r\nsum(v&gt;.05)\/N # Porcentaje de casos donde no refutariamos H0 (media en 0) \r\n[1] 0 # Nunca\r\n<\/pre>\n<p>No refutariamos nunca la hip&oacute;tesis. En cambio, si estamos tratando con una poblaci&oacute;n de distribuci&oacute;n diferente a la normal y con media diferente de 0: <\/p>\n<pre>\r\nN = 1000 \r\nn = 3 \r\nv = vector() \r\nfor (i in 1:N) { \r\n  x = runif(n, min=-49, max=1) # La media de la distribuci\u00f3n esta en -25 \r\n  v = append(v, t.test(x)$p.value) \r\n} \r\nsum(v&gt;.05)\/N # Porcentaje de casos donde no refutariamos H0 (media en 0) \r\n[1] 0.721 # Alto\r\n<\/pre>\n<p>El 72,10% de los casos no refutar&iacute;a la hipotesis y por tanto seria err&oacute;nea la deducci&oacute;n (la media realmente es diferente de 0). Como consecuencia, queda demostrado que el T-Test no es tan efectivo cuando trabajamos con datos de distribuci&oacute;n diferente a la normal y en consecuencia es mejor utilizar otras alternativas.<\/p>\n<h5>Wilcoxon Test: Datos con distribuci&oacute;n diferente a la normal<\/h5>\n<p>Si pensamos que la distribuci&oacute;n no es normal (ver secciones de identificaci&oacute;n de distribuciones y pruebas de normales) es mejor utilizar pruebas no param&eacute;tricas como Wilcoxon&#8217;s U test. Por ejemplo, un estudio sobre la duraci&oacute;n de las llamadas telef&oacute;nica arroja los siguientes minutos: <\/p>\n<pre>\r\n&gt; x = c(12.8,3.5,2.9,9.4,8.7,.7,.2,2.8,1.9,2.8,3.1,15.8) \r\n<\/pre>\n<p>Si visualizamos los datos (comprobar tambi&eacute;n utilizando QQ plot o con el test Shapiro-Wilk): <\/p>\n<pre>\r\n&gt; plot.hist.and.box(x) \r\n&gt; stem(x) \r\n\r\n  The decimal point is 1 digit(s) to the right of the | \r\n\r\n  0 | 01233334 \r\n  0 | 99 \r\n  1 | 3 \r\n  1 | 6 \r\n<\/pre>\n<p>Se observa una distribuci&oacute;n con una cola larga lejos de ser una normal, por tanto el T-Test queda descartado y en su lugar utilizaremos el Wilcox test. <\/p>\n<p>Como hipotesis nula a testear diremos que la <b>mediana<\/b> es 5, mientras que la alternativa es que la mediana es superior (descartamos que sea inferior =&gt; hip&oacute;tesis compleja): <\/p>\n<pre>\r\n&gt; wilcox.test(x,mu=5,alt=\"greater\") \r\n\r\n\tWilcoxon signed rank test with continuity correction \r\n\r\ndata:  x \r\nV = 39, p-value = 0.5156 \r\nalternative hypothesis: true location is greater than 5\r\n<\/pre>\n<p>El p-value es 0.5156 &gt; 0.05 y por tanto no podemos refutar la hip&oacute;tesis nula. <\/p>\n<h5>ANOVA \/ Kruskal<\/h5>\n<p>Los tests T y Wilcoxon nos permite analizar una o dos muestras de datos, pero si queremos evaluar m&aacute;s de 2 conjuntos necesitamos realizar un an&aacute;lisis de varianza (ANOVA). Veamos un ejemplo: Hemos realizado un examen a 24 personas y las correcciones se han repartido a 3 profesores. Las notas van de 1 a 5, siendo esta &uacute;ltima la mejor:<\/p>\n<pre>\r\nx = c(4,3,4,5,2,3,4,5) \r\ny = c(4,4,5,5,4,5,4,4) \r\nz = c(3,4,2,4,5,5,4,4) \r\nscores = data.frame(x,y,z) \r\nboxplot(scores)\r\n<\/pre>\n<p>Queremos comprobar que todos los profesores han evaluado bajo los mismos criterios y que no se han producido grandes diferencias. Para ello realizaremos un an&aacute;lisis de las varianzas. Para esto, necesitamos que los datos est&eacute;n en formato pila:<\/p>\n<pre>\r\n&gt; scores.s = stack(scores) \r\n&gt; scores .s\r\n   values ind \r\n1       4   x \r\n2       3   x \r\n3       4   x \r\n...\r\n9       4   y \r\n10      4   y \r\n...\r\n17      3   z \r\n18      4   z \r\n...\r\n<\/pre>\n<p>Ejecutamos el test Oneway (suponemos que la distribuci&oacute;n es normal) y comprobamos si todos los profesores tienen la misma media (hip&oacute;tesis nula), asumiendo que la varianza ser&aacute; equivalente para todos:<\/p>\n<pre>\r\n&gt; attach(scores.s) \r\n&gt; oneway.test(values ~ ind, var.equal=T) \r\n\r\n\tOne-way analysis of means \r\n\r\ndata:  values and ind \r\nF = 1.1308, num df = 2, denom df = 21, p-value = 0.3417\r\n<\/pre>\n<p>El p-value es de 0.3417 &gt; 0.05 y por tanto no podemos refutar la hipotesis.<\/p>\n<p>En caso de que la distribuci&oacute;n no sea normal, utilizar&iacute;amos el Test Kruskal:<\/p>\n<pre>\r\n&gt; kruskal.test(values ~ ind) \r\n\r\n\tKruskal-Wallis rank sum test \r\n\r\ndata:  values by ind \r\nKruskal-Wallis chi-squared = 1.9387, df = 2, p-value = 0.3793\r\n<\/pre>\n<h4><a name=\"00220\">Prueba sobre la varianza<\/a><\/h4>\n<p>Comparar varianzas de 2 conjuntos de datos:<\/p>\n<ul>\n<li>Param&eacute;trico (distribuci&oacute;n normal)<\/li>\n<\/ul>\n<pre>\r\n?fisher.test\r\n<\/pre>\n<ul>\n<li>No param&eacute;trico<\/li>\n<\/ul>\n<pre>\r\n?mood.test\r\n?ansari.test\r\n<\/pre>\n<p>Comparar varianzas de m&aacute;s de 2 conjuntos de datos:<\/p>\n<ul>\n<li VALUE=1>Param&eacute;trico (distribuci&oacute;n normal)<\/li>\n<\/ul>\n<pre>\r\n?bartlett.test\r\n<\/pre>\n<ul>\n<li VALUE=1>No param&eacute;trico<\/li>\n<\/ul>\n<pre>\r\n?fligner.test\r\n<\/pre>\n<h4><a name=\"00221\">Prueba de independencia<\/a><\/h4>\n<p>Nos puede interesar validar si 2 muestras\/variables son independientes entre si o si sus fluctuaciones se encuentran relacionadas, con este objetivo podemos hacer uso de las pruebas de independencia.<\/p>\n<h5>Coeficiente de Pearson: Datos con distribuci&oacute;n normal<\/h5>\n<p>El coeficiente de correlaci&oacute;n Pearson asume que la distribuci&oacute;n de probabilidad de los datos es la normal (estad&iacute;stica param&eacute;trica), si esta condici&oacute;n se cumple entonces las estimaciones son m&aacute;s precisas que otros m&eacute;todos (ver siguiente secci&oacute;n) y viceversa.<\/p>\n<p>La correlaci&oacute;n siempre devuelve un valor entre -1 y 1, donde 0 significa que no hay ning&uacute;n tipo de correlaci&oacute;n, -1 que la correlaci&oacute;n es absoluta pero en direcci&oacute;n opuesta y 1 la correlaci&oacute;n es completa. <\/p>\n<p>El c&aacute;lculo del coeficiente de correlaci&oacute;n de Pearson se lleva a cabo de la siguiente forma: <\/p>\n<pre>\r\n&gt; x = rnorm(1000, 50, 10)\t# Partimos de datos aleatorios normales \r\n&gt; y = rexp(1000, 50)\t\t# Y datos aleatorios exponenciales \r\n&gt; cor(x, y) \r\n[1] -0.007434471 \r\n&gt; cor.test(x, y) \r\n\r\n\tPearson's product-moment correlation \r\n\r\ndata:  x and y \r\nt = -0.2349, df = 998, p-value = 0.8144 \r\nalternative hypothesis: true correlation is not equal to 0 \r\n95 percent confidence interval: \r\n -0.06939557  0.05458377 \r\nsample estimates: \r\n\t cor \r\n-0.007434471\r\n<\/pre>\n<p>En el ejemplo anterior, el coeficiente es de -0.007 y las probabilidades de que las variables sean independiente (hipotesis nula) son del 81,44% (p-value). <\/p>\n<h5>M&eacute;todos no param&eacute;tricos: Datos con distribuci&oacute;n diferente a la normal<\/h5>\n<p>Cuando no estamos seguros de la distribuci&oacute;n de probabilidad de los datos o se trata de una diferente a la normal, la mejor opci&oacute;n es utilizar m&eacute;todos no param&eacute;tricos como el coeficiente de correlaci&oacute;n de Spearman (rho), Kendall tau o chi cuadrado. Por ejemplo, <b>coeficiente Spearman<\/b>: <\/p>\n<pre>\r\n&gt; cor(x, y, method=\"spearman\") \r\n[1] 0.003597064 \r\n&gt; cor.test(x, y, method=\"spearman\") \r\n\r\n\tSpearman's rank correlation rho \r\n\r\ndata:  x and y \r\nS = 166066990, p-value = 0.9095 \r\nalternative hypothesis: true rho is not equal to 0 \r\nsample estimates: \r\n\trho \r\n0.003597064\r\n<\/pre>\n<p>Y <b>coeficiente Kendall<\/b>:<\/p>\n<pre>\r\n&gt; cor(x, y, method=\"kendall\") \r\n[1] 0.002506507 \r\n&gt; cor.test(x, y, method=\"kendall\") \r\n\r\n\tKendall's rank correlation tau \r\n\r\ndata:  x and y \r\nz = 0.1187, p-value = 0.9055 \r\nalternative hypothesis: true tau is not equal to 0 \r\nsample estimates: \r\n\ttau \r\n0.002506507\r\n<\/pre>\n<p>Al igual que con el coeficiente de Pearson, cabe recordar que la correlaci&oacute;n siempre devuelve un valor entre -1 y 1, donde 0 significa que no hay ning&uacute;n tipo de correlaci&oacute;n, -1 que la correlaci&oacute;n es absoluta pero en direcci&oacute;n opuesta y 1 la correlaci&oacute;n es completa. <\/p>\n<p>En los ejemplos anteriores los coeficientes son de 0.004 (rho) y 0.003 (tau) respectivamente, y las probabilidades de que las variables sean independiente (coeficiente = 0) son del 90,95% y 90,55% (p-value). <\/p>\n<p>Veamos un ejemplo r&aacute;pido donde las variables no son independientes: <\/p>\n<pre>\r\n&gt; cor.test(c(1, 2, 3, 4, 5), c(2, 3, 4, 5, 6), method=\"spearman\") \r\n\r\n\tSpearman's rank correlation rho \r\n\r\ndata:  c(1, 2, 3, 4, 5) and c(2, 3, 4, 5, 6) \r\nS = 0, p-value = 0.01667 \r\nalternative hypothesis: true rho is not equal to 0 \r\nsample estimates: \r\nrho \r\n  1\r\n<\/pre>\n<p>Dado que los elementos del segundo vector son iguales que los del primero pero sumando 1, no existe independencia, por tanto rho es 1 y la probabilidad de que sean independientes &iacute;nfima: 1,67%. <\/p>\n<p>Hagamos ahora el mismo test de independencia pero utilizando el m&eacute;todo de <b>chi cuadrado<\/b>: <\/p>\n<pre>\r\n&gt; chisq.test(data.frame(x, y)) \r\n\r\n\tPearson's Chi-squared test \r\n\r\ndata:  data.frame(x, y) \r\nX-squared = 20.5816, df = 999, p-value = 1\r\n<\/pre>\n<p>El test nos muestra una probabilidad del 100% (p-value) de que la hipotesis nula sea cierta: las variables son independientes. <\/p>\n<h3><a name=\"00115\">An&aacute;lisis de regresiones<\/a><\/h3>\n<h4><a name=\"00222\">Regresiones lineales simples<\/a><\/h4>\n<p>Si entendemos que X es un valor que controlamos (p.ej. tabletas de chocolate que comemos) e Y un valor que medimos (p.ej. grado de felicidad), podemos utilizar una regresi&oacute;n lineal para predecir las Y para un valor desconocido de X (p.ej. cual sera mi grado de felicidad si como 20 tabletas de chocolate).<\/p>\n<p>En primer lugar, a partir de un conjunto de X e Y conocidos inferimos los coeficientes de nuestro modelo: Y = B1*x + B0<\/p>\n<pre>\r\n&gt; x = 1:100 \r\n&gt; y = rexp(100)\r\n&gt; lm.result = lm(y ~ x) # response ~ predictor \r\n&gt; lm.result\r\n\r\nCall: \r\nlm(formula = y ~ x) \r\n\r\nCoefficients: \r\n(Intercept)            x  \r\n   1.130804    -0.003217  \r\n<\/pre>\n<p>El modelo generado corresponde con la siguiente f&oacute;rmula:\ty = -0.003217 * x + 1.130803<\/p>\n<pre>\r\n&gt; coef(lm.result) \r\n(Intercept) x.chocolate \r\n  0.4395754   0.1466509 \r\n<\/pre>\n<p>Para  cada Y conocido (los que existen en el conjunto de datos inicial), podr&iacute;amos coger sus correspondientes X y utilizar la formula deducida y obtener la Y&#8217; que nos dar&iacute;a. Si restamos las Y reales con la Y&#8217; calculadas tenemos los residuales:<\/p>\n<pre>\r\n&gt; lm.res = resid(lm.result) \r\n&gt; summary(lm.res) \r\n      Min.    1st Qu.     Median       Mean    3rd Qu.       Max. \r\n-5.449e-01 -2.725e-01  4.904e-02  3.342e-18  2.616e-01  4.947e-01\r\n<\/pre>\n<p>De los datos anteriores se desprende que la diferencia media es muy peque&ntilde;a.<\/p>\n<p>Para analizar si el modelo encaja con los datos, podemos visualizar ambos:<\/p>\n<pre>\r\n&gt; plot(x,y) \r\n&gt; abline(lm(y ~ x))\r\n<\/pre>\n<p>Y analizar los residuales mediante 4 gr&aacute;ficas:<\/p>\n<pre>\r\n&gt; par(mfrow=c(2,2)) ;  plot(lm.result) \r\n<\/pre>\n<ul>\n<li>Residuals vs. Fitted: Muestra los valores usados de Y junto a los residuales (diferencia con Y&#8217;). Observando la distribuci&oacute;n alrededor de la linea y=0 podr&iacute;amos identificar tendencias que nos hagan pensar que existe una correlaci&oacute;n entre los datos.<\/li>\n<li>Normal qqplot: Los residuales son normales si la gr&aacute;fica se aproxima a una linea recta.<\/li>\n<li>Scale-Location: Muestra la raiz cuadrada de los residuales estandarizados. Los puntos m&aacute;s altos corresponden con los residuales m&aacute;s largos.<\/li>\n<li>Cook&rsquo;s distance: Identifica los puntos que tienen mucha influencia sobre la linea de regresi&oacute;n. <\/li>\n<\/ul>\n<p>Veamos un ejemplo donde el modelo encaja significativamente con los datos:<\/p>\n<pre>\r\n&gt; xx = 1:100\r\n&gt; yy = xx*2 + 100\r\n&gt; plot(xx,yy) \r\n&gt; abline(lm(yy ~ xx)) \r\n&gt; par(mfrow=c(2,2));plot(lm(yy ~ xx)) \r\n<\/pre>\n<p>Como hemos visto en el ejemplo inicial, el modelo generado correspondia con esta formula: y = -0.003217 * x + 1.130803<\/p>\n<p>Los par&aacute;metros calculados son inferencias sobre los cuales se realizan un test de verificaci&oacute;n y por tanto  tienen asociado un p-value :<\/p>\n<pre>\r\n&gt; coefficients(summary(lm.result)) \r\n                Estimate  Std. Error    t value     Pr(&gt;|t|) \r\n(Intercept)  1.130804321 0.191432344  5.9070703 5.041288e-08 \r\nx           -0.003217217 0.003291033 -0.9775707 3.306937e-01\r\n<\/pre>\n<p>Segundo ejemplo donde el modelo se ajusta m&aacute;s a la realidad:<\/p>\n<pre>\r\n&gt; coefficients(summary(lm(yy~xx))) \r\n            Estimate   Std. Error      t value Pr(&gt;|t|) \r\n(Intercept)      100 4.002787e-15 2.498259e+16        0 \r\nxx                 2 6.881441e-17 2.906368e+16        0\r\n<\/pre>\n<p>Con la funci&oacute;n &quot;predict&quot; podemos obtener las Y para X determinadas:<\/p>\n<pre>\r\n&gt; predict(lm.result,data.frame(x=c(1,2))) \r\n       1        2 \r\n1.127587 1.124370 \r\n<\/pre>\n<p>Y tambi&eacute;n podemos generar para cada predicci&oacute;n el intervalo de confianza:<\/p>\n<pre>\r\n&gt; predict(lm.result,data.frame(x=c(1,2)), interval=\"confidence\") \r\n       fit       lwr      upr \r\n1 1.127587 0.7533518 1.501822 \r\n2 1.124370 0.7557617 1.492978\r\n<\/pre>\n<p>Esto puede ser de utilidad observarlo gr&aacute;ficamente:<\/p>\n<pre>\r\nplot(x,y) \r\nabline(lm.result, col=\"red\") \r\ncurve(predict(lm.result,data.frame(x=x), level=.95, interval=\"confidence\")[,3],add=T) \r\ncurve(predict(lm.result,data.frame(x=x), level=.95, interval=\"confidence\")[,2],add=T)\r\n<\/pre>\n<h4><a name=\"00223\">Regresiones lineales m&uacute;ltiples<\/a><\/h4>\n<p>Para predecir el precio de una vivienda, existen m&uacute;ltiples factores que influyen: n&uacute;mero de habitaciones, barrio, etc. Por tanto, el modelo ser&aacute; diferente al visto en el anterior apartado:<\/p>\n<p>\tY = B0 + B1*X1 + B2*X2 + &#8230;<\/p>\n<p>Si partimos de los siguientes datos (extra&iacute;do del tutorial simpleR):<\/p>\n<pre>\r\n\"homeprice\" &lt;- \r\nstructure(list(list = c(80, 151.4, 310, 295, 339, 337.5, 228.7, \r\n245, 339, 43, 279, 599, 119, 289, 249, 178, 159, 289, 488, 376, \r\n249, 275, 275, 459, 219, 359, 379, 189, 173), sale = c(117.7, \r\n151, 300, 275, 340, 337.5, 215, 239, 345, 48, 262.5, 613, 119, \r\n305, 249, 170, 153, 291, 450, 370, 245, 275, 272.5, 459, 230, \r\n360, 370, 185, 185), full = c(1, 1, 2, 2, 2, 1, 3, 1, 1, 1, 1, \r\n3, 2, 2, 1, 2, 1, 2, 3, 3, 1, 2, 2, 3, 1, 2, 2, 1, 1), half = c(0, \r\n0, 1, 1, 0, 1, 0, 1, 2, 0, 2, 2, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, \r\n1, 1, 1, 0, 1, 1, 0), bedrooms = c(3, 4, 4, 4, 3, 4, 3, 3, 3, \r\n1, 3, 4, 3, 3, 2, 3, 2, 3, 3, 3, 3, 4, 2, 5, 3, 3, 4, 4, 3), \r\n    rooms = c(6, 7, 9, 8, 7, 8, 7, 7, 7, 3, 8, 10, 7, 6, 4, 6, \r\n    7, 7, 7, 7, 8, 8, 6, 11, 7, 8, 8, 8, 7), neighborhood = c(1, \r\n    1, 2, 2, 3, 2, 1, 1, 2, 1, 1, 3, 1, 2, 2, 1, 1, 2, 3, 3, \r\n    2, 2, 2, 3, 2, 3, 3, 1, 2)), .Names = c(\"list\", \"sale\", \"full\", \r\n\"half\", \"bedrooms\", \"rooms\", \"neighborhood\"), row.names = c(NA, \r\n-29L), class = \"data.frame\")\r\n<\/pre>\n<pre>\r\n&gt; homeprice \r\n    list  sale full half bedrooms rooms neighborhood \r\n1   80.0 117.7    1    0        3     6            1 \r\n2  151.4 151.0    1    0        4     7            1 \r\n3  310.0 300.0    2    1        4     9            2 \r\n4  295.0 275.0    2    1        4     8            2 \r\n5  339.0 340.0    2    0        3     7            3 \r\n...\r\n<\/pre>\n<p>Podemos observar el precio en funci&oacute;n de las habitaciones de la vivienda y agrupados seg&uacute;n barriadas:<\/p>\n<pre>\r\n&gt; library(lattice);\t\r\n&gt; panel.lm = function(x,y) { \r\n  panel.xyplot(x,y) \r\n  panel.abline(lm(y~x))} \r\n&gt; attach(homeprice)\r\n&gt; xyplot(sale ~ rooms | neighborhood, panel= panel.lm,layout=c(3,1))\r\n<\/pre>\n<p>Si tenemos en cuenta los dormitorios y los ba&ntilde;os completamente equipados:<\/p>\n<pre>\r\n&gt; summary(lm(sale ~ bedrooms + full + neighborhood)) \r\n\r\nCall: \r\nlm(formula = sale ~ bedrooms + full + neighborhood) \r\n\r\nResiduals: \r\n   Min     1Q Median     3Q    Max \r\n-72.85 -43.11 -15.36  22.89 165.38 \r\n\r\nCoefficients: \r\n             Estimate Std. Error t value Pr(&gt;|t|)    \r\n(Intercept)    -67.89      47.58  -1.427   0.1660    \r\nbedrooms        31.74      14.77   2.149   0.0415 *  \r\nfull            28.51      18.19   1.567   0.1297    \r\nneighborhood   101.00      17.69   5.709 6.04e-06 *** \r\n--- \r\nSignif. codes:  0 *** 0.001 ** 0.01 * 0.05 . 0.1   1 \r\n\r\nResidual standard error: 58.71 on 25 degrees of freedom \r\nMultiple R-squared: 0.7764,\tAdjusted R-squared: 0.7496 \r\nF-statistic: 28.94 on 3 and 25 DF,  p-value: 2.694e-08\r\n<\/pre>\n<p>Vemos que un dormitorio adicional supone 31 mil euros m&aacute;s, un ba&ntilde;o completo 28 mil euros y estar situado en un barrio mejor 101 mil euros adicionales.<\/p>\n<p>El precio de una vivienda sin habitaciones corresponder&iacute;a a (seg&uacute;n la barriada):<\/p>\n<pre>\r\n&gt; -67.89 + 101*(1:3) \r\n[1]  33.11 134.11 235.11\r\n<\/pre>\n<p>Las variables pueden ser combinadas de la siguientes forma:<\/p>\n<table WIDTH=100% BORDER=1 BORDERCOLOR=\"#000000\" CELLPADDING=4 CELLSPACING=0>\n<col WIDTH=128*>\n\t<\/col>\n<col WIDTH=128*>\n<tr VALIGN=TOP>\n<td WIDTH=50% BGCOLOR=\"#333366\">\n<p ALIGN=CENTER><font COLOR=\"#ffffff\"><b>F&oacute;rmula<\/b><\/font>\n\t\t<\/p>\n<\/td>\n<td WIDTH=50% BGCOLOR=\"#333366\">\n<p ALIGN=CENTER><font COLOR=\"#ffffff\"><b>Interpretaci&oacute;n<\/b><\/font>\n\t\t<\/p>\n<\/td>\n<\/tr>\n<tr VALIGN=TOP>\n<td WIDTH=50%>\n\t\t\tY &sim; X1\n\t\t<\/td>\n<td WIDTH=50%>\n\t\t\tY modelado por X1 (visto en el apartado<br \/>\n\t\t\tanterior)\n\t\t<\/td>\n<\/tr>\n<tr VALIGN=TOP>\n<td WIDTH=50%>\n\t\t\tY &sim; X1 + X2\n\t\t<\/td>\n<td WIDTH=50%>\n\t\t\tY modelado por X1 y X2 <\/p>\n<\/td>\n<\/tr>\n<tr VALIGN=TOP>\n<td WIDTH=50%>\n\t\t\tY &sim; X1 * X2\n\t\t<\/td>\n<td WIDTH=50%>\n\t\t\tY modelado por X1, X2 y X1*X2\n\t\t<\/td>\n<\/tr>\n<tr VALIGN=TOP>\n<td WIDTH=50%>\n\t\t\t(Y &sim; (X1 + X2)&circ;2)\n\t\t<\/td>\n<td WIDTH=50%>\n\t\t\tInteracci&oacute;n en 2 sentidos <\/p>\n<\/td>\n<\/tr>\n<tr VALIGN=TOP>\n<td WIDTH=50%>\n\t\t\tY &sim; X1+ I((X2^2)\n\t\t<\/td>\n<td WIDTH=50%>\n\t\t\tY modelado por X1 y X2 al cuadrado\n\t\t<\/td>\n<\/tr>\n<tr VALIGN=TOP>\n<td WIDTH=50%>\n\t\t\tY &sim; X1 | X2\n\t\t<\/td>\n<td WIDTH=50%>\n\t\t\tY modelado por X1 condicionado en X2 (p.ej. precio piso (Y) seg&uacute;n habitaciones (X1) pero la relaci&oacute;n depende del barrio (X2 = Eixample, Gracia&#8230;), un modelo diferente por cada barrio)\n\t\t<\/td>\n<\/tr>\n<\/col>\n<\/table>\n<h3><a name=\"00116\">Estandarizar y escalar<\/a><\/h3>\n<p>Si queremos comparar dos variables aleatorias con escalas diferentes (media y desviaci&oacute;n est&aacute;ndar diferentes) podemos estandarizarlas utilizando la funci&oacute;n &#8216;scale&#8217; que nos devolver&aacute; los datos con media 0 y desviaci&oacute;n est&aacute;ndar 1: <\/p>\n<pre>\r\n&gt; x = rnorm(5, mean=100, sd=16) \r\n&gt; z = scale(x) \r\n&gt; mean(z)\t# Casi 0 \r\n[1] 1.887162e-16 \r\n&gt; sd(z)\t# 1 \r\n[1] 1\r\n<\/pre>\n<h3><a name=\"00117\">T&eacute;cnicas para identificar fraude<\/a><\/h3>\n<p>Si necesitamos estudiar unos datos para identificar posibles fraudes (p.ej. blanqueo de capitales), podemos utilizar diversas t&eacute;cnicas que nos ayudaran a centrar nuestro trabajo:<\/p>\n<ul>\n<li>Ordenaci&oacute;n de los datos y Agings: dado un conjunto de transacciones de un periodo, si se identifican fechas anteriores o futuras pueden ser indicios de potenciales fraudes.<\/li>\n<\/ul>\n<ul>\n<li>Clasificaci&oacute;n: Si por ejemplo el 95% de las transacciones se encuentran destinadas a la misma persona, esto puede ser un indicio de fraude.<\/li>\n<\/ul>\n<ul>\n<li>Estad&iacute;stica:<\/li>\n<\/ul>\n<p>A partir de un conjunto de valores, como por ejemplo:<\/p>\n<pre>\r\n&gt; transacciones = round(rexp(100)*1000, 2) \r\n<\/pre>\n<p>Podemos utilizar como regla que un valor extremo (outlier) ser&aacute; todo aquel valor superior\/inferior a la media mas\/menos la desviaci&oacute;n est&aacute;ndar multiplicada por 3. Ejemplo: <\/p>\n<pre>\r\n&gt; transacciones[transacciones &lt; mean(transacciones)-sd(transacciones)*3] \r\nnumeric(0) \r\n&gt; transacciones[transacciones &gt; mean(transacciones)+sd(transacciones)*3] \r\n[1] 4621.22 5500.91 5049.35\r\n<\/pre>\n<p>Estas transacciones son potenciales anomal&iacute;as que deben ser analizadas. <\/p>\n<p>Otra forma de realizar la misma identificaci&oacute;n de forma gr&aacute;fica seria utilizando boxplot: <\/p>\n<pre>\r\n&gt; boxplot(transacciones) \r\n<\/pre>\n<p>Existen otros m&eacute;todos para la identificaci&oacute;n de valores extremos como por ejemplo: Rosner test, Dixon test y Grubbs test, cuyas implementaciones para R pueden encontrarse en librer&iacute;as disponibles en la red. <\/p>\n<ul>\n<li>Ley de Benford:<\/li>\n<\/ul>\n<p>Es m&aacute;s probable que el d&iacute;gito 1 sea el primero de una cantidad que el 9. Si existe alg&uacute;n tipo de fraude, es probable que desvirt&uacute;e esta distribuci&oacute;n.<\/p>\n<p>Definimos en R las siguientes funciones que definen una distribuci&oacute;n discreta que sigue la ley de Benford: <\/p>\n<pre>\r\n# Funci\u00f3n de densidad \r\ndbenford = function(x){ \r\n\tlog10(1 + 1\/x) \r\n} \r\n \r\n# Funci\u00f3n de distribuci\u00f3n \r\npbenford = function(q){ \r\n\tcumprobs = cumsum(dbenford(1:9)) \r\n\treturn(cumprobs[q]) \r\n} \r\n \r\n# Funci\u00f3n de los cuantiles \r\nqbenford = function(p){ \r\n\tcumprobs = cumsum(dbenford(1:9)) \r\n\tcumprobs[9] = 1 # To fix a rounding error \r\n\tquantiles = sapply(p, function(x) {10 - sum(cumprobs &gt;= x)}) \r\n\treturn(quantiles) \r\n} \r\n\r\n# Generaci\u00f3n aleatoria de n\u00famero seg\u00fan la distribuci\u00f3n \r\nrbenford = function(n){ \r\n\tsample(1:9, size = n, replace = TRUE, prob = dbenford(1:9)) \r\n}\r\n<\/pre>\n<p>Tambi&eacute;n creamos una funci&oacute;n que nos permita visualizar gr&aacute;ficamente un conjunto de datos y compararlos contra la distribuci&oacute;n basada en la ley de Benford: <\/p>\n<pre>\r\nBenfordObsExp = function(x){ \r\n\tdata = substitute(x) \r\n\tn = length(x) \r\n\t# Peel off the first digit \r\n\tx = as.numeric(substring(formatC(x, format = 'e'), 1, 1)) \r\n\tobsFreq = tabulate(x, nbins = 9) \r\n\tbenFreq = n * dbenford(1:9) \r\n\tplot(1:9, benFreq, xlim = c(1, 9), ylim = c(0, max(obsFreq, benFreq)), type = 'l', \r\n\tmain = paste(data, \": observed (red) and expected (Benford's Law)\"), \r\n\txlab = \"Digit\", ylab = \"Frequency\") \r\n\taxis(1, at = 1:9) \r\n\tpoints(1:9, obsFreq, col = \"red\", pch = 16) \r\n}\r\n<\/pre>\n<p>Visualizamos las transacciones para identificar anomal&iacute;as: <\/p>\n<pre>\r\n&gt; BenfordObsExp(transacciones) \r\n<\/pre>\n<h3><a name=\"00118\">Programaci&oacute;n<\/a><\/h3>\n<p>Hasta el momento hemos visto como interactuar con la shell de R, pero tambi&eacute;n podemos generar ficheros con comandos para que sean ejecutados por R. Por ejemplo, creamos el fichero &ldquo;test.R&rdquo;:<\/p>\n<pre>\r\nx = runif(100) \r\ny = runif(100) \r\nz = x + y \r\ncat(\"Imprimimos el listado generado:\\n\")\r\nz \r\ncat(\"Fin\")\r\n<\/pre>\n<p>Y lo ejecutamos mediante:<\/p>\n<pre>\r\n$ R --slave --vanilla -f test.R \r\nImprimimos el listado generado: \r\n  [1] 0.8127675 0.2205953 0.8711474 1.1461206 1.5373148 0.8068898 1.1030845 \r\n  [8] 0.3391666 1.2360769 1.3011322 1.5047748 0.5618684 0.9276672 0.8581834 \r\n [15] 1.6176204 0.8798410 0.8575242 0.8529046 1.7232819 0.7442834 1.1624653 \r\n [22] 1.5103152 1.2968150 1.2777382 0.6855236 0.8132157 1.3333253 1.2821548 \r\n [29] 1.3576682 1.1655971 0.3267455 1.1248876 0.2601012 0.3260605 0.7609038 \r\n [36] 0.5666418 0.8664088 1.2207019 1.1709423 1.4731985 1.4740750 1.5157082 \r\n [43] 1.2244977 1.2633403 1.6129252 1.6111450 0.8875049 0.9616655 1.0212954 \r\n [50] 0.3086974 0.8500047 0.9417143 1.7620811 0.9862873 1.2310904 0.7335394 \r\n [57] 1.2586577 0.9282816 0.6394448 0.9480084 1.0489753 0.1546561 0.8817316 \r\n [64] 0.8384202 0.9665596 1.9363211 1.1402878 0.5812365 0.5223378 1.5062012 \r\n [71] 0.4690346 1.1312263 1.1484181 1.5491576 1.9231288 0.8261800 1.6588865 \r\n [78] 0.2999772 0.5317558 1.0639816 1.6124205 1.0747384 0.8697748 0.7791368 \r\n [85] 1.0116984 0.7644074 1.5599921 0.8562209 1.5363938 1.1215349 1.1354001 \r\n [92] 0.9089423 1.7165493 0.8804664 0.6908375 0.1000780 1.3157824 1.3394445 \r\n [99] 1.1517646 0.6332460 \r\nFin\r\n<\/pre>\n<p>Tambi&eacute;n podr\u00edamos cargar y ejecutar el c&oacute;digo del fichero &quot;test.R&quot; desde la terminal de R:<\/p>\n<pre>\r\n$ R -q \r\n&gt; source(\"test.R\") \r\nCodigo de ejemplo \r\nImprimimos el listado generado: \r\nFin\r\n<\/pre>\n<p>En este caso el comportamiento es ligeramente diferente, la variable Z no se imprime por pantalla pero si queda en memoria para que podamos trabajar con ella.<\/p>\n<h4><a name=\"00224\">Estructuras de control<\/a><\/h4>\n<p>Condiciones: <\/p>\n<pre>\r\nif(...) { \r\n  ... \r\n} else { \r\n  ... \r\n} \r\n<\/pre>\n<pre>\r\nx = rnorm(100) \r\ny = ifelse(x&gt;0, 1, -1) \r\nz = ifelse(x&gt;0, 1, ifelse(x&lt;0, -1, 0)) \r\n<\/pre>\n<p>Bucles: <\/p>\n<pre>\r\nfor (i in 1:10) { \r\n  ... \r\n  if(...) { next } \r\n  ... \r\n  if(...) { break } \r\n  ... \r\n} \r\n<\/pre>\n<pre>\r\nwhile(...) { \r\n  ... \r\n}\r\n<\/pre>\n<h4><a name=\"00225\">Definici&oacute;n de funciones<\/a><\/h4>\n<p>Podemos crear funciones donde el valor retornado corresponder&aacute; a la &uacute;ltima expresi&oacute;n (como en Ruby, aunque tambi&eacute;n podemos utilizar return): <\/p>\n<pre>\r\nf = function(x, z=1) { \r\n  x^2 + x + z \r\n}\r\n<\/pre>\n<p>Adicionalmente, la anterior funci&oacute;n define 2 argumentos, el segundo puede no ser especificado y toma por defecto 1. A la hora de utilizar la funci&oacute;n, si especificamos los nombres de los argumentos, estos pueden ir en<br \/>\ncualquier orden: <\/p>\n<pre>\r\n\tf(2)\t# x=2, z=1 \r\n\tf(3, 2)\t# x=3, z=2 \r\n\tf(z=2, x=3)\t#x=3, z=2\r\n<\/pre>\n<p>Cuando llamamos a la funci&oacute;n, el valor retornado se imprime por pantalla, si queremos que lo devuelva igualmente pero que no se imprima podemos utilizar invisble: <\/p>\n<pre>\r\nf = function(x, z=1) { \r\n  invisible(x^2 + x + z) \r\n} \r\nr = f(2) \r\nr\r\n<\/pre>\n<p>Podemos tener un n&uacute;mero indefinido de argumentos si utilizamos &quot;&#8230;&quot;: <\/p>\n<pre>\r\nf = function(x, ...) { \r\n  plot(x, ...) \r\n} \r\n\r\nf = function (...) { \r\n  l = list(...) # Put the arguments in a (named) list \r\n  for (i in seq(along=l)) { \r\n\tcat(\"Argument name:\", names(l)[i], \"Value:\", l[[i]], \"\\n\") \r\n  } \r\n}\r\n<\/pre>\n<p>Es importante tener en cuenta que una funci&oacute;n siempre guarda toda la informaci&oacute;n en su ambito local, no puede modificar valores de variables globales.<\/p>\n<p>Si queremos ver el c&oacute;digo de una funci&oacute;n, simplemente la llamamos sin parentesis ni argumentos: <\/p>\n<pre>\r\n&gt; f \r\nfunction(x, z=1) { \r\n  invisible(x^2 + x + z) \r\n}\r\n<\/pre>\n<h4><a name=\"00226\">Depurar \/ Debug <\/a><\/h4>\n<p>Paso a paso: <\/p>\n<pre>\r\nf = function () { \r\n  x = rnorm(10) \r\n  y = rnorm(11) \r\n  x + y \r\n} \r\ndebug(f) \r\nf() \r\n\r\n# n o ENTER para continuar al siguiente paso \r\n# c para continuar hasta el siguiente cambio de contexto \r\n# where llamadas \r\n# Q termina \r\n# Cualquier otra expresi\u00f3n ser\u00e1 evaluada desde el entorno donde se llam\u00f3 a f(), es decir, no podemos ver las variables locales \r\n\r\nundebug(f)\r\n<\/pre>\n<p>Breakpoints: <\/p>\n<pre>\r\nf = function () { \r\n  x = rnorm(10) \r\n  y = rnorm(11) \r\n  browser() \r\n  x + y \r\n} \r\n\r\nf() \r\n\r\n# Mismas posibilidades que con debug, excepto que aqu\u00ed si podemos acceder a las variables locales (p.ej. x e y \r\n<\/pre>\n<h4><a name=\"00227\">Optimizaci&oacute;n \/ Profiling<\/a><\/h4>\n<pre>\r\n# Tiempo de ejecuci\u00f3n de una funci\u00f3n \r\n&gt; system.time(runif(100)) \r\n   user  system elapsed \r\n\t  0       0       0\r\n<\/pre>\n<p>Consultar ayuda:<\/p>\n<pre>\r\n?RProf\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>En el \u00faltimo art\u00edculo hemos visto AWK como herramienta para el tratamiento masivo de datos, donde hemos demostrado que pod\u00eda ser una alternativa parcial a otras herramientas comerciales como SAS, ACL o IDEA (muy utilizadas en el mundo de la Auditor\u00eda). AWK es una soluci\u00f3n parcial dado que \u00fanicamente nos proporciona funcionalidades para hacer un &hellip; <a href=\"https:\/\/www.marblestation.com\/?p=794\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">R, estad\u00edstica y tratamiento masivo de datos (alternativa a SAS, ACL e IDEA)<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1,6],"tags":[],"class_list":["post-794","post","type-post","status-publish","format-standard","hentry","category-espanyol","category-tecnologia"],"_links":{"self":[{"href":"https:\/\/www.marblestation.com\/index.php?rest_route=\/wp\/v2\/posts\/794","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.marblestation.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.marblestation.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.marblestation.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.marblestation.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=794"}],"version-history":[{"count":11,"href":"https:\/\/www.marblestation.com\/index.php?rest_route=\/wp\/v2\/posts\/794\/revisions"}],"predecessor-version":[{"id":1222,"href":"https:\/\/www.marblestation.com\/index.php?rest_route=\/wp\/v2\/posts\/794\/revisions\/1222"}],"wp:attachment":[{"href":"https:\/\/www.marblestation.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=794"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.marblestation.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=794"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.marblestation.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=794"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}