library(tidyverse)
## Registered S3 methods overwritten by 'ggplot2':
##   method         from 
##   [.quosures     rlang
##   c.quosures     rlang
##   print.quosures rlang
## -- Attaching packages --------------------------------------- tidyverse 1.2.1 --
## v ggplot2 3.1.1     v purrr   0.3.2
## v tibble  2.1.1     v dplyr   0.8.1
## v tidyr   0.8.3     v stringr 1.4.0
## v readr   1.3.1     v forcats 0.4.0
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
data <- read.csv("datos_numericos_cuentas.csv")
data$X<- NULL

Clustering con todos los atributos

Intento ingenuo de hacer clustering con todos los atributos

set.seed(413)

scaled <- scale(data %>% select(2:14))

wss <- 0
clust = 15 # graficaremos hasta 15 clusters
for (i in 1:clust){
  wss[i] <-
    sum(kmeans(scaled, centers=i)$withinss)
}

plot(1:clust, wss, type="b", xlab="Numero de clusters", ylab="wss")

Se usan 6 nodos

kmall.out <- kmeans(scaled, 6, nstart = 20)
pairs(data, col=kmall.out$cluster)

Conclusión: FRACASO

No hay un patrón descifrable en las figuras

Clustering con followers/day y updates/day

set.seed(413)

scaledday <- scale(data %>% select(12,14))

wss <- 0
clust = 15 # graficaremos hasta 15 clusters
for (i in 1:clust){
  wss[i] <-
    sum(kmeans(scaledday, centers=i)$withinss)
}

plot(1:clust, wss, type="b", xlab="Numero de clusters", ylab="wss")

Se usan 4 nodos.

kmday.out <- kmeans(scaledday, 4, nstart = 20)
plot(data %>% select(12,14), main="Clusters de cambios por dia", col =(kmday.out$cluster), xlab="follower/day", ylab="updates/day")

Dos outliers arruinan el clustering. Limpiando..

set.seed(413)

scaledday <- scale(data %>% select(12,14) %>% filter(followers_day < 2000, updates_day < 20000))

wss <- 0
clust = 15 # graficaremos hasta 15 clusters
for (i in 1:clust){
  wss[i] <-
    sum(kmeans(scaledday, centers=i)$withinss)
}

plot(1:clust, wss, type="b", xlab="Numero de clusters", ylab="wss")

Se usan 4 nodos

kmday.out <- kmeans(scaledday, 4, nstart = 20)
plot(data %>% select(12,14) %>% filter(followers_day < 2000, updates_day < 20000), main="Clusters de cambios por dia", col =(kmday.out$cluster), xlab="follower/day", ylab="updates/day")

Conclusión: Factible

Posible interpretación

Es posible que todos los datos sin crecimiento de followers sean bots.

Clustering con diferencias de followers, updates y fechas

set.seed(413)

scaleddiff <- scale(data %>% select(4, 10, 11))

wss <- 0
clust = 15 # graficaremos hasta 15 clusters
for (i in 1:clust){
  wss[i] <-
    sum(kmeans(scaleddiff, centers=i)$withinss)
}

plot(1:clust, wss, type="b", xlab="Numero de clusters", ylab="wss")

Se usan 6 nodos

kmdiff.out <- kmeans(scaleddiff, 6, nstart = 20)
pairs(data %>% select(4, 10, 11), main="Clusters de diferencias", col=(kmdiff.out$cluster))

Varios outliers afectan los clusters. Limpiando..

set.seed(413)

scaleddiff <- scale(data %>% select(4, 10, 11) %>% filter(diff_updates < 30000, diff_publish_date < 800, diff_followers < 40000))

wss <- 0
clust = 15 # graficaremos hasta 15 clusters
for (i in 1:clust){
  wss[i] <-
    sum(kmeans(scaleddiff, centers=i)$withinss)
}

plot(1:clust, wss, type="b", xlab="Numero de clusters", ylab="wss")

Se usan 5 nodos

kmdiff.out <- kmeans(scaleddiff, 5, nstart = 20)
pairs(data %>% select(4, 10, 11) %>% filter(diff_updates < 30000, diff_publish_date < 800, diff_followers < 40000), main="Clusters de diferencias", col=(kmdiff.out$cluster))

Conclusión: Factible

Posible interpretación

Descripcion de los modelos

kmday.out
## K-means clustering with 4 clusters of sizes 7, 2623, 17, 115
## 
## Cluster means:
##   followers_day updates_day
## 1  13.851241269   1.8842424
## 2  -0.158133165  -0.0916677
## 3  -0.009894483  11.4104558
## 4   2.765154865   0.2893647
## 
## Within cluster sum of squares by cluster:
## [1] 177.8485 367.7555 118.2409 300.3675
##  (between_SS / total_SS =  82.5 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"    
## [5] "tot.withinss" "betweenss"    "size"         "iter"        
## [9] "ifault"
kmdiff.out
## K-means clustering with 5 clusters of sizes 1637, 144, 54, 46, 860
## 
## Cluster means:
##   diff_followers diff_updates diff_publish_date
## 1    -0.22387810  -0.29092429        -0.5996253
## 2     0.58740368   3.00179453         0.7465959
## 3     0.47613078   0.50475606         4.4456397
## 4     6.40969955   2.20746268         1.2197632
## 5    -0.04494758  -0.09862262         0.6719805
## 
## Within cluster sum of squares by cluster:
## [1] 332.0654 679.2508 102.3365 517.9097 677.6000
##  (between_SS / total_SS =  71.9 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"    
## [5] "tot.withinss" "betweenss"    "size"         "iter"        
## [9] "ifault"

Guardado de la tabla

La tabla contiene los resultados de ambos modelos.

cluster_day <- (data %>% filter(followers_day < 2000, updates_day < 20000) %>% select(1))
cluster_day['cl_day'] = kmday.out$cluster
cluster_diff <- (data %>% filter(diff_updates < 30000, diff_publish_date < 800, diff_followers < 40000) %>% select(1))
cluster_diff['cl_diff'] = kmdiff.out$cluster

res_clusters <- (cluster_day %>% left_join(cluster_diff, by="author"))

write.csv(res_clusters, "clusters_cuentas.csv", row.names=F, na="")

Conclusiones

Si bien existen patrones en los datos que indican categorías (o clusters) en el crecimiento de followers y updates, para poder aplicar estos como definición de popularidad deben refinarse los procedimientos. Por ejemplo, en el clustering de crecimiento por día, se podría preasignar una clase a los elementos que no crecen en followers.

También existe el problema de que estos patrones sean propios del dataset, pues en el clustering por diferencias absolutas se puede observar claramente que la distribución de los intervalos de tiempo entre el primer y el último tweet registrado de cada cuenta no es uniforme, sino que tiene ciertos peaks. Este es un fenomeno que podría ser fácilmente clasificado en el dataset, pero que puede causar dificultades a la hora de escalar el algoritmo.