3 Procesado de datos
Fecha última actualización: 2024-10-12
Instalación/carga librerías utilizadas
if (!require(openxlsx)) install.packages('openxlsx')
library(openxlsx)
if (!require(pxR)) install.packages('pxR')
library(pxR)
if (!require(tidyverse)) install.packages('tidyverse')
library(tidyverse)
Rara vez nos encontramos los datos organizados en la forma que necesitamos para el objetivo de nuestro análisis. De hecho, con frecuencia, el trabajo más complejo de nuestra exploración de datos es localizar, extraer y entender como están organizados los datos. Por ello, la primera tarea de cualquier análisis de datos es procesarlos hasta tenerlos en la forma y estructura que nosotros queremos. Por ello vamos a dedicar en el curso cierta atención a la manipulación de datos.
En primer lugar hablaremos de las bases de datos principales que usaremos en el curso. Como se verá a continuación se utilizarán principalmente bases de datos actuales sobre temas de interés general que pueden ser más atractivas que las bases de datos incluidas por defecto en R
que se suelen usar en los cursos de análisis de datos.
3.1 Bases de datos
Las fuentes principales de información que vamos a usar para ilustrar los contenidos del curso son las siguientes bases de datos de interés general:
OWID: base de datos a nivel mundial sobre temas de actualidad
UNdata: base de datos de la organización de las Naciones Unidas.
INE: base de datos del Instituto Nacional de Estadística.
ISTAC : base de datos del Instituto Canario de Estadística
UNICEF : base de datos de UNICEF
Organización mundial de la salud : base de datos de la Organización mundial de la salud
Kaggle : Kaggle es una plataforma muy popular para compartir datos. Tiene la ventaja de que posee una gran variedad de todo tipo de datos pero hay que tener precaución porque cualquier persona puede subir datos y ello puede comprometer su fiabilidad. Kaggle asigna a cada conjunto de datos el valor “Usability” que se puede interpretar como un factor de calidad de los datos que incluye la fiabilidad de las fuentes de los datos. Es importante usar datos con un valor alto de “Usability” y en particular, dentro de “Usability”, que tengan un valor alto del factor “Credibility”.
En este libro también utilizaremos algunas bases de datos almacenadas en un repositorio local de datos llamado data
. Los ficheros referenciados en este libro a este repositorio se pueden localizar en la dirección https://ctim.es/AEDV/data/. Estas bases de datos locales, en general, se han extraído de las bases de datos anteriores y por comodidad se han puesto en un repositorio local.
Además de estas bases de datos, R
tiene una amplia colección de bases de datos de ejemplo directamente accesibles. Por ejemplo la base de datos con información de coches mtcars
se utiliza mucho para ilustrar las funcionalidades de R
## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
## Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
## Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
## Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
## Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
Estas bases de datos incorporadas en R
no las utilizaremos en este curso.
3.2 Formatos de ficheros de datos
Para hacer análisis de datos, lo primero que hay que hacer es acceder a ellos, lo cual se hace generalmente leyendo los datos de un fichero donde están almacenados como una tabla. A continuación veremos los formatos de ficheros de datos más habituales y como leerlos usando las librerías correspondientes, las librerías de lectura que usamos permiten leer los datos directamente desde un servidor WEB, lo cual es un valor añadido. Como resumen de esta sección puede ser útil mirar la siguiente ficha resumen.
Formato CSV
El formato CSV consiste en un texto plano, es decir, contiene los valores de la tabla sin ninguna otra información sobre si se trata de fechas, números, caracteres, etc. Se puede editar con cualquier editor de texto (como NOTEPAD) y los campos están separados entre sí por una coma y los decimales se expresan con puntos. Para leer ficheros CSV utilizaremos la función read_csv
de la librería readl
incluida en la librería tidyverse
. Si la tabla se ha creado a partir del idioma español, es posible que los campos en la tabla estén separados por el símbolo ;
y además los decimales de los números se expresan con comas. En ese caso utilizaremos la función de lectura read_csv2
. Si el delimitador entre campos no es ni una coma ni un punto y coma, podemos usar la función read_delim
que permite declarar cualquier delimitador entre campos. En la mencionada ficha resumen aparece una descripción más detallada de estas funciones.
Un problema que surge con cierta frecuencia al leer ficheros de texto es que estos ficheros admiten diferentes tipos de codificación para los caracteres especiales como acentos, etc.. La codificación estándar que espera encontrar por defecto R
es la denominada UTF-8. Si un fichero de texto nos da problemas de lectura y no vemos ninguna razón, lo primero que debemos intentar es abrir el fichero con NOTEPAD, convertir la codificación a UTF-8, salvar el fichero y volvemos a intentar leerlo desde R
.
A continuación leeremos un fichero CSV con la información de la población mundial de la base de datos de las Naciones Unidas (UN). Como sucede con frecuencia, las tablas de datos requieren de una manipulación para corregir errores o seleccionar los campos que nos interesan. En este caso, la primera línea de la tabla contiene comentarios y en la segunda línea, que contiene los nombres de los campos, hay un campo que viene sin nombre. En secciones posteriores de este tema veremos como manipular/transformar los datos. Esta base de datos se puede leer directamente desde el servidor de las Naciones Unidas usando el script:
UN_population <- read_csv('https://data.un.org/_Docs/SYB/CSV/SYB65_1_202209_Population,%20Surface%20Area%20and%20Density.csv',skip = 1)%>%
as_tibble()
Por comodidad, hemos guardado una copia del fichero en nuestro repositorio local y la leemos desde esa fuente. Añadimos en la instrucción de lectura skip=1
para no tener en cuenta la primera línea de la tabla que contiene un comentario, una vez que leemos la tabla usamos la función str
para analizar su estructura :
UN_population <- read_csv("https://ctim.es/AEDV/data/UN_population.csv",skip = 1)%>%
as_tibble()
str(UN_population)
## tibble [7,873 × 7] (S3: tbl_df/tbl/data.frame)
## $ Region/Country/Area: num [1:7873] 1 1 1 1 1 1 1 1 1 1 ...
## $ ...2 : chr [1:7873] "Total, all countries or areas" "Total, all countries or areas" "Total, all countries or areas" "Total, all countries or areas" ...
## $ Year : num [1:7873] 2010 2010 2010 2010 2010 ...
## $ Series : chr [1:7873] "Population mid-year estimates (millions)" "Population mid-year estimates for males (millions)" "Population mid-year estimates for females (millions)" "Sex ratio (males per 100 females)" ...
## $ Value : num [1:7873] 6985.6 3514.4 3471.2 101.2 27.1 ...
## $ Footnotes : chr [1:7873] NA NA NA NA ...
## $ Source : chr [1:7873] "United Nations Population Division, New York, World Population Prospects: The 2022 Revision, last accessed July 2022." "United Nations Population Division, New York, World Population Prospects: The 2022 Revision, last accessed July 2022." "United Nations Population Division, New York, World Population Prospects: The 2022 Revision, last accessed July 2022." "United Nations Population Division, New York, World Population Prospects: The 2022 Revision; supplemented by da"| __truncated__ ...
Con frecuencia, no queda muy claro, a primera vista, el contenido real de algunas de las variables. Por ello, en el análisis exploratorio de datos, el primer paso es analizar con cierto detalle el contenido de las tablas. Para analizar el rango de valores posibles de las variables, especialmente en el caso de variables categóricas (tipo factor) podemos ver el contenido de algunas de las variables usando levels
y tomando la variable como factor
para que nos salga el rango de los valores posibles sin repetir. Para las variable numéricas podemos usar la función `summary’ para tener una primera idea de su rango de valores. Para esta primera tabla presentamos un análisis exhaustivo de las variables. En general, en este curso, para no hacer muy engorrosa la presentación de las tablas utilizadas, no analizaremos en tanto detalle las tablas usadas, pero es fundamental que los alumnos adquieran el hábito de analizar en detalle las tablas antes de empezar a trabajar con ellas.
## [1] "1" "2" "4" "5" "8" "9" "11" "12" "13" "14" "15" "16"
## [13] "17" "18" "19" "20" "21" "24" "28" "29" "30" "31" "32" "34"
## [25] "35" "36" "39" "40" "44" "48" "50" "51" "52" "53" "54" "56"
## [37] "57" "60" "61" "62" "64" "68" "70" "72" "76" "84" "90" "92"
## [49] "96" "100" "104" "108" "112" "116" "120" "124" "132" "136" "140" "142"
## [61] "143" "144" "145" "148" "150" "151" "152" "154" "155" "156" "158" "170"
## [73] "174" "175" "178" "180" "184" "188" "191" "192" "196" "202" "203" "204"
## [85] "208" "212" "214" "218" "222" "226" "231" "232" "233" "234" "238" "242"
## [97] "246" "250" "254" "258" "262" "266" "268" "270" "275" "276" "288" "292"
## [109] "296" "300" "304" "308" "312" "316" "320" "324" "328" "332" "336" "340"
## [121] "344" "348" "352" "356" "360" "364" "368" "372" "376" "380" "384" "388"
## [133] "392" "398" "400" "404" "408" "410" "414" "417" "418" "419" "422" "426"
## [145] "428" "430" "434" "438" "440" "442" "446" "450" "454" "458" "462" "466"
## [157] "470" "474" "478" "480" "484" "492" "496" "498" "499" "500" "504" "508"
## [169] "512" "516" "520" "524" "528" "531" "533" "534" "535" "540" "548" "554"
## [181] "558" "562" "566" "570" "578" "580" "583" "584" "585" "586" "591" "598"
## [193] "600" "604" "608" "616" "620" "624" "626" "630" "634" "638" "642" "643"
## [205] "646" "652" "654" "659" "660" "662" "663" "666" "670" "674" "678" "682"
## [217] "686" "688" "690" "694" "702" "703" "704" "705" "706" "710" "716" "724"
## [229] "728" "729" "732" "740" "748" "752" "756" "760" "762" "764" "768" "772"
## [241] "776" "780" "784" "788" "792" "795" "796" "798" "800" "804" "807" "818"
## [253] "826" "830" "833" "834" "840" "850" "854" "858" "860" "862" "876" "882"
## [265] "887" "894"
La variable Region/Country/Area
es un código numérico que identifica al país. Este código nos permite combinar los valores de esta tabla con otras tablas de datos de países que usen el mismo código. Esta variable la podemos gestionar como numeric
o como factor
, dado que se usa para clasificar a que país pertenece al dato de cada registro
## [1] "1" "2" "4" "5" "8" "9" "11" "12" "13" "14" "15" "16"
## [13] "17" "18" "19" "20" "21" "24" "28" "29" "30" "31" "32" "34"
## [25] "35" "36" "39" "40" "44" "48" "50" "51" "52" "53" "54" "56"
## [37] "57" "60" "61" "62" "64" "68" "70" "72" "76" "84" "90" "92"
## [49] "96" "100" "104" "108" "112" "116" "120" "124" "132" "136" "140" "142"
## [61] "143" "144" "145" "148" "150" "151" "152" "154" "155" "156" "158" "170"
## [73] "174" "175" "178" "180" "184" "188" "191" "192" "196" "202" "203" "204"
## [85] "208" "212" "214" "218" "222" "226" "231" "232" "233" "234" "238" "242"
## [97] "246" "250" "254" "258" "262" "266" "268" "270" "275" "276" "288" "292"
## [109] "296" "300" "304" "308" "312" "316" "320" "324" "328" "332" "336" "340"
## [121] "344" "348" "352" "356" "360" "364" "368" "372" "376" "380" "384" "388"
## [133] "392" "398" "400" "404" "408" "410" "414" "417" "418" "419" "422" "426"
## [145] "428" "430" "434" "438" "440" "442" "446" "450" "454" "458" "462" "466"
## [157] "470" "474" "478" "480" "484" "492" "496" "498" "499" "500" "504" "508"
## [169] "512" "516" "520" "524" "528" "531" "533" "534" "535" "540" "548" "554"
## [181] "558" "562" "566" "570" "578" "580" "583" "584" "585" "586" "591" "598"
## [193] "600" "604" "608" "616" "620" "624" "626" "630" "634" "638" "642" "643"
## [205] "646" "652" "654" "659" "660" "662" "663" "666" "670" "674" "678" "682"
## [217] "686" "688" "690" "694" "702" "703" "704" "705" "706" "710" "716" "724"
## [229] "728" "729" "732" "740" "748" "752" "756" "760" "762" "764" "768" "772"
## [241] "776" "780" "784" "788" "792" "795" "796" "798" "800" "804" "807" "818"
## [253] "826" "830" "833" "834" "840" "850" "854" "858" "860" "862" "876" "882"
## [265] "887" "894"
## [1] "Afghanistan" "Africa"
## [3] "Albania" "Algeria"
## [5] "American Samoa" "Americas"
## [7] "Andorra" "Angola"
## [9] "Anguilla" "Antigua and Barbuda"
## [11] "Argentina" "Armenia"
## [13] "Aruba" "Asia"
## [15] "Australia" "Australia and New Zealand"
## [17] "Austria" "Azerbaijan"
## [19] "Bahamas" "Bahrain"
## [21] "Bangladesh" "Barbados"
## [23] "Belarus" "Belgium"
## [25] "Belize" "Benin"
## [27] "Bermuda" "Bhutan"
## [29] "Bolivia (Plurin. State of)" "Bonaire, St. Eustatius & Saba"
## [31] "Bosnia and Herzegovina" "Botswana"
## [33] "Brazil" "British Virgin Islands"
## [35] "Brunei Darussalam" "Bulgaria"
## [37] "Burkina Faso" "Burundi"
## [39] "Cabo Verde" "Cambodia"
## [41] "Cameroon" "Canada"
## [43] "Caribbean" "Cayman Islands"
## [45] "Central African Republic" "Central America"
## [47] "Central Asia" "Chad"
## [49] "Channel Islands" "Chile"
## [51] "China" "China, Hong Kong SAR"
## [53] "China, Macao SAR" "Colombia"
## [55] "Comoros" "Congo"
## [57] "Cook Islands" "Costa Rica"
## [59] "Côte d’Ivoire" "Croatia"
## [61] "Cuba" "Curaçao"
## [63] "Cyprus" "Czechia"
## [65] "Dem. People's Rep. Korea" "Dem. Rep. of the Congo"
## [67] "Denmark" "Djibouti"
## [69] "Dominica" "Dominican Republic"
## [71] "Eastern Africa" "Eastern Asia"
## [73] "Eastern Europe" "Ecuador"
## [75] "Egypt" "El Salvador"
## [77] "Equatorial Guinea" "Eritrea"
## [79] "Estonia" "Eswatini"
## [81] "Ethiopia" "Europe"
## [83] "Falkland Islands (Malvinas)" "Faroe Islands"
## [85] "Fiji" "Finland"
## [87] "France" "French Guiana"
## [89] "French Polynesia" "Gabon"
## [91] "Gambia" "Georgia"
## [93] "Germany" "Ghana"
## [95] "Gibraltar" "Greece"
## [97] "Greenland" "Grenada"
## [99] "Guadeloupe" "Guam"
## [101] "Guatemala" "Guinea"
## [103] "Guinea-Bissau" "Guyana"
## [105] "Haiti" "Holy See"
## [107] "Honduras" "Hungary"
## [109] "Iceland" "India"
## [111] "Indonesia" "Iran (Islamic Republic of)"
## [113] "Iraq" "Ireland"
## [115] "Isle of Man" "Israel"
## [117] "Italy" "Jamaica"
## [119] "Japan" "Jordan"
## [121] "Kazakhstan" "Kenya"
## [123] "Kiribati" "Kuwait"
## [125] "Kyrgyzstan" "Lao People's Dem. Rep."
## [127] "Latin America & the Caribbean" "Latvia"
## [129] "Lebanon" "Lesotho"
## [131] "Liberia" "Libya"
## [133] "Liechtenstein" "Lithuania"
## [135] "Luxembourg" "Madagascar"
## [137] "Malawi" "Malaysia"
## [139] "Maldives" "Mali"
## [141] "Malta" "Marshall Islands"
## [143] "Martinique" "Mauritania"
## [145] "Mauritius" "Mayotte"
## [147] "Melanesia" "Mexico"
## [149] "Micronesia" "Micronesia (Fed. States of)"
## [151] "Middle Africa" "Monaco"
## [153] "Mongolia" "Montenegro"
## [155] "Montserrat" "Morocco"
## [157] "Mozambique" "Myanmar"
## [159] "Namibia" "Nauru"
## [161] "Nepal" "Netherlands"
## [163] "New Caledonia" "New Zealand"
## [165] "Nicaragua" "Niger"
## [167] "Nigeria" "Niue"
## [169] "North Macedonia" "Northern Africa"
## [171] "Northern America" "Northern Europe"
## [173] "Northern Mariana Islands" "Norway"
## [175] "Oceania" "Oman"
## [177] "Other non-specified areas" "Pakistan"
## [179] "Palau" "Panama"
## [181] "Papua New Guinea" "Paraguay"
## [183] "Peru" "Philippines"
## [185] "Poland" "Polynesia"
## [187] "Portugal" "Puerto Rico"
## [189] "Qatar" "Republic of Korea"
## [191] "Republic of Moldova" "Réunion"
## [193] "Romania" "Russian Federation"
## [195] "Rwanda" "Saint Barthélemy"
## [197] "Saint Helena" "Saint Kitts and Nevis"
## [199] "Saint Lucia" "Saint Martin (French part)"
## [201] "Saint Pierre and Miquelon" "Saint Vincent & Grenadines"
## [203] "Samoa" "San Marino"
## [205] "Sao Tome and Principe" "Saudi Arabia"
## [207] "Senegal" "Serbia"
## [209] "Seychelles" "Sierra Leone"
## [211] "Singapore" "Sint Maarten (Dutch part)"
## [213] "Slovakia" "Slovenia"
## [215] "Solomon Islands" "Somalia"
## [217] "South-central Asia" "South-eastern Asia"
## [219] "South Africa" "South America"
## [221] "South Sudan" "Southern Africa"
## [223] "Southern Asia" "Southern Europe"
## [225] "Spain" "Sri Lanka"
## [227] "State of Palestine" "Sub-Saharan Africa"
## [229] "Sudan" "Suriname"
## [231] "Sweden" "Switzerland"
## [233] "Syrian Arab Republic" "Tajikistan"
## [235] "Thailand" "Timor-Leste"
## [237] "Togo" "Tokelau"
## [239] "Tonga" "Total, all countries or areas"
## [241] "Trinidad and Tobago" "Tunisia"
## [243] "Türkiye" "Turkmenistan"
## [245] "Turks and Caicos Islands" "Tuvalu"
## [247] "Uganda" "Ukraine"
## [249] "United Arab Emirates" "United Kingdom"
## [251] "United Rep. of Tanzania" "United States of America"
## [253] "United States Virgin Islands" "Uruguay"
## [255] "Uzbekistan" "Vanuatu"
## [257] "Venezuela (Boliv. Rep. of)" "Viet Nam"
## [259] "Wallis and Futuna Islands" "Western Africa"
## [261] "Western Asia" "Western Europe"
## [263] "Western Sahara" "Yemen"
## [265] "Zambia" "Zimbabwe"
La variable ...2
es el nombre del país y es de tipo character
.
## [1] "Population aged 0 to 14 years old (percentage)"
## [2] "Population aged 60+ years old (percentage)"
## [3] "Population density"
## [4] "Population mid-year estimates (millions)"
## [5] "Population mid-year estimates for females (millions)"
## [6] "Population mid-year estimates for males (millions)"
## [7] "Sex ratio (males per 100 females)"
## [8] "Surface area (thousand km2)"
La variable Series
, describe el nombre del indicador asociado al dato de cada registro, es decir, indica lo que se está midiendo en cada registro. Podemos gestionarla como character
o como factor
dado que también se usa para clasificar los registros. Con frecuencia, no queda claro, a partir del nombre del indicador, cual es su significado exacto. En ese caso hay que mirar información complementaria a la tabla donde se explica con más detalle el significado de los indicadores utilizados. Esto es muy importante para poder interpretar y comprender los datos que manejamos.
## [1] "2010" "2015" "2017" "2020" "2022"
La variable Year
determina el año asociado al dato de cada registro. Habitualmente convertiremos los datos temporales en tipo Date
, en este caso, por ejemplo, podemos asociarle el último día del año en cuestión.
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.00 5.00 21.52 255.80 94.70 136162.00
La variable Value', de tipo
numeric`, suministra el valor numérico del dato de cada registro.
## [1] "A dispute exists between the Governments of Argentina and the United Kingdom of Great Britain and Northern Ireland concerning sovereignty over the Falkland Islands (Malvinas)."
## [2] "A dispute exists between the Governments of Argentina and the United Kingdom of Great Britain and Northern Ireland concerning sovereignty over the Falkland Islands (Malvinas). For statistical purposes, the data for United Kingdom do not include this area."
## [3] "Calculated by the UN Statistics Division."
## [4] "Calculated by the UN Statistics Division.;Projected estimate (medium fertility variant)."
## [5] "Changes in total area per year are the result of new measuring and correcting of the administrative borders between former Yugoslavian countries."
## [6] "Comprising the Northern Region (former Saguia el Hamra) and Southern Region (former Rio de Oro)."
## [7] "Data refer to 1 October 2007."
## [8] "Data refer to the Vatican City State."
## [9] "Data updated according to \"Superintendencia Agraria\". Interior waters correspond to natural or artificial bodies of water or snow."
## [10] "Excluding Åland Islands."
## [11] "Excluding Channel Islands (Guernsey and Jersey) and Isle of Man, shown separately, if available."
## [12] "Excluding Faeroe Islands and Greenland shown separately, if available."
## [13] "Excluding inland water."
## [14] "Excluding Kosovo."
## [15] "Excluding Niue, shown separately, which is part of Cook Islands, but because of remoteness is administered separately."
## [16] "Excluding the islands of Saint Brandon and Agalega."
## [17] "For statistical purposes, the data for China do not include this area."
## [18] "For statistical purposes, the data for China do not include this area.;Projected estimate (medium fertility variant)."
## [19] "For statistical purposes, the data for China do not include those for the Hong Kong Special Administrative Region (Hong Kong SAR), Macao Special Administrative Region (Macao SAR) and Taiwan Province of China."
## [20] "For statistical purposes, the data for Denmark do not include Faroe Islands, and Greenland."
## [21] "For statistical purposes, the data for Denmark do not include this area."
## [22] "For statistical purposes, the data for France do not include French Guiana, French Polynesia, Guadeloupe, Martinique, Mayotte, New Caledonia, Réunion, Saint Pierre and Miquelon, Saint Barthélemy, Saint Martin (French part), Wallis and Futuna Islands."
## [23] "For statistical purposes, the data for France do not include this area."
## [24] "For statistical purposes, the data for France do not include this area.;Projected estimate (medium fertility variant)."
## [25] "For statistical purposes, the data for Netherlands do not include Aruba, Bonaire, Sint Eustatius and Saba, Curaçao, and Sint Maarten (Dutch part)."
## [26] "For statistical purposes, the data for Netherlands do not include this area."
## [27] "For statistical purposes, the data for Netherlands do not include this area.;Projected estimate (medium fertility variant)."
## [28] "For statistical purposes, the data for New Zealand do not include Cook Islands, Niue, and Tokelau."
## [29] "For statistical purposes, the data for New Zealand do not include this area."
## [30] "For statistical purposes, the data for United Kingdom do not include this area."
## [31] "For statistical purposes, the data for United States of America do not include American Samoa, Guam, Northern Mariana Islands, Puerto Rico, and United States Virgin Islands."
## [32] "For statistical purposes, the data for United States of America do not include this area."
## [33] "Including Abkhazia and South Ossetia."
## [34] "Including Agalega, Rodrigues and Saint Brandon."
## [35] "Including Åland Islands."
## [36] "Including Andorra, Gibraltar, Holy See, and San Marino."
## [37] "Including Anguilla, Bonaire, Sint Eustatius and Saba, British Virgin Islands, Cayman Islands, Dominica, Montserrat, Saint Kitts and Nevis, Sint Maarten (Dutch part) and Turks and Caicos Islands."
## [38] "Including Ascension and Tristan da Cunha."
## [39] "Including Ascension and Tristan da Cunha. For statistical purposes, the data for United Kingdom do not include this area."
## [40] "Including Ascension and Tristan da Cunha.;St. Helena Island has no substantial natural inland waters however there are 15 reservoirs and similar open water storage features on island."
## [41] "Including Bermuda, Greenland, and Saint Pierre and Miquelon."
## [42] "Including Canary Islands, Ceuta and Melilla."
## [43] "Including Christmas Island, Cocos (Keeling) Islands and Norfolk Island."
## [44] "Including Crimea."
## [45] "Including East Jerusalem."
## [46] "Including Falkland Islands (Malvinas)."
## [47] "Including Liechtenstein and Monaco."
## [48] "Including low water level for all islands (area to shoreline)."
## [49] "Including Marshall Islands, Nauru, Northern Mariana Islands and Palau."
## [50] "Including Nagorno-Karabakh."
## [51] "Including Norfolk Island."
## [52] "Including Pitcairn."
## [53] "Including Sabah and Sarawak."
## [54] "Including Saint Helena."
## [55] "Including Svalbard and Jan Mayen Islands."
## [56] "Including the Faroe Islands and the Isle of Man."
## [57] "Including the Transnistria region."
## [58] "Including water bodies of lake Vaihiria, lake Temae and the Maiao lagoons, but not lake Maeva and the lagoons of Raiatea and Tahaa from the upper islands. No lagoons from lower islands are included."
## [59] "Including Zanzibar."
## [60] "Inland waters include the reservoirs."
## [61] "Land area only."
## [62] "Land area only. Excluding 84 square km of uninhabited islands."
## [63] "Projected estimate (medium fertility variant)."
## [64] "Projected estimate (medium fertility variant).;A dispute exists between the Governments of Argentina and the United Kingdom of Great Britain and Northern Ireland concerning sovereignty over the Falkland Islands (Malvinas). For statistical purposes, the data for United Kingdom do not include this area."
## [65] "Projected estimate (medium fertility variant).;Data refer to the Vatican City State."
## [66] "Projected estimate (medium fertility variant).;Excluding Kosovo."
## [67] "Projected estimate (medium fertility variant).;For statistical purposes, the data for China do not include those for the Hong Kong Special Administrative Region (Hong Kong SAR), Macao Special Administrative Region (Macao SAR) and Taiwan Province of China."
## [68] "Projected estimate (medium fertility variant).;For statistical purposes, the data for Denmark do not include Faroe Islands, and Greenland."
## [69] "Projected estimate (medium fertility variant).;For statistical purposes, the data for Denmark do not include this area."
## [70] "Projected estimate (medium fertility variant).;For statistical purposes, the data for France do not include French Guiana, French Polynesia, Guadeloupe, Martinique, Mayotte, New Caledonia, Réunion, Saint Pierre and Miquelon, Saint Barthélemy, Saint Martin (French part), Wallis and Futuna Islands."
## [71] "Projected estimate (medium fertility variant).;For statistical purposes, the data for France do not include this area."
## [72] "Projected estimate (medium fertility variant).;For statistical purposes, the data for Netherlands do not include Aruba, Bonaire, Sint Eustatius and Saba, Curaçao, and Sint Maarten (Dutch part)."
## [73] "Projected estimate (medium fertility variant).;For statistical purposes, the data for Netherlands do not include this area."
## [74] "Projected estimate (medium fertility variant).;For statistical purposes, the data for New Zealand do not include Cook Islands, Niue, and Tokelau."
## [75] "Projected estimate (medium fertility variant).;For statistical purposes, the data for New Zealand do not include this area."
## [76] "Projected estimate (medium fertility variant).;For statistical purposes, the data for United Kingdom do not include this area."
## [77] "Projected estimate (medium fertility variant).;For statistical purposes, the data for United States of America do not include American Samoa, Guam, Northern Mariana Islands, Puerto Rico, and United States Virgin Islands."
## [78] "Projected estimate (medium fertility variant).;For statistical purposes, the data for United States of America do not include this area."
## [79] "Projected estimate (medium fertility variant).;Including Abkhazia and South Ossetia."
## [80] "Projected estimate (medium fertility variant).;Including Agalega, Rodrigues and Saint Brandon."
## [81] "Projected estimate (medium fertility variant).;Including Åland Islands."
## [82] "Projected estimate (medium fertility variant).;Including Andorra, Gibraltar, Holy See, and San Marino."
## [83] "Projected estimate (medium fertility variant).;Including Anguilla, Bonaire, Sint Eustatius and Saba, British Virgin Islands, Cayman Islands, Dominica, Montserrat, Saint Kitts and Nevis, Sint Maarten (Dutch part) and Turks and Caicos Islands."
## [84] "Projected estimate (medium fertility variant).;Including Ascension and Tristan da Cunha. For statistical purposes, the data for United Kingdom do not include this area."
## [85] "Projected estimate (medium fertility variant).;Including Bermuda, Greenland, and Saint Pierre and Miquelon."
## [86] "Projected estimate (medium fertility variant).;Including Canary Islands, Ceuta and Melilla."
## [87] "Projected estimate (medium fertility variant).;Including Christmas Island, Cocos (Keeling) Islands and Norfolk Island."
## [88] "Projected estimate (medium fertility variant).;Including Crimea."
## [89] "Projected estimate (medium fertility variant).;Including East Jerusalem."
## [90] "Projected estimate (medium fertility variant).;Including Falkland Islands (Malvinas)."
## [91] "Projected estimate (medium fertility variant).;Including Liechtenstein and Monaco."
## [92] "Projected estimate (medium fertility variant).;Including Marshall Islands, Nauru, Northern Mariana Islands and Palau."
## [93] "Projected estimate (medium fertility variant).;Including Nagorno-Karabakh."
## [94] "Projected estimate (medium fertility variant).;Including Pitcairn."
## [95] "Projected estimate (medium fertility variant).;Including Sabah and Sarawak."
## [96] "Projected estimate (medium fertility variant).;Including Saint Helena."
## [97] "Projected estimate (medium fertility variant).;Including Svalbard and Jan Mayen Islands."
## [98] "Projected estimate (medium fertility variant).;Including the Faroe Islands and the Isle of Man."
## [99] "Projected estimate (medium fertility variant).;Including the Transnistria region."
## [100] "Projected estimate (medium fertility variant).;Including Zanzibar."
## [101] "Projected estimate (medium fertility variant).;Refers to the United Kingdom of Great Britain and Northern Ireland. For statistical purposes, the data for United Kingdom do not include Anguilla, Bermuda, British Virgin Islands, Cayman Islands, Channel Islands, Falkland Islands (Malvinas), Gibraltar, Isle of Man, Montserrat, Saint Helena, Turks and Caicos Islands."
## [102] "Projected estimate (medium fertility variant).;Refers to the whole country."
## [103] "Refers to Guernsey and Jersey."
## [104] "Refers to habitable area. Excludes Saint Lucia's Forest Reserve."
## [105] "Refers to the United Kingdom of Great Britain and Northern Ireland. For statistical purposes, the data for United Kingdom do not include Anguilla, Bermuda, British Virgin Islands, Cayman Islands, Channel Islands, Falkland Islands (Malvinas), Gibraltar, Isle of Man, Montserrat, Saint Helena, Turks and Caicos Islands."
## [106] "Refers to the whole country."
## [107] "Surface area is 0.44 Km2."
## [108] "Surface area is based on the 2002 population and housing census."
## [109] "The land area of Singapore comprises the mainland and other islands."
## [110] "The total area includes continental areas and islands, and excludes Antarctic area."
## [111] "The total surface is 21 040.79 square kilometres, without taking into account the last ruling of The Hague."
La variable Footnotes
, es de tipo character
e incluye posibles observaciones asociadas a algunos datos.
## [1] "United Nations Population Division, New York, World Population Prospects: The 2022 Revision, last accessed July 2022."
## [2] "United Nations Population Division, New York, World Population Prospects: The 2022 Revision; supplemented by data from the United Nations Statistics Division, New York, Demographic Yearbook 2020 and Secretariat for the Pacific Community (SPC) for small countries or areas, last accessed July 2022."
## [3] "United Nations Statistics Division, New York, \"Demographic Yearbook 2020\" and the demographic statistics database, last accessed June 2022."
La variable source
determina el nombre de la fuente de la cual se ha obtenido el dato de cada registro
Concluimos que la tabla nos da un dato, de tipo numérico, por países y periodos temporales, sobre algunos aspectos demográficos y su superficie. Se da información sobre 5 periodos temporales en concreto. En función de que lo queramos hacer, es posible que tengamos que hacer una coerción para cambiar el tipo de algunas variables como el año a tipo Date
, o las variables que se usan para clasificar a tipo factor
.
Formato TSV
El formato TSV (Tab-separated values) es un formato similar al CSV donde se usan tabuladores para separar los datos. Para leer ficheros TSV utilizaremos la función read_tsv
. Veamos un ejemplo con datos de una consulta al ISTAC sobre la renta media disponible de los habitantes de los municipios canarios. Utilizamos las funciones str
y levels(as.factor())
para hacer un primer análisis de la tabla y observamos que contiene datos de toda Canarias, por islas, y por municipios. Los datos van del 2013 al 2021 y para cada lugar y año suministra el dato de renta disponible y otros datos relativos a la variación de dicha renta.
ISTAC_RentaDisponible <- read_tsv("https://ctim.es/AEDV/data/ISTAC_RentaDisponibleMunicipios.tsv")%>%
as_tibble()
str(ISTAC_RentaDisponible)
## tibble [4,320 × 7] (S3: tbl_df/tbl/data.frame)
## $ GEOGRAPHICAL : chr [1:4320] "Canarias" "Canarias" "Canarias" "Canarias" ...
## $ GEOGRAPHICAL_CODE: chr [1:4320] "CCAA_CANARIAS" "CCAA_CANARIAS" "CCAA_CANARIAS" "CCAA_CANARIAS" ...
## $ TIME : num [1:4320] 2021 2021 2021 2021 2021 ...
## $ TIME_CODE : num [1:4320] 2021 2021 2021 2021 2021 ...
## $ MEASURE : chr [1:4320] "Tasa variación interperiódica" "Variación interperiódica" "Variación anual" "Tasa variación anual" ...
## $ MEASURE_CODE : chr [1:4320] "INTERPERIOD_PERCENTAGE_RATE" "INTERPERIOD_PUNTUAL_RATE" "ANNUAL_PUNTUAL_RATE" "ANNUAL_PERCENTAGE_RATE" ...
## $ OBS_VALUE : chr [1:4320] "4.06" "810.84" "810.84" "4.06" ...
## [1] "Adeje" "Agaete"
## [3] "Agüimes" "Agulo"
## [5] "Alajeró" "Antigua"
## [7] "Arafo" "Arico"
## [9] "Arona" "Arrecife"
## [11] "Artenara" "Arucas"
## [13] "Barlovento" "Betancuria"
## [15] "Breña Alta" "Breña Baja"
## [17] "Buenavista del Norte" "Canarias"
## [19] "Candelaria" "El Hierro (Isla)"
## [21] "El Paso" "El Pinar de El Hierro"
## [23] "El Rosario" "El Sauzal"
## [25] "El Tanque" "Fasnia"
## [27] "Firgas" "Frontera"
## [29] "Fuencaliente de La Palma" "Fuerteventura (Isla)"
## [31] "Gáldar" "Garachico"
## [33] "Garafía" "Gran Canaria (Isla)"
## [35] "Granadilla de Abona" "Guía de Isora"
## [37] "Güímar" "Haría"
## [39] "Hermigua" "Icod de los Vinos"
## [41] "Ingenio" "La Aldea de San Nicolás"
## [43] "La Gomera (Isla)" "La Guancha"
## [45] "La Matanza de Acentejo" "La Oliva"
## [47] "La Orotava" "La Palma (Isla)"
## [49] "La Victoria de Acentejo" "Lanzarote (Isla)"
## [51] "Las Palmas de Gran Canaria" "Los Llanos de Aridane"
## [53] "Los Realejos" "Los Silos"
## [55] "Mogán" "Moya"
## [57] "Pájara" "Puerto de La Cruz"
## [59] "Puerto del Rosario" "Puntagorda"
## [61] "Puntallana" "San Andrés y Sauces"
## [63] "San Bartolomé" "San Bartolomé de Tirajana"
## [65] "San Cristóbal de La Laguna" "San Juan de la Rambla"
## [67] "San Miguel de Abona" "San Sebastián de La Gomera"
## [69] "Santa Brígida" "Santa Cruz de La Palma"
## [71] "Santa Cruz de Tenerife" "Santa Lucía de Tirajana"
## [73] "Santa María de Guía de Gran Canaria" "Santa Úrsula"
## [75] "Santiago del Teide" "Tacoronte"
## [77] "Tazacorte" "Tegueste"
## [79] "Teguise" "Tejeda"
## [81] "Telde" "Tenerife (Isla)"
## [83] "Teror" "Tías"
## [85] "Tijarafe" "Tinajo"
## [87] "Tuineje" "Valle Gran Rey"
## [89] "Vallehermoso" "Valleseco"
## [91] "Valsequillo de Gran Canaria" "Valverde"
## [93] "Vega de San Mateo" "Vilaflor de Chasna"
## [95] "Villa de Mazo" "Yaiza"
## [1] "2013" "2014" "2015" "2016" "2017" "2018" "2019" "2020" "2021"
## [1] "Dato" "Tasa variación anual"
## [3] "Tasa variación interperiódica" "Variación anual"
## [5] "Variación interperiódica"
Formato EXCEL
Para leer hojas de cálculo excel utilizaremos la librería openxlsx
que permite leer archivos alojados localmente o en un servidor web. Como ejemplo vamos a leer datos publicados por la OWID. Podemos leer los datos de la OWID directamente en su servidor web usando un script como el siguiente:
df <- read.xlsx("https://nyc3.digitaloceanspaces.com/owid-public/data/co2/owid-co2-data.xlsx",sheet=1)
sin embargo, como la base de datos es muy grande y toma bastante tiempo leerla por Internet, hemos guardado algunos datos simplificados sobre la población por países en nuestro repositorio local data
.
Esta tabla está organizada de forma más sencilla que la tabla UN_population
y simplemente con la función str()
podemos identificar como está organizada y su contenido:
## tibble [237 × 17] (S3: tbl_df/tbl/data.frame)
## $ iso_code : chr [1:237] "ABW" "AFG" "AGO" "AIA" ...
## $ location : chr [1:237] "Aruba" "Afghanistan" "Angola" "Anguilla" ...
## $ continent : chr [1:237] "North America" "Asia" "Africa" "North America" ...
## $ population : num [1:237] 106459 41128772 35588996 15877 2842318 ...
## $ median_age : num [1:237] 41.2 18.6 16.8 NA 38 NA 34 31.9 35.7 NA ...
## $ life_expectancy : num [1:237] 76.3 64.8 61.1 81.9 78.6 ...
## $ aged_65_older : num [1:237] 13.09 2.58 2.4 NA 13.19 ...
## $ aged_70_older : num [1:237] 7.45 1.34 1.36 NA 8.64 ...
## $ gdp_per_capit : num [1:237] 35974 1804 5819 NA 11803 ...
## $ extreme_poverty : num [1:237] NA NA NA NA 1.1 NA NA 0.6 1.8 NA ...
## $ cardiovasc_death_rat : num [1:237] NA 597 276 NA 304 ...
## $ diabetes_prevalence : num [1:237] 11.62 9.59 3.94 NA 10.08 ...
## $ female_smokers : num [1:237] NA NA NA NA 7.1 29 1.2 16.2 1.5 NA ...
## $ male_smokers : num [1:237] NA NA NA NA 51.2 37.8 37.4 27.7 52.1 NA ...
## $ handwashing_facilities : num [1:237] NA 37.7 26.7 NA NA ...
## $ hospital_beds_per_thousand: num [1:237] NA 0.5 NA NA 2.89 NA 1.2 5 4.2 NA ...
## $ human_development_index : num [1:237] NA 0.511 0.581 NA 0.795 0.868 0.89 0.845 0.776 NA ...
Concluimos que esta tabla nos da información por países de algunos indicadores. El código identificativo de los países (variable iso_code
), es de 3 letras, en lugar de 3 números como usaba la tabla anterior de UN. Esto supone un problema que habrá que resolver si queremos combinar las dos tablas. Nótese que la organización de esta tabla y la anterior es muy distinta. En esta, cada fila de la tabla contiene la información de todos los indicadores del país, cada uno de ellos corresponde a un campo distinto, y en la tabla anterior, cada fila contiene el dato de un solo indicador, y los nombres de los indicadores están en otro campo. Esta última organización (la de la tabla UN) se denomina tidy data
y hablaremos de ella con más detalle al final de este tema.
Formato PC-Axis
El formato PC-Axis, especializado en almacenar datos estadísticos, es el utilizado por el INE y el ISTAD para exportar datos. Se puede editar con cualquier editor de texto plano (como NOTEPAD). Para leer este formato de ficheros usamos la función read.px
de la librería pxR
. Vamos a continuación a leer datos de la población por municipios de las islas Canarias previamente almacenados en el repositorio local de datos data
a partir de una consulta realizada en el ISTAD.
istac_poblacion <- read.px("https://ctim.es/AEDV/data/PoblacionMunicipiosCanarios.px")%>%
as_tibble()
istac_poblacion %>%
print(n=5)
## # A tibble: 2,112 × 5
## Sexos Años Edades.año.a.año Municipios.por.islas value
## <fct> <fct> <fct> <fct> <dbl>
## 1 AMBOS SEXOS 2021 TOTAL CANARIAS 2172944
## 2 AMBOS SEXOS 2020 TOTAL CANARIAS 2175952
## 3 AMBOS SEXOS 2019 TOTAL CANARIAS 2153389
## 4 AMBOS SEXOS 2018 TOTAL CANARIAS 2127685
## 5 AMBOS SEXOS 2017 TOTAL CANARIAS 2108121
## # ℹ 2,107 more rows
## [1] "AMBOS SEXOS"
## [1] "2021" "2020" "2019" "2018" "2017" "2016" "2015" "2014" "2013" "2012"
## [11] "2011" "2010" "2009" "2008" "2007" "2006" "2005" "2004" "2003" "2002"
## [21] "2001" "2000"
## [1] "TOTAL"
## [1] "CANARIAS" "LANZAROTE"
## [3] "Arrecife" "Haría"
## [5] "San Bartolomé" "Teguise"
## [7] "Tías" "Tinajo"
## [9] "Yaiza" "FUERTEVENTURA"
## [11] "Antigua" "Betancuria"
## [13] "Oliva (La)" "Pájara"
## [15] "Puerto del Rosario" "Tuineje"
## [17] "GRAN CANARIA" "Agaete"
## [19] "Agüimes" "Artenara"
## [21] "Arucas" "Firgas"
## [23] "Gáldar" "Ingenio"
## [25] "Mogán" "Moya"
## [27] "Palmas de Gran Canaria (Las)" "San Bartolomé de Tirajana"
## [29] "Aldea de San Nicolás (La)" "Santa Brígida"
## [31] "Santa Lucía" "Santa María de Guía"
## [33] "Tejeda" "Telde"
## [35] "Teror" "Valsequillo"
## [37] "Valleseco" "Vega de San Mateo"
## [39] "TENERIFE" "Adeje"
## [41] "Arafo" "Arico"
## [43] "Arona" "Buenavista del Norte"
## [45] "Candelaria" "Fasnia"
## [47] "Garachico" "Granadilla de Abona"
## [49] "Guancha (La)" "Guía de Isora"
## [51] "Güimar" "Icod de Los Vinos"
## [53] "Laguna (La)" "Matanza de Acentejo (La)"
## [55] "Orotava (La)" "Puerto de La Cruz"
## [57] "Realejos (Los)" "Rosario (El)"
## [59] "San Juan de La Rambla" "San Miguel"
## [61] "Santa Cruz de Tenerife" "Santa Úrsula"
## [63] "Santiago del Teide" "Sauzal (El)"
## [65] "Silos (Los)" "Tacoronte"
## [67] "Tanque (El)" "Tegueste"
## [69] "Victoria de Acentejo (La)" "Vilaflor"
## [71] "LA GOMERA" "Agulo"
## [73] "Alajeró" "Hermigua"
## [75] "San Sebastián de La Gomera" "Valle Gran Rey"
## [77] "Vallehermoso" "LA PALMA"
## [79] "Barlovento" "Breña Alta"
## [81] "Breña Baja" "Fuencaliente"
## [83] "Garafía" "Llanos de Aridane (Los)"
## [85] "Paso (El)" "Puntagorda"
## [87] "Puntallana" "San Andrés y Sauces"
## [89] "Santa Cruz de La Palma" "Tazacorte"
## [91] "Tijarafe" "Villa de Mazo"
## [93] "EL HIERRO" "Frontera"
## [95] "Valverde" "Pinar de El Hierro (El)"
Concluimos que esta tabla nos da información sobre la población de los municipios de las Islas Canarias entre los años 2000 y 2021 incluyendo ambos sexos y sumando todas las edades. No aparece ningún código identificativo del municipio.
Las bases de datos del INE y el ISTAD se obtienen a partir de una consulta que se hace en su servidor web, y es la consulta la que genera el fichero con los datos. Podemos editar el fichero en modo texto para ver algunos metadatos sobre la tabla que se pierden al cargarlos en un tibble
. Si la lectura de los ficheros PC-Axis falla, o genera problemas, siempre podemos descargar la consulta, en otro formato de fichero, por ejemplo en formato CSV, e intentar cargar los datos desde el fichero CSV.
Formato de texto
En ocasiones, cuando los datos vienen dados por un fichero de texto, no están organizados como una tabla y la lectura del fichero usando las funciones anteriormente vistas puede dar lugar a errores. En ese caso tenemos que corregir y actualizar el fichero antes de cargarlo como tabla. Esto se puede hacer abriendo el fichero con un editor de texto y manipularlo manualmente. Una forma alternativa, y automática, de hacerlo desde R
es usar la función read_lines
que carga el fichero de texto como un vector que contiene las líneas del fichero y que no asume que tenga un formato de tabla con campos y registros identificables. Podemos editar este vector y volver a escribirlo actualizado usando la función write_lines
.
UN_population2 <- read_lines("https://ctim.es/AEDV/data/UN_population.csv")
# eliminamos la primera línea
UN_population2 <- UN_population2[-1]
# sustituimos el string "Region/Country/Area" por "location"
UN_population2 <- gsub('Region/Country/Area','location',UN_population2)
# eliminamos todas las líneas que contienen el string "Total"
UN_population2 <- UN_population2[str_detect(UN_population2,"Total")==FALSE]
# escribimos el archivo actualizado
write_lines(UN_population2,"UN_population2.csv")
Formato ZIP
la librería readl
permite gestionar ficheros comprimidos con ZIP almacenados localmente (no alojados en un servidor). Veamos un ejemplo con datos del fichero “data/UNCTAD.zip” obtenidos del UNCTAD un organismo vinculado a las Naciones Unidas dedicado al Comercio y Desarrollo. Primero vamos a ver que documentos incluye este fichero zip:
## Name
## 1 US_GovExpenditures_ST202306281615_v1.csv
## 2 Glossary_Classification of the functions of government (COFOG) - Statistics Explained.pdf
## 3 UNCTADstat - Productive Capacities Index.pdf
## 4 WordlOfDebt_data.csv
## 5 Un mundo endeudado _ UNCTAD.pdf
## 6 US_PCI_20230704063200.csv
## Length Date
## 1 1890332 2023-09-18 11:25:00
## 2 670903 2023-09-01 10:56:00
## 3 2446315 2023-09-01 10:50:00
## 4 4248979 2023-09-01 11:19:00
## 5 659704 2023-09-01 11:25:00
## 6 3717173 2023-07-18 17:38:00
Observamos que este fichero zip incluye 3 ficheros CSV con datos y 3 documentos PDF explicativos. Vamos a abrir uno de los ficheros de datos:
WordlOfDebt_data <- read_csv(unzip("../data/UNCTAD.zip", "WordlOfDebt_data.csv")) %>%
as_tibble()
str(WordlOfDebt_data)
## tibble [28,455 × 10] (S3: tbl_df/tbl/data.frame)
## $ ID : chr [1:28455] "AF" "AL" "DZ" "AO" ...
## $ Name : chr [1:28455] "Afghanistan" "Albania" "Algeria" "Angola" ...
## $ Region : chr [1:28455] "Developing Asia and Oceania" "Europe and Central Asia*" "Africa" "Africa" ...
## $ World Bank income group: chr [1:28455] "Low income countries" "Upper middle income countries" "Lower middle income countries" "Lower middle income countries" ...
## $ Development status : chr [1:28455] "Developing countries" "Developed countries" "Developing countries" "Developing countries" ...
## $ LDC : num [1:28455] 1 0 0 1 0 0 0 0 0 0 ...
## $ SIDS : num [1:28455] 0 0 0 0 1 0 0 0 0 0 ...
## $ Indicator : chr [1:28455] "Public debt as a share of GDP" "Public debt as a share of GDP" "Public debt as a share of GDP" "Public debt as a share of GDP" ...
## $ Year : chr [1:28455] "2010" "2010" "2010" "2010" ...
## $ Value : num [1:28455] 0.077 0.577 0.105 0.372 0.897 ...
## [1] "Africa" "Developing Asia and Oceania"
## [3] "Europe and Central Asia*" "Latin America and the Caribbean"
## [1] "High income countries" "Low income countries"
## [3] "Lower middle income countries" "Upper middle income countries"
## [1] "Developed countries" "Developing countries"
## [1] "Bilateral creditors as a share of external public debt"
## [2] "External public debt as a share of GDP"
## [3] "External public debt in US$ billions"
## [4] "External public debt in US$ per capita"
## [5] "Multilateral creditors as a share of external public debt"
## [6] "Private creditors as a share of external public debt"
## [7] "Public debt as a share of GDP"
## [8] "Public debt in US$ billions"
## [9] "Public debt in US$ per capita"
## [10] "Public debt interest payments as a share of GDP"
## [11] "Public debt interest payments as a share of revenues"
## [12] "Public debt interest payments in US$ per capita"
## [13] "Public education expenditure as a share of GDP"
## [14] "Public health expenditure as share of GDP"
## [15] "Public investment expenditure as a share of GDP"
## [16] "Ratio of public interest payments to education expenditure"
## [17] "Ratio of public interest payments to health expenditure"
## [18] "Ratio of public interest payments to investment expenditure"
## [1] "2010" "2010-2012" "2011" "2012" "2013" "2014"
## [7] "2014-2016" "2015" "2016" "2017" "2018" "2019"
## [13] "2019-2021" "2020" "2021" "2022"
Concluimos que esta tabla suministra información por países y años (en ocasiones agrupados) de algunos indicadores sobre su deuda. Además los países se clasifican por sus ingresos y nivel de desarrollo.
3.3 Transformación de datos
El paquete dplyr
El paquete dplyr
, que se encuentra dentro de la librería tidyverse
, se usa habitualmente para gestionar/transformar los datos. Como resumen de esta sección puede ser útil mirar la siguiente ficha resumen. Veremos, a continuación, las funcionalidades más importantes de este paquete.
filter()
Filtra las filas de la tabla a partir de condiciones. Por ejemplo, con la siguiente instrucción filtramos los países de Europa con una población superior a los 40 millones de habitantes
## # A tibble: 6 × 17
## iso_code location continent population median_age life_expectancy
## <chr> <chr> <chr> <dbl> <dbl> <dbl>
## 1 DEU Germany Europe 83369840 46.6 81.3
## 2 ESP Spain Europe 47558632 45.5 83.6
## 3 FRA France Europe 67813000 42 82.7
## 4 GBR United Kingdom Europe 67508936 40.8 81.3
## 5 ITA Italy Europe 59037472 47.9 83.5
## 6 RUS Russia Europe 144713312 39.6 72.6
## # ℹ 11 more variables: aged_65_older <dbl>, aged_70_older <dbl>,
## # gdp_per_capit <dbl>, extreme_poverty <dbl>, cardiovasc_death_rat <dbl>,
## # diabetes_prevalence <dbl>, female_smokers <dbl>, male_smokers <dbl>,
## # handwashing_facilities <dbl>, hospital_beds_per_thousand <dbl>,
## # human_development_index <dbl>
Con la función str_detect
podemos filtrar la tabla a partir del contenido de un campo de strings. Por ejemplo, a continuación filtramos los países del mundo cuyo nombre contiene el string “ma” (sin tener en cuenta mayúsculas o minúsculas)
## # A tibble: 29 × 17
## iso_code location continent population median_age life_expectancy
## <chr> <chr> <chr> <dbl> <dbl> <dbl>
## 1 BHS Bahamas North Am… 409989 34.3 73.9
## 2 CYM Cayman Islands North Am… 68722 NA 83.9
## 3 DEU Germany Europe 83369840 46.6 81.3
## 4 DNK Denmark Europe 5882259 42.3 80.9
## 5 GTM Guatemala North Am… 17843914 22.9 74.3
## 6 IMN Isle of Man Europe 84534 NA 81.4
## 7 JAM Jamaica North Am… 2827382 31.4 74.5
## 8 MAC Macao Asia 695180 39.2 84.2
## 9 MAF Saint Martin (Frenc… North Am… 31816 NA 82.1
## 10 MDG Madagascar Africa 29611718 19.6 67.0
## # ℹ 19 more rows
## # ℹ 11 more variables: aged_65_older <dbl>, aged_70_older <dbl>,
## # gdp_per_capit <dbl>, extreme_poverty <dbl>, cardiovasc_death_rat <dbl>,
## # diabetes_prevalence <dbl>, female_smokers <dbl>, male_smokers <dbl>,
## # handwashing_facilities <dbl>, hospital_beds_per_thousand <dbl>,
## # human_development_index <dbl>
select()
Selecciona algunos campos de la tabla. Los campos se pueden seleccionar individualmente
o por grupos usando el símbolo :
.
owid_country %>%
filter(continent=="Europe" & population>4e7) %>%
arrange(desc(population)) %>%
select(location,life_expectancy:gdp_per_capit)
## # A tibble: 6 × 5
## location life_expectancy aged_65_older aged_70_older gdp_per_capit
## <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Russia 72.6 14.2 9.39 24766.
## 2 Germany 81.3 21.5 16.0 45229.
## 3 France 82.7 19.7 13.1 38606.
## 4 United Kingdom 81.3 18.5 12.5 39753.
## 5 Italy 83.5 23.0 16.2 35220.
## 6 Spain 83.6 19.4 13.8 34272.
select
también sirve para quitar campos de la tabla poniendo delante del campo
el signo -
owid_country %>%
filter(continent=="Europe" & population>4e7) %>%
arrange(desc(population)) %>%
select(-iso_code,-continent)
## # A tibble: 6 × 15
## location population median_age life_expectancy aged_65_older aged_70_older
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Russia 144713312 39.6 72.6 14.2 9.39
## 2 Germany 83369840 46.6 81.3 21.5 16.0
## 3 France 67813000 42 82.7 19.7 13.1
## 4 United King… 67508936 40.8 81.3 18.5 12.5
## 5 Italy 59037472 47.9 83.5 23.0 16.2
## 6 Spain 47558632 45.5 83.6 19.4 13.8
## # ℹ 9 more variables: gdp_per_capit <dbl>, extreme_poverty <dbl>,
## # cardiovasc_death_rat <dbl>, diabetes_prevalence <dbl>,
## # female_smokers <dbl>, male_smokers <dbl>, handwashing_facilities <dbl>,
## # hospital_beds_per_thousand <dbl>, human_development_index <dbl>
arrange()
Ordena la tabla a partir de uno o varios campos
owid_country %>%
filter(continent=="Europe" & population>4e7) %>%
arrange(desc(population)) # desc() se usa para ordenar en forma descendente.
## # A tibble: 6 × 17
## iso_code location continent population median_age life_expectancy
## <chr> <chr> <chr> <dbl> <dbl> <dbl>
## 1 RUS Russia Europe 144713312 39.6 72.6
## 2 DEU Germany Europe 83369840 46.6 81.3
## 3 FRA France Europe 67813000 42 82.7
## 4 GBR United Kingdom Europe 67508936 40.8 81.3
## 5 ITA Italy Europe 59037472 47.9 83.5
## 6 ESP Spain Europe 47558632 45.5 83.6
## # ℹ 11 more variables: aged_65_older <dbl>, aged_70_older <dbl>,
## # gdp_per_capit <dbl>, extreme_poverty <dbl>, cardiovasc_death_rat <dbl>,
## # diabetes_prevalence <dbl>, female_smokers <dbl>, male_smokers <dbl>,
## # handwashing_facilities <dbl>, hospital_beds_per_thousand <dbl>,
## # human_development_index <dbl>
mutate()
Calcula campos nuevos o modifica campos existentes pudiendo usar los campos de la tabla.
owid_country %>%
mutate( gdp = gdp_per_capit * population) %>%
select(location,population,gdp) %>%
arrange(desc(gdp)) %>%
head(10) %>%
knitr::kable( caption = "Países ordenados por su PIB",format = "html",table.attr = "style='width:60%;'")
location | population | gdp |
---|---|---|
China | 1425887360 | 2.182850e+13 |
United States | 338289856 | 1.834392e+13 |
India | 1417173120 | 9.107710e+12 |
Japan | 123951696 | 4.834392e+12 |
Germany | 83369840 | 3.770755e+12 |
Russia | 144713312 | 3.583963e+12 |
Indonesia | 275501344 | 3.082514e+12 |
Brazil | 215313504 | 3.036664e+12 |
United Kingdom | 67508936 | 2.683699e+12 |
France | 67813000 | 2.617966e+12 |
relocate()
Cambia el orden de las columnas
owid_country %>%
relocate(location) %>% # pone location en primer lugar
relocate(continent,.after=location) %>%
relocate(life_expectancy,.after=continent) %>%
print(n=5)
## # A tibble: 237 × 17
## location continent life_expectancy iso_code population median_age
## <chr> <chr> <dbl> <chr> <dbl> <dbl>
## 1 Aruba North America 76.3 ABW 106459 41.2
## 2 Afghanistan Asia 64.8 AFG 41128772 18.6
## 3 Angola Africa 61.2 AGO 35588996 16.8
## 4 Anguilla North America 81.9 AIA 15877 NA
## 5 Albania Europe 78.6 ALB 2842318 38
## # ℹ 232 more rows
## # ℹ 11 more variables: aged_65_older <dbl>, aged_70_older <dbl>,
## # gdp_per_capit <dbl>, extreme_poverty <dbl>, cardiovasc_death_rat <dbl>,
## # diabetes_prevalence <dbl>, female_smokers <dbl>, male_smokers <dbl>,
## # handwashing_facilities <dbl>, hospital_beds_per_thousand <dbl>,
## # human_development_index <dbl>
rename()
Cambia el nombre de los campos
owid_country %>%
filter(continent=="Europe" & population>4e7) %>%
arrange(desc(population)) %>%
select(location,population,median_age) %>%
rename(country = location)%>%
knitr::kable( caption = "Países europeos ordenados por su población",format = "html",table.attr = "style='width:60%;'")
country | population | median_age |
---|---|---|
Russia | 144713312 | 39.6 |
Germany | 83369840 | 46.6 |
France | 67813000 | 42.0 |
United Kingdom | 67508936 | 40.8 |
Italy | 59037472 | 47.9 |
Spain | 47558632 | 45.5 |
str_replace
Esta función reemplaza un string por otro dentro de un vector de strings
## # A tibble: 20 × 17
## iso_code location continent population median_age life_expectancy
## <chr> <chr> <chr> <dbl> <dbl> <dbl>
## 1 TWN Taiwan Asia 23893396 42.2 80.5
## 2 TZA Tanzania Africa 65497752 17.7 65.5
## 3 UGA Uganda Africa 47249588 16.4 63.4
## 4 UKR Ukraine Europe 39701744 41.4 72.1
## 5 URY Uruguay South Am… 3422796 35.6 77.9
## 6 USA USA North Am… 338289856 38.3 78.9
## 7 UZB Uzbekistan Asia 34627648 28.2 71.7
## 8 VAT Vatican Europe 808 NA 75.1
## 9 VCT Saint Vincent and t… North Am… 103959 31.8 72.5
## 10 VEN Venezuela South Am… 28301700 29 72.1
## 11 VGB British Virgin Isla… North Am… 31332 NA 79.1
## 12 VIR USA Virgin Islands North Am… 99479 42.2 80.6
## 13 VNM Vietnam Asia 98186856 32.6 75.4
## 14 VUT Vanuatu Oceania 326744 23.1 70.5
## 15 WLF Wallis and Futuna Oceania 11596 NA 79.9
## 16 WSM Samoa Oceania 222390 22 73.3
## 17 YEM Yemen Asia 33696612 20.3 66.1
## 18 ZAF South Africa Africa 59893884 27.3 64.1
## 19 ZMB Zambia Africa 20017670 17.7 63.9
## 20 ZWE Zimbabwe Africa 16320539 19.6 61.5
## # ℹ 11 more variables: aged_65_older <dbl>, aged_70_older <dbl>,
## # gdp_per_capit <dbl>, extreme_poverty <dbl>, cardiovasc_death_rat <dbl>,
## # diabetes_prevalence <dbl>, female_smokers <dbl>, male_smokers <dbl>,
## # handwashing_facilities <dbl>, hospital_beds_per_thousand <dbl>,
## # human_development_index <dbl>
Para cambiar un valor en todo el tibble
podemos hacer:
owid_country[owid_country=="United States"] <- "USA"
owid_country%>%
select(iso_code,location)%>%
filter(location=="USA")
## # A tibble: 1 × 2
## iso_code location
## <chr> <chr>
## 1 USA USA
group_by() y summarise()
group_by
agrupa los registros por uno o varios campos y posteriormente summarise
nos permite hacer operaciones sobre los agrupamientos obtenidos. La variable sobre la que se realiza el agrupamiento siempre aparece en el resultado de summarise
. En el siguiente ejemplo se calcula el PIB por habitante agrupándolo por continentes. Es decir, el dato de cada país se asocia al grupo que comparte el mismo continente.
owid_country %>%
group_by(continent) %>%
summarise(
populationContinent=sum(population),
gdp_per_capita=sum(na.omit(gdp_per_capit*population))/populationContinent
) %>%
arrange(desc(gdp_per_capita)) %>%
knitr::kable( caption = "PIB per capita",format = "html",table.attr = "style='width:40%;'")
continent | populationContinent | gdp_per_capita |
---|---|---|
North America | 600323657 | 38468.345 |
Europe | 745629155 | 32792.373 |
Oceania | 45038907 | 31272.576 |
South America | 436816679 | 14519.141 |
Asia | 4721455390 | 12148.167 |
Africa | 1426736614 | 4544.862 |
En este caso se ha utilizado la función sum
dentro del summarise
para que el resultado sea la suma de los valores de los países de cada continente, se pueden utilizar otras funciones como min
, max
, mean
, median
, sd
, first
, last
, prod
o n
(número de valores del vector). Dentro del summarise
siempre hay que usar funciones que generen, para cada grupo, un único valor a partir de los elementos del grupo.
Combinando datos de varias tablas
Con frecuencia hay que combinar la información de varias tablas. El tipo de combinación que usaremos aquí es el “left_join” que mantiene todos los registros de la primera tabla combinándolos con los de la segunda tabla. Como primer ejemplo vamos a combinar dos tablas de la OWID utilizando como campo común iso_code
, que es un código de 3 letras que identifica a cada país. Para ello utilizaremos la función left_join
de la librería dplyr
.
## # A tibble: 41,294 × 95
## iso_code location continent population.x median_age life_expectancy
## <chr> <chr> <chr> <dbl> <dbl> <dbl>
## 1 ABW Aruba North America 106459 41.2 76.3
## 2 ABW Aruba North America 106459 41.2 76.3
## 3 ABW Aruba North America 106459 41.2 76.3
## 4 ABW Aruba North America 106459 41.2 76.3
## 5 ABW Aruba North America 106459 41.2 76.3
## 6 ABW Aruba North America 106459 41.2 76.3
## 7 ABW Aruba North America 106459 41.2 76.3
## 8 ABW Aruba North America 106459 41.2 76.3
## 9 ABW Aruba North America 106459 41.2 76.3
## 10 ABW Aruba North America 106459 41.2 76.3
## # ℹ 41,284 more rows
## # ℹ 89 more variables: aged_65_older <dbl>, aged_70_older <dbl>,
## # gdp_per_capit <dbl>, extreme_poverty <dbl>, cardiovasc_death_rat <dbl>,
## # diabetes_prevalence <dbl>, female_smokers <dbl>, male_smokers <dbl>,
## # handwashing_facilities <dbl>, hospital_beds_per_thousand <dbl>,
## # human_development_index <dbl>, country <chr>, year <dbl>,
## # population.y <dbl>, gdp <dbl>, cement_co2 <dbl>, …
La instrucción by = "iso_code"
es equivalente a join_by(iso_code == iso_code)
. La segunda tiene la ventaja de que podríamos usar un campo común con diferentes nombres en ambas tablas.
La función left_join
solo funciona cuando el campo común en ambas tablas es idéntico, si el campo común es un string (por ejemplo el nombre de un municipio) puede haber pequeñas diferencias al escribir el municipio en ambas tablas lo que hace que la comparación falle. Lo ideal es que en todas las tablas, cada registro se acompañe
de un código identificativo único y universal. Por ejemplo, el INE utiliza un código identificativo para cada municipio, pero desafortunadamente, este código no acompaña
sistemáticamente a las tablas que resultan de hacer una consulta en el INE o en el ISTAC relacionada con municipios. Y lo que es peor, los nombres de los municipios pueden cambiar ligeramente de una consulta a otra, y por tanto, usar el nombre del municipio como identificador puede causar problemas. Para resolver
estos problemas, lo primero que hay que hacer al leer una tabla del INE o ISTAC, es intentar asociarle el código identificativo universal del INE a partir del nombre del municipio (si estamos gestionando municipios). Los códigos INE de los municipios los tomaremos de la siguiente tabla que filtramos para quedarnos solo con los municipios canarios.
uclm_mun <- read.xlsx("https://ctim.es/AEDV/data/uclm-list-mun-2012.xlsx",sheet=1) %>%
as_tibble() %>% filter(CA=="05")
uclm_mun %>%
str()
## tibble [88 × 11] (S3: tbl_df/tbl/data.frame)
## $ codine : chr [1:88] "35001" "35002" "35003" "35004" ...
## $ Municipio : chr [1:88] "Agaete" "Agüimes" "Antigua" "Arrecife" ...
## $ Superficie : num [1:88] 45.5 79.3 250.6 22.7 66.7 ...
## $ Capitalidad : chr [1:88] "Agaete" "Agüimes" "Antigua" "Arrecife" ...
## $ Año : num [1:88] NA NA NA NA NA NA NA NA NA NA ...
## $ CA : chr [1:88] "05" "05" "05" "05" ...
## $ Autonomía : chr [1:88] "Canarias" "Canarias" "Canarias" "Canarias" ...
## $ CP : chr [1:88] "35" "35" "35" "35" ...
## $ Provincia : chr [1:88] "Palmas (Las)" "Palmas (Las)" "Palmas (Las)" "Palmas (Las)" ...
## $ CPJ : chr [1:88] "3504" "3508" "3503" "3501" ...
## $ Partido_Judicial: chr [1:88] "Santa María de Guía de Gran Canaria" "Santa Lucía de Tirajana" "Puerto del Rosario" "Arrecife" ...
A continuación vamos a leer una tabla del ISTAC sobre municipios. Hemos modificado la tabla original añadiendo campos con los nombres de algunos municipios ligeramente cambiados para tener varias opciones a la hora de comparar los nombres: :
istac_municipios <- read.xlsx("https://ctim.es/AEDV/data/istac_municipios.xlsx") %>%
as_tibble()
istac_municipios %>%
filter(is.na(nombre3)==FALSE) %>%
print(n=10)
## # A tibble: 19 × 5
## nombre nombre2 nombre3 isla superficie
## <chr> <chr> <chr> <chr> <dbl>
## 1 Aldea de San Nicolás (La) La Aldea de San Nicolás La Ald… Gran… 124.
## 2 Palmas de Gran Canaria (Las) Las Palmas de Gran Can… Las Pa… Gran… 101.
## 3 Llanos de Aridane (Los) Los Llanos de Aridane Los Ll… La P… 35.8
## 4 Puerto de la Cruz <NA> P. de … Tene… 8.73
## 5 Puerto del Rosario <NA> P. del… Fuer… 290.
## 6 San Andrés y Sauces <NA> S. And… La P… 42.8
## 7 San Bartolomé <NA> S. Bar… Lanz… 40.9
## 8 San Bartolomé de Tirajana San Bartolomé de Tiraj… S. B. … Gran… 333.
## 9 San Cristóbal de La Laguna <NA> La Lag… Tene… 102.
## 10 San Juan de la Rambla <NA> S.J. d… Tene… 20.7
## # ℹ 9 more rows
Como la tabla istac_municipios
no tiene el código INE, vamos a añadírselo. Para ello, en primer lugar, vamos a comprobar si a través de los nombres de los municipios en ambas tablas es posible encontrar un “matching” sin fallos entre las dos tablas. Para ello vamos a usar la función LeftJoinNearestString
implementada por nosotros en el fichero utilidades.R que hace un “left join” entre dos tibbles de strings u
y v
que se corresponden con los posibles nombres que vamos a comparar en las 2 tablas usando la función adist
, Esta función devuelve un tibble con los siguientes campos:
pos1
: índices de los registros (filas) de la tablau
pos2
: índices de los registros en la tablav
que menor distancia tiene con el de la tablau
. Es decir el mejor matching de la filapos1[k]
en la primera tabla se encuentra en la filapos2[k]
de la segunda tabla.value1
: el string dentro de la tablau
que más se parece al de la tablav
value2
: el string dentro de la tablav
que más se parece al de la tablau
dis
: la distancia entre los strings
value1y
value2`
Esta función tiene como parámetros adicionales, los parámetros ignore.case
y partial
que por defecto están asignados como ignore.case=FALSE
y partial=FALSE
, pero que pueden modificarse añadiéndolos en la llamada a la función.
Nótese que esta función no genera las tablas combinadas, pero con los campos pos1
y pos2
podemos poner en correspondencia los registros de una tabla y otra. Por tanto, a partir de esta información podemos combinar las tablas como nos interese. La función `LeftJoinNearestString tiene un elevado coste computacional y solo sirve para bases de datos relativamente pequeñas. Si se aplica en tablas con muchos registros puede tardar mucho.
Hay que tener en cuenta que la comparación puede fallar y por tanto es conveniente verificar y corregir los resultados. A continuación hacemos el “matching” entre los nombres de los municipios en ambas tablas e imprimimos los resultados de los que tienen una distancia mayor que cero.
source("utilidades.R")
res <- LeftJoinNearestString(istac_municipios%>%select(nombre:nombre3),uclm_mun%>%select(Municipio))
res%>%
arrange(desc(dis)) %>%
filter(dis>0) %>%
print(n=100)
## # A tibble: 15 × 5
## pos1 pos2 value1 value2 dis
## <int> <dbl> <chr> <chr> <dbl>
## 1 50 88 Pinar del Hierro (El) Pinar de El Hierro, El 5
## 2 19 61 Paso (El) Paso, El 3
## 3 20 66 Rosario (El) Rosario, El 3
## 4 21 75 Sauzal (El) Sauzal, El 3
## 5 22 78 Tanque (El) Tanque, El 3
## 6 37 20 Aldea de San Nicolás (La) Aldea de San Nicolás, La 3
## 7 38 52 Guancha (La) Guancha, La 3
## 8 39 59 Matanza de Acentejo (La) Matanza de Acentejo, La 3
## 9 40 14 Oliva (La) Oliva, La 3
## 10 41 60 Orotava (La) Orotava, La 3
## 11 42 85 Victoria de Acentejo (La) Victoria de Acentejo, La 3
## 12 43 16 Palmas de Gran Canaria (Las) Palmas de Gran Canaria, Las 3
## 13 44 58 Llanos de Aridane (Los) Llanos de Aridane, Los 3
## 14 45 65 Realejos (Los) Realejos, Los 3
## 15 46 76 Silos (Los) Silos, Los 3
Observamos, inspeccionando el resultado, que el matching no tiene fallos y procedemos a añadir un campo a istac_municipios
con el código de cada municipio.
istac_municipios$ine_code <- NA
for(i in 1:nrow(istac_municipios) ){
istac_municipios$ine_code[i] <- uclm_mun$codine[res$pos2[i]]
}
istac_municipios %>%
relocate(ine_code)
## # A tibble: 88 × 6
## ine_code nombre nombre2 nombre3 isla superficie
## <chr> <chr> <chr> <chr> <chr> <dbl>
## 1 38001 Adeje <NA> <NA> Tenerife 106.
## 2 35001 Agaete <NA> <NA> Gran Canaria 45.5
## 3 35002 Agüimes <NA> <NA> Gran Canaria 79.3
## 4 38002 Agulo <NA> <NA> La Gomera 25.4
## 5 38003 Alajeró <NA> <NA> La Gomera 49.4
## 6 35003 Antigua <NA> <NA> Fuerteventura 251.
## 7 38004 Arafo <NA> <NA> Tenerife 33.9
## 8 38005 Arico <NA> <NA> Tenerife 179.
## 9 38006 Arona <NA> <NA> Tenerife 81.8
## 10 35004 Arrecife <NA> <NA> Lanzarote 22.7
## # ℹ 78 more rows
Vamos ahora a intentar hacer lo mismo para la tabla istac_poblacion
. Esta tabla tiene muchas filas con nombres de municipios que corresponden a diferentes años. La función LeftJoinNearestString
tiene un alto coste computacional por el uso intensivo de la función adist
. Para reducir este costo computacional se ha diseñado suponiendo que en cada una de las tablas que se compara, solo aparece una vez (por fila) el datos que se quiere comparar con la otra tabla. Por ello, para aplicarla a este ejemplo, primero crearemos una tabla con solo los nombres posibles de municipios, haremos el matching con esa tabla y después, con un left_join
normal extenderemos la combinación a toda la tabla. Previamente pasamos a character
el campo con el nombre del municipio porque la función LeftJoinNearestString
requiere que las columnas a comparar sean de ese tipo.
istac_poblacion_municipios <- istac_poblacion %>%
mutate(Municipios.por.islas=as.character(Municipios.por.islas)) %>%
group_by(Municipios.por.islas) %>%
summarise()
istac_poblacion_municipios
## # A tibble: 96 × 1
## Municipios.por.islas
## <chr>
## 1 Adeje
## 2 Agaete
## 3 Agulo
## 4 Agüimes
## 5 Alajeró
## 6 Aldea de San Nicolás (La)
## 7 Antigua
## 8 Arafo
## 9 Arico
## 10 Arona
## # ℹ 86 more rows
res <- LeftJoinNearestString(istac_poblacion_municipios,uclm_mun%>%select(Municipio))
res%>%
arrange(desc(dis)) %>%
filter(dis>0) %>%
print(n=100)
## # A tibble: 32 × 5
## pos1 pos2 value1 value2 dis
## <int> <dbl> <chr> <chr> <dbl>
## 1 22 8 FUERTEVENTURA Firgas 12
## 2 27 9 GRAN CANARIA Gáldar 11
## 3 41 12 LANZAROTE Mogán 9
## 4 19 8 CANARIAS Firgas 8
## 5 21 10 EL HIERRO Haría 8
## 6 39 13 LA GOMERA Moya 8
## 7 40 12 LA PALMA Mogán 8
## 8 42 14 Laguna (La) Oliva, La 8
## 9 63 73 San Miguel Santa Úrsula 7
## 10 74 24 TENERIFE Teguise 7
## 11 68 73 Santa Lucía Santa Úrsula 5
## 12 6 20 Aldea de San Nicolás (La) Aldea de San Nicolás, La 3
## 13 31 52 Guancha (La) Guancha, La 3
## 14 43 58 Llanos de Aridane (Los) Llanos de Aridane, Los 3
## 15 44 59 Matanza de Acentejo (La) Matanza de Acentejo, La 3
## 16 47 14 Oliva (La) Oliva, La 3
## 17 48 60 Orotava (La) Orotava, La 3
## 18 49 16 Palmas de Gran Canaria (Las) Palmas de Gran Canaria, Las 3
## 19 50 61 Paso (El) Paso, El 3
## 20 51 88 Pinar de El Hierro (El) Pinar de El Hierro, El 3
## 21 57 65 Realejos (Los) Realejos, Los 3
## 22 58 66 Rosario (El) Rosario, El 3
## 23 72 75 Sauzal (El) Sauzal, El 3
## 24 73 76 Silos (Los) Silos, Los 3
## 25 76 78 Tanque (El) Tanque, El 3
## 26 93 85 Victoria de Acentejo (La) Victoria de Acentejo, La 3
## 27 34 54 Güimar Güímar 1
## 28 37 56 Icod de Los Vinos Icod de los Vinos 1
## 29 52 62 Puerto de La Cruz Puerto de la Cruz 1
## 30 62 68 San Juan de La Rambla San Juan de la Rambla 1
## 31 64 70 San Sebastián de La Gomera San Sebastián de la Gomera 1
## 32 66 71 Santa Cruz de La Palma Santa Cruz de la Palma 1
En este caso, observamos que falla el matching en algunos casos. Lo que vamos a hacer para resolver esto es asignar manualmente NA
al vector res$pos2
, en las posiciones donde haya fallado. Es decir, primero, visualmente miramos donde falla y luego hacemos
En los municipios donde falla también podríamos haber manipulado las tablas para corregir el error. Una vez resuelto de esta manera añadimos como antes el código del municipio a la tabla istac_poblacion_municipios
istac_poblacion_municipios$ine_code <- NA
for(i in 1:nrow(istac_poblacion_municipios) ){
istac_poblacion_municipios$ine_code[i] <- uclm_mun$codine[res$pos2[i]]
}
istac_poblacion_municipios
## # A tibble: 96 × 2
## Municipios.por.islas ine_code
## <chr> <chr>
## 1 Adeje 38001
## 2 Agaete 35001
## 3 Agulo 38002
## 4 Agüimes 35002
## 5 Alajeró 38003
## 6 Aldea de San Nicolás (La) 35020
## 7 Antigua 35003
## 8 Arafo 38004
## 9 Arico 38005
## 10 Arona 38006
## # ℹ 86 more rows
Por último, hacemos un left_join
para añadir el código del municipio a toda la tabla istac_poblacion
## # A tibble: 2,112 × 6
## Sexos Años Edades.año.a.año Municipios.por.islas value ine_code
## <fct> <fct> <fct> <chr> <dbl> <chr>
## 1 AMBOS SEXOS 2002 TOTAL Betancuria 665 35007
## 2 AMBOS SEXOS 2001 TOTAL Betancuria 670 35007
## 3 AMBOS SEXOS 2000 TOTAL Betancuria 677 35007
## 4 AMBOS SEXOS 2009 TOTAL Betancuria 680 35007
## 5 AMBOS SEXOS 2006 TOTAL Betancuria 705 35007
## 6 AMBOS SEXOS 2017 TOTAL Betancuria 710 35007
## 7 AMBOS SEXOS 2015 TOTAL Betancuria 713 35007
## 8 AMBOS SEXOS 2016 TOTAL Betancuria 714 35007
## 9 AMBOS SEXOS 2008 TOTAL Betancuria 715 35007
## 10 AMBOS SEXOS 2003 TOTAL Betancuria 721 35007
## # ℹ 2,102 more rows
Tidy data (datos ordenados)
La misma información se puede organizar de muy diversas formas. Sin embargo, una buena organización requiere cumplir con ciertos criterios de la organización ordenada de datos “tidy data”. Estos criterios son esencialmente:
Cada variable (o campo) que mides debe corresponder a una única columna. Es decir las instancias de la misma variable no pueden estar asignadas a columnas distintas. Por ejemplo, en una tabla de datos de países, cada país no puede ser una columna distinta de la tabla, debe haber una única columna (por ejemplo país) y los nombres de cada país deben ser elementos de esa columna.
Cada fila solo puede contener el dato de una única observación acompañada de variables categóricas. En otras palabras, en cada fila puede haber varias variables categóricas (incluidas fechas) pero un único valor observado.
Debe haber una tabla distinta para cada “clase” de variable. Es decir no se pueden combinar datos heterogéneos en la misma tabla.
Si tienes múltiples tablas, debe existir una columna en cada tabla que permita enlazarlas.
Vamos a ilustrar este concepto con un ejemplo de un tibble de algunos datos de población (en millones) de España, Francia y Alemania
data <- tibble(
año=c(1985,2000,2015),
España=c(38.734,40.75,46.122),
Francia=c(55.38,59.387,64.395),
Alemania=c(77.57,81.896,80.689))
data%>%
knitr::kable( caption = "Tabla de datos no ordenados",format = "html",table.attr = "style='width:50%;'")
año | España | Francia | Alemania |
---|---|---|---|
1985 | 38.734 | 55.380 | 77.570 |
2000 | 40.750 | 59.387 | 81.896 |
2015 | 46.122 | 64.395 | 80.689 |
esta forma de organizar una tabla se usa con frecuencia porque es una manera natural en la escribiríamos los datos si lo hiciéramos a mano. Sin embargo no cumple con los criterios de “tidy data” porque los campos con los nombres de las países son instancias de la variable país, y por tanto las columnas de la tabla deberían ser año,país y población. La función pivot_longer
convierte automáticamente el tibble anterior en un tibble “ordenado” eliminando columnas y añadiendo filas:
data %>%
pivot_longer(c(`España`, `Francia`, `Alemania`), names_to = "country", values_to = "population")%>%
knitr::kable( caption = "Tabla de datos ordenados",format = "html",table.attr = "style='width:30%;'")
año | country | population |
---|---|---|
1985 | España | 38.734 |
1985 | Francia | 55.380 |
1985 | Alemania | 77.570 |
2000 | España | 40.750 |
2000 | Francia | 59.387 |
2000 | Alemania | 81.896 |
2015 | España | 46.122 |
2015 | Francia | 64.395 |
2015 | Alemania | 80.689 |
Una ventaja importante de los “tidy data” es que hay muchos procesos y funciones diseñados para trabajar con esta organización de la información. En particular, los procesos de visualización de datos requieren “tidy data”. En ocasiones es interesante hacer la operación contraria a pivot_longer
que es pivot_wider
que organiza
la tabla añadiendo columnas y quitando filas. Esto permite separar los campos y manejarlos individualmente :
data %>%
pivot_longer(c(`España`, `Francia`, `Alemania`), names_to = "country", values_to = "population") %>%
pivot_wider(names_from = country, values_from = population)
## # A tibble: 3 × 4
## año España Francia Alemania
## <dbl> <dbl> <dbl> <dbl>
## 1 1985 38.7 55.4 77.6
## 2 2000 40.8 59.4 81.9
## 3 2015 46.1 64.4 80.7
Observamos que hacer un pivot_longer
y a continuación un pivot_wider
nos lleva a la tabla original. Estas operaciones nos permiten manejar
la misma tabla en el formato que nos interese en cada momento.
Como resumen de esta sección puede ser útil mirar la siguiente ficha resumen.
La organización de las bases de datos públicas que usamos en este curso difiere bastante entre ellas. Por ejemplo las tablas de la OWID contienen muchas columnas con variables distintas y cada línea de la tabla es una observación de todas las variables para un país en una fecha concreta. Sin embargo, las tablas de la UN ponen una columna que contiene el nombre de la variable y una sola columna con el valor numérico para dicha variable, de tal manera que cada línea incluye únicamente la observación de una variable. Las bases del INE y el ISTAC tienen una organización similar a la de UN.
Combinando datos de UN y OWID
Las bases de datos de la OWID utilizan un código ISO (International Organization for Standardization) de 3 letras para identificar los países. Sin embargo las bases de datos de la UN utiliza su propia codificación. Para combinar tablas de las dos bases de datos utilizaremos una tabla que suministra las UN con las equivalencias entre diferentes códigos de países que nosotros hemos almacenado en el fichero “data/UN_code.xlsx”
UN_code <- read.xlsx("https://ctim.es/AEDV/data/UN_code.xlsx",sheet=1) %>%
as_tibble()
UN_code %>%
str()
## tibble [246 × 9] (S3: tbl_df/tbl/data.frame)
## $ ctyCode : num [1:246] 533 4 24 660 8 20 784 32 51 16 ...
## $ ISO_A2 : chr [1:246] "AW" "AF" "AO" "AI" ...
## $ ISO_A3 : chr [1:246] "ABW" "AFG" "AGO" "AIA" ...
## $ cty.Name.English : chr [1:246] "Aruba" "Afghanistan" "Angola" "Anguilla" ...
## $ cty.Fullname.English: chr [1:246] "Aruba" "Afghanistan" "Angola" "Anguilla" ...
## $ Cty.Abbreviation : chr [1:246] "Aruba" "Afghanistan" "Angola" "Anguilla" ...
## $ Cty.Comments : chr [1:246] "NULL" "NULL" "NULL" "NULL" ...
## $ Start.Valid.Year : num [1:246] 1988 1962 1962 1981 1962 ...
## $ End.Valid.Year : num [1:246] 2061 2061 2061 2061 2061 ...
En esta tabla aparecen 3 códigos para cada país: en el campo ctyCode
aparece un código numérico, en el campo ISO_A2
aparece un código de 2 caracteres y en el campo ISO_A3
aparece un código de 3 caracteres.
A continuación leemos una tabla de la UN, le cambiamos el nombre a algunos campos de interés, seleccionamos
los campos y hacemos un pivot_wider
UN_population <- as_tibble(read_csv("https://ctim.es/AEDV/data/UN_population.csv",skip=1))%>%
rename(un_code=`Region/Country/Area`,country=...2) %>%
select(un_code,country,Year,Series,Value) %>%
pivot_wider(names_from = Series, values_from = Value)
UN_population %>%
str()
## tibble [1,056 × 11] (S3: tbl_df/tbl/data.frame)
## $ un_code : num [1:1056] 1 1 1 1 2 2 2 2 15 15 ...
## $ country : chr [1:1056] "Total, all countries or areas" "Total, all countries or areas" "Total, all countries or areas" "Total, all countries or areas" ...
## $ Year : num [1:1056] 2010 2015 2020 2022 2010 ...
## $ Population mid-year estimates (millions) : num [1:1056] 6986 7427 7841 7975 1055 ...
## $ Population mid-year estimates for males (millions) : num [1:1056] 3514 3737 3944 4009 526 ...
## $ Population mid-year estimates for females (millions): num [1:1056] 3471 3689 3897 3967 529 ...
## $ Sex ratio (males per 100 females) : num [1:1056] 101.2 101.3 101.2 101.1 99.3 ...
## $ Population aged 0 to 14 years old (percentage) : num [1:1056] 27.1 26.4 25.7 25.3 41.5 41.3 40.5 40.1 32.4 32.8 ...
## $ Population aged 60+ years old (percentage) : num [1:1056] 11.1 12.3 13.5 13.9 5 5.2 5.4 5.5 6.6 7.3 ...
## $ Population density : num [1:1056] 53.6 57 60.1 61.2 35.7 40.6 46 48.3 26.9 29.7 ...
## $ Surface area (thousand km2) : num [1:1056] NA 136162 130094 NA NA ...
Ahora, usando left_join
combinaremos las tablas y ordenamos un poco sus campos
owid_country %>%
select(iso_code:population) %>%
left_join(UN_code,join_by(iso_code==ISO_A3)) %>%
left_join(UN_population,join_by (ctyCode==un_code)) %>%
relocate(Year, .after=iso_code) %>%
str()
## tibble [882 × 22] (S3: tbl_df/tbl/data.frame)
## $ iso_code : chr [1:882] "ABW" "ABW" "ABW" "ABW" ...
## $ Year : num [1:882] 2010 2015 2020 2022 2010 ...
## $ location : chr [1:882] "Aruba" "Aruba" "Aruba" "Aruba" ...
## $ continent : chr [1:882] "North America" "North America" "North America" "North America" ...
## $ population : num [1:882] 106459 106459 106459 106459 41128772 ...
## $ ctyCode : num [1:882] 533 533 533 533 4 4 4 4 24 24 ...
## $ ISO_A2 : chr [1:882] "AW" "AW" "AW" "AW" ...
## $ cty.Name.English : chr [1:882] "Aruba" "Aruba" "Aruba" "Aruba" ...
## $ cty.Fullname.English : chr [1:882] "Aruba" "Aruba" "Aruba" "Aruba" ...
## $ Cty.Abbreviation : chr [1:882] "Aruba" "Aruba" "Aruba" "Aruba" ...
## $ Cty.Comments : chr [1:882] "NULL" "NULL" "NULL" "NULL" ...
## $ Start.Valid.Year : num [1:882] 1988 1988 1988 1988 1962 ...
## $ End.Valid.Year : num [1:882] 2061 2061 2061 2061 2061 ...
## $ country : chr [1:882] "Aruba" "Aruba" "Aruba" "Aruba" ...
## $ Population mid-year estimates (millions) : num [1:882] 0.1 0.1 0.11 0.11 28.19 ...
## $ Population mid-year estimates for males (millions) : num [1:882] 0.05 0.05 0.05 0.05 14.24 ...
## $ Population mid-year estimates for females (millions): num [1:882] 0.05 0.05 0.06 0.06 13.95 ...
## $ Sex ratio (males per 100 females) : num [1:882] 91.2 90.2 89.1 89.2 102.1 ...
## $ Population aged 0 to 14 years old (percentage) : num [1:882] 20.7 18.8 17.4 16.2 49 45.8 43.8 43.1 45.7 45.8 ...
## $ Population aged 60+ years old (percentage) : num [1:882] 14.7 18.2 22.4 23.9 3.8 3.8 3.8 3.8 4.1 4.1 ...
## $ Population density : num [1:882] 557.5 579.2 592.1 591.4 43.4 ...
## $ Surface area (thousand km2) : num [1:882] NA 0 0 NA NA ...
3.4 Análisis exploratorio inicial
Cualquier análisis de datos debe empezar por entender el contenido y organización de los datos que se van a utilizar. Para ello, sistemáticamente, abordaremos los siguientes pasos preliminares:
- Abrir los ficheros con los datos en formato texto o con excel (si se trata de una hoja excel) y analizar visualmente su contenido.
- Localizar y entender la posibles metadatos asociados. Los metadatos que, en general, acompañan a los datos, nos suministran información muy valiosa para entender el contenido de los datos. Estos metadatos pueden estar en otros ficheros o incluidos en alguna parte del fichero de datos. Hay que tener en cuenta que en este caso, los metadatos se pierden al cargar los datos como un
tibble
y hay que mirarlos en los ficheros de datos originales. Esto pasa, por ejemplo, en los ficheros en formatopx
. - Identificar los tipos de las variables. Si hay una variable con información de fechas, identificar el formato. Estudiar si hay que hacer coerción de variables y transformar la variable con información de fechas.
- Identificar si los datos tienen una organización
tidy
, es decir, si cada fila incluye una sola observación acompañada de posibles variables categóricas (que se usan para clasificar) o, por el contrario, cada fila contiene múltiples observaciones. - Identificar el rango de las variables categóricas para entender los posibles items de clasificación de los datos. Por ejemplo, si la variable categórica es el sexo, identificar que posibles valores puede tomar esta variable. Para ello podemos usar la funcionalidad de
R
levels(as.factor(NombreVariable))
- Identificar si existe una variable índice que nos va a permitir combinar la información de nuestra tabla de datos con otras tablas.
- Analizar la ausencia de datos
NA
e identificar como se codifica la ausencia de datos en los datos analizados. En el caso de series temporales, que son datos que van cambiando con el tiempo, la ausencia de datos puede deberse a que falten fechas intermedias. Esto enR
se puede detectar usando la funciónlag
para comparar una variable fecha con la misma variable desplazada un valor. Veamos un ejemplo:
## Time differences in days
## [1] NA 1 2 1
de esta manera, podemos detectar que faltan fechas cuando el valor de date-lag(date)
es mayor que 1. Todo este análisis exploratorio inicial es fundamental y es necesario hacerlo como paso preliminar a cualquier procesado posterior de los datos.
Referencias
[Pe15] Roger D. Peng. R Programming for Data Science, Lulu, 2015.
[WiÇeGa23] Wickham, Hadley, Mine Çetinkaya-Rundel and Garrett Grolemund. R for Data Science (2e), O’Reilly Media, 2023.