Carga de la Data
Cargo el dataset, con el formato de fecha correcto y el nombre de las columnas, el cual esta presente en el CSV:
library(readr)
dataset <- read_csv("C:/Users/Leonel/Projects/dataset.csv", col_types = cols(fecha = col_date(format = "%Y%m%d")))
Analisis exploratorio
Lo primero siempre, deseo ver como se ve la data y si se cargo correctamente:
head(dataset)
Ahora, necesito saber las dimensiones del dataset:
dim(dataset)
[1] 1000001 4
Vemos que el dataset tiene un millon de filas y 4 columnas.
Deseo ver un sumario rapido de la data:
summary(dataset)
X1 fecha id txn
Min. : 0 Min. :2016-01-04 Min. : 6 Min. :-1328767.1
1st Qu.: 250000 1st Qu.:2016-01-04 1st Qu.: 432193 1st Qu.: -100.0
Median : 500000 Median :2016-01-08 Median :65048457 Median : -24.0
Mean : 500000 Mean :2016-03-23 Mean :54800228 Mean : -97.6
3rd Qu.: 750000 3rd Qu.:2016-05-03 3rd Qu.:98663337 3rd Qu.: -2.9
Max. :1000000 Max. :2016-12-06 Max. :98953092 Max. : 450000.0
NA's :396151 NA's :396151
Se puede observar:
- Lo primero que se puede observar es que la columna identificadora esta indexada en 0. Esto puede ser un issue si queremos insertar ese valor como PK en algunos manejadores de DB.
- Veo que el rango de valores para la columna ID es bastante alto, para ser una columna de usuarios. Para estudiar valores quiza convenga dejar fuera este valor.
- fecha y txn tienen 396151 NA’s o datos faltantes. Inspeccionando rapidamente, puedo percatarme que cuando uno falta, el otro tambien. Muy conveniente.
Ahora, quiero una lista de filas con valores faltantes:
dataset[!complete.cases(dataset),]
Veo que hay mas de 390.000 filas sin datos. Aproximadamente el 40% de la data.
Limpieza e Imputacion
En este punto, lo normal es decidir que hacer con la data faltante. En condiciones normales, se debe revisar la fuente de la data respecto a los valores faltantes, la posibilidad y las implicaciones. De todos modos, para este reto eso no es una posibilidad. Con eso en mente, el primer impulso seria descartar los datos faltantes, especialmente porque las filas a las que les falta informacion, tienen todas 2 onservaciones faltantes. Sin embargo, este asunto naturalmente despertaria la curiosisdad de cualquier cientifico. Imputar las observaciones cuantitativas (txn) no representaria un mayor reto. Sin embargo, para las fechas faltantes, puede no ser trivial. Mi primer impulso es averiguar si las fechas estan ordenadas logicamente.
Voy a extraer el mes:
library(dplyr)
library(lubridate)
dataset2 <- mutate(dataset, month = month(dataset$fecha, label = TRUE))
library(ggplot2)
ggplot(dataset2,aes(x=month,fill=month)) + geom_bar(width = 0.6) + theme(legend.position = "none") + labs(title="Data distribution by month")

ggplot(dataset2,aes(x=fecha,fill=fecha)) + geom_bar(width = 0.6) + theme(legend.position = "none") + labs(title="Data distribution by day")

Me preocupa que la data no parece tener una distribucion igualitaria. Parece haber mucha mas data en Enero que en mayo y Diciembre juntos. Ademas, los unicos 3 meses que tienen data, parecen estar aleatoriamente distribuidos. (De Enero a Mayo hay 4 meses y de Mayo a Diciembre, hay 7) La distribucion por dia, hace mucho mas evidente la desigualdad en la distribucion de datos.
En conclusion, no siento que tenga gran valor para el analisis de datos, realizar imputaciones a la fecha y a la cantidad de las transacciones para los usuarios. Lo que si considero valioso, es tomar en cuenta los registros con informacion faltante, ya que solo el usuario que reliza la transaccion e suna informacion valiosa, en caso que se quiera sumarizar la cantidad de transacciones faltantes para un usuario, o la cantidad de transacciones totales en determinado mes. La manera de insertar la data en una base de datos va a depender del objetivo del analisis, claro. Ademas, del sistema de informacion gerencial que va a procesar la data. Recomiendo colocar una fecha invalida y cero (0) como valor de la transaccion. (Esto porque al ser transacciones con ingresos y egresos, el cero es un valor que no afectara los calculos de balance).
Aunque en el ejercicio no se especifica el nivel de confianza que se tiene en este dataset, debido a los datos faltantes de fecha y txn es logico ser un poco esceptico. Considero imnteresante ver la distribucion en la cantidad de las transacciones:
boxplot(dataset$txn)

El resultado tiene sentido para transacciones bancarias. Aunque hay alguien que hizo un retiro un tanto atipico!. -1328767.1 Quiza valga la pena revisarlo… Pero no es el objetivo de este ejercicio.
Conclusiones
La data es un tanto ruidosa y dispersa. Es de esperarse en un dataset de prueba. Sin embargo, el realizar este analisis exploratorio ha permitido obtener informacion valiosa para la creacion de un modelo de datos compatible en un sistema Backend, como requiere el ejercicio. Cosas a tomar en cuenta:
- El identificador de las filas esta indexado en cero.
- La fecha puede requerir parseo antes de ser insertada en un manejador.
- El UUID debe ser un entero.
- El TXN debe ser un decimal signed.
- Los registros con fecha faltante deben ser insertados, pero considerados en los resultados.
- Los registros con fecha faltante deben mostrarse al usuario final de alguna manera, sin que afecte agregados o cuentas.
LS0tDQp0aXRsZTogIkFuYWxpc2lzIEV4cGxvcmF0b3JpbyBkZSBEYXRvcyAtIEJhbmlzdG1vIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyMjIENhcmdhIGRlIGxhIERhdGENCkNhcmdvIGVsIGRhdGFzZXQsIGNvbiBlbCBmb3JtYXRvIGRlIGZlY2hhIGNvcnJlY3RvIHkgZWwgbm9tYnJlIGRlIGxhcyBjb2x1bW5hcywgZWwgY3VhbCBlc3RhIHByZXNlbnRlIGVuIGVsIENTVjoNCmBgYHtyfQ0KbGlicmFyeShyZWFkcikNCmRhdGFzZXQgPC0gcmVhZF9jc3YoIkM6L1VzZXJzL0xlb25lbC9Qcm9qZWN0cy9kYXRhc2V0LmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoZmVjaGEgPSBjb2xfZGF0ZShmb3JtYXQgPSAiJVklbSVkIikpKQ0KYGBgDQoNCiMjIyBBbmFsaXNpcyBleHBsb3JhdG9yaW8NCkxvIHByaW1lcm8gc2llbXByZSwgZGVzZW8gdmVyIGNvbW8gc2UgdmUgbGEgZGF0YSB5IHNpIHNlIGNhcmdvIGNvcnJlY3RhbWVudGU6DQpgYGB7cn0NCmhlYWQoZGF0YXNldCkNCmBgYA0KDQpBaG9yYSwgbmVjZXNpdG8gc2FiZXIgbGFzICpkaW1lbnNpb25lcyogZGVsIGRhdGFzZXQ6DQpgYGB7cn0NCmRpbShkYXRhc2V0KQ0KYGBgDQpWZW1vcyBxdWUgZWwgZGF0YXNldCB0aWVuZSB1biBtaWxsb24gZGUgZmlsYXMgeSA0IGNvbHVtbmFzLg0KDQoNCkRlc2VvIHZlciB1biAqc3VtYXJpbyogcmFwaWRvIGRlIGxhIGRhdGE6DQpgYGB7cn0NCnN1bW1hcnkoZGF0YXNldCkNCmBgYA0KU2UgcHVlZGUgb2JzZXJ2YXI6DQoNCjEuIExvIHByaW1lcm8gcXVlIHNlIHB1ZWRlIG9ic2VydmFyIGVzIHF1ZSBsYSBjb2x1bW5hIGlkZW50aWZpY2Fkb3JhIGVzdGEgaW5kZXhhZGEgZW4gMC4gRXN0byBwdWVkZSBzZXIgdW4gaXNzdWUgc2kgcXVlcmVtb3MgaW5zZXJ0YXIgZXNlIHZhbG9yIGNvbW8gUEsgZW4gYWxndW5vcyBtYW5lamFkb3JlcyBkZSBEQi4NCjIuIFZlbyBxdWUgZWwgcmFuZ28gZGUgdmFsb3JlcyBwYXJhIGxhIGNvbHVtbmEgSUQgZXMgYmFzdGFudGUgYWx0bywgcGFyYSBzZXIgdW5hIGNvbHVtbmEgZGUgdXN1YXJpb3MuIFBhcmEgZXN0dWRpYXIgdmFsb3JlcyBxdWl6YSBjb252ZW5nYSBkZWphciBmdWVyYSBlc3RlIHZhbG9yLg0KMy4gZmVjaGEgeSB0eG4gdGllbmVuIDM5NjE1MSBOQSdzIG8gZGF0b3MgZmFsdGFudGVzLiBJbnNwZWNjaW9uYW5kbyByYXBpZGFtZW50ZSwgcHVlZG8gcGVyY2F0YXJtZSBxdWUgY3VhbmRvIHVubyBmYWx0YSwgZWwgb3RybyB0YW1iaWVuLiBNdXkgY29udmVuaWVudGUuDQoNCg0KQWhvcmEsIHF1aWVybyB1bmEgbGlzdGEgZGUgZmlsYXMgY29uICp2YWxvcmVzIGZhbHRhbnRlcyo6DQpgYGB7cn0NCmRhdGFzZXRbIWNvbXBsZXRlLmNhc2VzKGRhdGFzZXQpLF0NCmBgYA0KVmVvIHF1ZSBoYXkgbWFzIGRlIDM5MC4wMDAgZmlsYXMgc2luIGRhdG9zLiBBcHJveGltYWRhbWVudGUgZWwgNDAlIGRlIGxhIGRhdGEuDQoNCiMjIyBMaW1waWV6YSBlIEltcHV0YWNpb24NCkVuIGVzdGUgcHVudG8sIGxvIG5vcm1hbCBlcyBkZWNpZGlyIHF1ZSBoYWNlciBjb24gbGEgZGF0YSBmYWx0YW50ZS4gRW4gY29uZGljaW9uZXMgbm9ybWFsZXMsIHNlIGRlYmUgcmV2aXNhciBsYSBmdWVudGUgZGUgbGEgZGF0YSByZXNwZWN0byBhIGxvcyB2YWxvcmVzIGZhbHRhbnRlcywgbGEgcG9zaWJpbGlkYWQgeSBsYXMgaW1wbGljYWNpb25lcy4gRGUgdG9kb3MgbW9kb3MsIHBhcmEgZXN0ZSByZXRvIGVzbyBubyBlcyB1bmEgcG9zaWJpbGlkYWQuDQpDb24gZXNvIGVuIG1lbnRlLCBlbCBwcmltZXIgaW1wdWxzbyBzZXJpYSBkZXNjYXJ0YXIgbG9zIGRhdG9zIGZhbHRhbnRlcywgZXNwZWNpYWxtZW50ZSBwb3JxdWUgbGFzIGZpbGFzIGEgbGFzIHF1ZSBsZXMgZmFsdGEgaW5mb3JtYWNpb24sIHRpZW5lbiB0b2RhcyAyIG9uc2VydmFjaW9uZXMgZmFsdGFudGVzLg0KU2luIGVtYmFyZ28sIGVzdGUgYXN1bnRvIG5hdHVyYWxtZW50ZSBkZXNwZXJ0YXJpYSBsYSBjdXJpb3Npc2RhZCBkZSBjdWFscXVpZXIgY2llbnRpZmljby4gSW1wdXRhciBsYXMgb2JzZXJ2YWNpb25lcyBjdWFudGl0YXRpdmFzICh0eG4pIG5vIHJlcHJlc2VudGFyaWEgdW4gbWF5b3IgcmV0by4gU2luIGVtYmFyZ28sIHBhcmEgbGFzIGZlY2hhcyBmYWx0YW50ZXMsIHB1ZWRlIG5vIHNlciB0cml2aWFsLg0KTWkgcHJpbWVyIGltcHVsc28gZXMgYXZlcmlndWFyIHNpIGxhcyBmZWNoYXMgZXN0YW4gb3JkZW5hZGFzIGxvZ2ljYW1lbnRlLg0KDQpWb3kgYSBleHRyYWVyIGVsIG1lczoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkobHVicmlkYXRlKQ0KZGF0YXNldDIgPC0gbXV0YXRlKGRhdGFzZXQsIG1vbnRoID0gbW9udGgoZGF0YXNldCRmZWNoYSwgbGFiZWwgPSBUUlVFKSkNCmxpYnJhcnkoZ2dwbG90MikNCmdncGxvdChkYXRhc2V0MixhZXMoeD1tb250aCxmaWxsPW1vbnRoKSkgKyBnZW9tX2Jhcih3aWR0aCA9IDAuNikgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsgbGFicyh0aXRsZT0iRGF0YSBkaXN0cmlidXRpb24gYnkgbW9udGgiKQ0KZ2dwbG90KGRhdGFzZXQyLGFlcyh4PWZlY2hhLGZpbGw9ZmVjaGEpKSArIGdlb21fYmFyKHdpZHRoID0gMC42KSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKyBsYWJzKHRpdGxlPSJEYXRhIGRpc3RyaWJ1dGlvbiBieSBkYXkiKQ0KYGBgDQpNZSBwcmVvY3VwYSBxdWUgbGEgZGF0YSBubyBwYXJlY2UgdGVuZXIgdW5hIGRpc3RyaWJ1Y2lvbiBpZ3VhbGl0YXJpYS4gUGFyZWNlIGhhYmVyIG11Y2hhIG1hcyBkYXRhIGVuIEVuZXJvIHF1ZSBlbiBtYXlvIHkgRGljaWVtYnJlIGp1bnRvcy4NCkFkZW1hcywgbG9zIHVuaWNvcyAzIG1lc2VzIHF1ZSB0aWVuZW4gZGF0YSwgcGFyZWNlbiBlc3RhciBhbGVhdG9yaWFtZW50ZSBkaXN0cmlidWlkb3MuIChEZSBFbmVybyBhIE1heW8gaGF5IDQgbWVzZXMgeSBkZSBNYXlvIGEgRGljaWVtYnJlLCBoYXkgNykNCkxhIGRpc3RyaWJ1Y2lvbiBwb3IgZGlhLCBoYWNlIG11Y2hvIG1hcyBldmlkZW50ZSBsYSBkZXNpZ3VhbGRhZCBlbiBsYSBkaXN0cmlidWNpb24gZGUgZGF0b3MuDQoNCg0KRW4gY29uY2x1c2lvbiwgbm8gc2llbnRvIHF1ZSB0ZW5nYSBncmFuIHZhbG9yIHBhcmEgZWwgYW5hbGlzaXMgZGUgZGF0b3MsIHJlYWxpemFyIGltcHV0YWNpb25lcyBhIGxhIGZlY2hhIHkgYSBsYSBjYW50aWRhZCBkZSBsYXMgdHJhbnNhY2Npb25lcyBwYXJhIGxvcyB1c3Vhcmlvcy4NCkxvIHF1ZSBzaSBjb25zaWRlcm8gdmFsaW9zbywgZXMgdG9tYXIgZW4gY3VlbnRhIGxvcyByZWdpc3Ryb3MgY29uIGluZm9ybWFjaW9uIGZhbHRhbnRlLCB5YSBxdWUgc29sbyBlbCB1c3VhcmlvIHF1ZSByZWxpemEgbGEgdHJhbnNhY2Npb24gZSBzdW5hIGluZm9ybWFjaW9uIHZhbGlvc2EsIGVuIGNhc28gcXVlIHNlIHF1aWVyYSBzdW1hcml6YXIgbGEgY2FudGlkYWQgZGUgdHJhbnNhY2Npb25lcyBmYWx0YW50ZXMgcGFyYSB1biB1c3VhcmlvLCBvIGxhIGNhbnRpZGFkIGRlIHRyYW5zYWNjaW9uZXMgdG90YWxlcyBlbiBkZXRlcm1pbmFkbyBtZXMuDQpMYSBtYW5lcmEgZGUgaW5zZXJ0YXIgbGEgZGF0YSBlbiB1bmEgYmFzZSBkZSBkYXRvcyB2YSBhIGRlcGVuZGVyIGRlbCBvYmpldGl2byBkZWwgYW5hbGlzaXMsIGNsYXJvLiBBZGVtYXMsIGRlbCBzaXN0ZW1hIGRlIGluZm9ybWFjaW9uIGdlcmVuY2lhbCBxdWUgdmEgYSBwcm9jZXNhciBsYSBkYXRhLiBSZWNvbWllbmRvIGNvbG9jYXIgdW5hIGZlY2hhIGludmFsaWRhIHkgY2VybyAoMCkgY29tbyB2YWxvciBkZSBsYSB0cmFuc2FjY2lvbi4gKEVzdG8gcG9ycXVlIGFsIHNlciB0cmFuc2FjY2lvbmVzIGNvbiBpbmdyZXNvcyB5IGVncmVzb3MsIGVsIGNlcm8gZXMgdW4gdmFsb3IgcXVlIG5vIGFmZWN0YXJhIGxvcyBjYWxjdWxvcyBkZSBiYWxhbmNlKS4NCg0KQXVucXVlIGVuIGVsIGVqZXJjaWNpbyBubyBzZSBlc3BlY2lmaWNhIGVsIG5pdmVsIGRlIGNvbmZpYW56YSBxdWUgc2UgdGllbmUgZW4gZXN0ZSBkYXRhc2V0LCBkZWJpZG8gYSBsb3MgZGF0b3MgZmFsdGFudGVzIGRlIGZlY2hhIHkgdHhuIGVzIGxvZ2ljbyBzZXIgdW4gcG9jbyBlc2NlcHRpY28uDQpDb25zaWRlcm8gaW1udGVyZXNhbnRlIHZlciBsYSAqZGlzdHJpYnVjaW9uKiBlbiBsYSBjYW50aWRhZCBkZSBsYXMgdHJhbnNhY2Npb25lczoNCmBgYHtyfQ0KYm94cGxvdChkYXRhc2V0JHR4bikNCmBgYA0KDQpFbCByZXN1bHRhZG8gdGllbmUgc2VudGlkbyBwYXJhIHRyYW5zYWNjaW9uZXMgYmFuY2FyaWFzLiBBdW5xdWUgaGF5IGFsZ3VpZW4gcXVlIGhpem8gdW4gcmV0aXJvIHVuIHRhbnRvIGF0aXBpY28hLiBgLTEzMjg3NjcuMWAgUXVpemEgdmFsZ2EgbGEgcGVuYSByZXZpc2FybG8uLi4gUGVybyBubyBlcyBlbCBvYmpldGl2byBkZSBlc3RlIGVqZXJjaWNpby4NCg0KIyMjIENvbmNsdXNpb25lcw0KTGEgZGF0YSBlcyB1biB0YW50byBydWlkb3NhIHkgZGlzcGVyc2EuIEVzIGRlIGVzcGVyYXJzZSBlbiB1biBkYXRhc2V0IGRlIHBydWViYS4gU2luIGVtYmFyZ28sIGVsIHJlYWxpemFyIGVzdGUgYW5hbGlzaXMgZXhwbG9yYXRvcmlvIGhhIHBlcm1pdGlkbyBvYnRlbmVyIGluZm9ybWFjaW9uIHZhbGlvc2EgcGFyYSBsYSBjcmVhY2lvbiBkZSB1biBtb2RlbG8gZGUgZGF0b3MgY29tcGF0aWJsZSBlbiB1biBzaXN0ZW1hIEJhY2tlbmQsIGNvbW8gcmVxdWllcmUgZWwgZWplcmNpY2lvLiBDb3NhcyBhIHRvbWFyIGVuIGN1ZW50YToNCg0KKiBFbCBpZGVudGlmaWNhZG9yIGRlIGxhcyBmaWxhcyBlc3RhIGluZGV4YWRvIGVuIGNlcm8uDQoqIExhIGZlY2hhIHB1ZWRlIHJlcXVlcmlyIHBhcnNlbyBhbnRlcyBkZSBzZXIgaW5zZXJ0YWRhIGVuIHVuIG1hbmVqYWRvci4NCiogRWwgVVVJRCBkZWJlIHNlciB1biBlbnRlcm8uDQoqIEVsIFRYTiBkZWJlIHNlciB1biBkZWNpbWFsIHNpZ25lZC4NCiogTG9zIHJlZ2lzdHJvcyBjb24gZmVjaGEgZmFsdGFudGUgZGViZW4gc2VyIGluc2VydGFkb3MsIHBlcm8gY29uc2lkZXJhZG9zIGVuIGxvcyByZXN1bHRhZG9zLg0KKiBMb3MgcmVnaXN0cm9zIGNvbiBmZWNoYSBmYWx0YW50ZSBkZWJlbiBtb3N0cmFyc2UgYWwgdXN1YXJpbyBmaW5hbCBkZSBhbGd1bmEgbWFuZXJhLCBzaW4gcXVlIGFmZWN0ZSBhZ3JlZ2Fkb3MgbyBjdWVudGFzLg0KDQoNCg==