Esta sección carga los paquetes necesarios, importa el dataset de TikTok y realiza una limpieza general: renombrado de columnas, conversión de tipos de datos, eliminación de valores nulos y creación de nuevas variables como la tasa de engagement y categorías temáticas detectadas en las transcripciones.
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.2 ✔ tibble 3.2.1
## ✔ lubridate 1.9.4 ✔ tidyr 1.3.1
## ✔ purrr 1.0.4
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(plotly)
##
## Adjuntando el paquete: 'plotly'
##
## The following object is masked from 'package:ggplot2':
##
## last_plot
##
## The following object is masked from 'package:stats':
##
## filter
##
## The following object is masked from 'package:graphics':
##
## layout
library(shiny)
library(DT)
##
## Adjuntando el paquete: 'DT'
##
## The following objects are masked from 'package:shiny':
##
## dataTableOutput, renderDataTable
library(lubridate)
# Cargar los datos
tiktok_data <- read_csv("C:/R/Unidad_3/tiktok_dataset/tiktok_dataset.csv")
## Rows: 19382 Columns: 12
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (9): claim_status, video_transcription_text, verified_status, author_ban...
## dbl (3): #, video_id, video_duration_sec
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Limpieza inicial
clean_data <- tiktok_data %>%
select(-`#`) %>%
rename_all(~str_to_lower(.)) %>%
rename_all(~str_replace_all(., " ", "_")) %>%
mutate(
claim_status = as.factor(claim_status),
verified_status = as.factor(verified_status),
author_ban_status = as.factor(author_ban_status),
video_transcription_text = str_trim(video_transcription_text),
video_view_count = as.numeric(video_view_count),
video_like_count = as.numeric(video_like_count),
video_share_count = as.numeric(video_share_count),
video_download_count = as.numeric(video_download_count),
video_comment_count = as.numeric(video_comment_count)
) %>%
drop_na(video_view_count, video_like_count) %>%
mutate(
engagement_rate = (video_like_count + video_comment_count + video_share_count) / video_view_count,
category = case_when(
str_detect(video_transcription_text, "drone|deliver") ~ "Technology",
str_detect(video_transcription_text, "microorganism|soil|animal|plant|tree") ~ "Nature/Science",
str_detect(video_transcription_text, "carnegie|million|billion|gdp|business") ~ "Economy/Business",
str_detect(video_transcription_text, "metro|subway|bus|network") ~ "Transportation",
str_detect(video_transcription_text, "olympics|sport|player|match") ~ "Sports",
str_detect(video_transcription_text, "moon|earth|planet|space|sun") ~ "Space",
str_detect(video_transcription_text, "internet|web|mobile|device") ~ "Technology/Digital",
str_detect(video_transcription_text, "music|song|band|album") ~ "Music",
str_detect(video_transcription_text, "animal|dog|cat|bird") ~ "Animals",
TRUE ~ "Other"
),
upload_date = as.Date("2023-01-01") + days(row_number() %% 365)
)
## Warning: There were 5 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `video_view_count = as.numeric(video_view_count)`.
## Caused by warning:
## ! NAs introducidos por coerción
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 4 remaining warnings.
Esta sección permite a los usuarios filtrar los datos por categoría, duración del video y estado de verificación del autor.
selectInput("category", "Seleccionar Categoría:",
choices = unique(clean_data$category),
multiple = TRUE,
selected = "Nature/Science")
sliderInput("duration", "Duración del Video (segundos):",
min = min(clean_data$video_duration_sec),
max = max(clean_data$video_duration_sec),
value = c(10, 60))
checkboxGroupInput("verification", "Estado de Verificación:",
choices = levels(clean_data$verified_status),
selected = levels(clean_data$verified_status))
Este gráfico muestra la distribución de vistas de videos agrupados por estado de verificación del autor.
filtered_data <- reactive({
clean_data %>%
filter(
category %in% input$category,
video_duration_sec >= input$duration[1],
video_duration_sec <= input$duration[2],
verified_status %in% input$verification
)
})
plot_ly(
data = clean_data %>%
filter(
category %in% c("Nature/Science"), # Selección estática
video_duration_sec >= 10, # Duración estática
video_duration_sec <= 60, # Duración estática
verified_status %in% c("verified") # Estado de verificación estático
),
x = ~verified_status,
y = ~log10(video_view_count),
color = ~verified_status,
type = "box"
) %>%
layout(title = "Distribución de Vistas por Verificación",
xaxis = list(title = "Verificación"),
yaxis = list(title = "Log10(Vistas)"))
## Warning in RColorBrewer::brewer.pal(N, "Set2"): minimal value for n is 3, returning requested palette with 3 different levels
## Warning in RColorBrewer::brewer.pal(N, "Set2"): minimal value for n is 3, returning requested palette with 3 different levels
Interpretación: Esta gráfica compara las vistas de los videos entre usuarios verificados y no verificados. Se utiliza una escala logarítmica para facilitar la visualización de grandes diferencias. Permite ver si la verificación está asociada con un mayor alcance.
Esta sección genera un gráfico de dispersión que relaciona la duración del video con su tasa de engagement.
plot_ly(
data = clean_data %>%
filter(
category %in% c("Nature/Science"), # Selección estática
video_duration_sec >= 10, # Duración estática
video_duration_sec <= 60, # Duración estática
verified_status %in% c("verified") # Estado de verificación estático
),
x = ~video_duration_sec,
y = ~engagement_rate,
color = ~category,
size = ~video_view_count,
type = "scatter",
mode = "markers",
hoverinfo = "text",
text = ~paste("ID:", video_id, "<br>Duración:", video_duration_sec,
"<br>Engagement:", round(engagement_rate, 4),
"<br>Vistas:", video_view_count)) %>%
layout(title = "Engagement vs Duración",
xaxis = list(title = "Duración (s)"),
yaxis = list(title = "Engagement Rate"))
## Warning: `line.width` does not currently support multiple values.
## Warning in RColorBrewer::brewer.pal(N, "Set2"): minimal value for n is 3, returning requested palette with 3 different levels
## Warning in RColorBrewer::brewer.pal(N, "Set2"): minimal value for n is 3, returning requested palette with 3 different levels
Interpretación: Esta gráfica evalúa la relación entre la duración de los videos y la tasa de engagement. Permite detectar si los videos más largos o cortos generan más interacción relativa. También se comparan temáticas (colores) y volumen de vistas (tamaño).
Este gráfico de barras muestra la cantidad de videos por categoría diferenciando si el autor ha sido baneado o no.
plot_ly(
data = clean_data %>% count(category, author_ban_status),
x = ~category,
y = ~n,
color = ~author_ban_status,
type = "bar",
hoverinfo = "text",
text = ~paste("Categoría:", category, "<br>Estado:", author_ban_status, "<br>Conteo:", n)
) %>%
layout(
title = "Distribución de Videos por Categoría y Estado de Ban del Autor",
xaxis = list(title = "Categoría", categoryorder = "total descending"),
yaxis = list(title = "Número de Videos"),
barmode = "stack",
hovermode = "x unified"
)
Interpretación: Muestra la cantidad de videos por categoría, diferenciando si el autor ha sido baneado o no. Esto puede ayudar a detectar temáticas más propensas a violaciones de políticas.
Esta sección representa cómo cambió la frecuencia de publicaciones a lo largo del tiempo, diferenciada por categoría.
plot_ly(
data = clean_data %>% count(upload_date, category),
x = ~upload_date,
y = ~n,
color = ~category,
type = "scatter",
mode = "lines+markers",
hoverinfo = "text",
text = ~paste("Fecha:", upload_date, "<br>Categoría:", category, "<br>Videos:", n)
) %>%
layout(
title = "Tendencia Temporal de Publicaciones por Categoría",
xaxis = list(title = "Fecha"),
yaxis = list(title = "Número de Videos Publicados"),
hovermode = "x unified"
)
## Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
## Returning the palette you asked for with that many colors
## Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
## Returning the palette you asked for with that many colors
Interpretación: Representa cómo cambió la frecuencia de publicaciones a lo largo del tiempo, diferenciada por categoría. Permite detectar tendencias, estacionalidad o picos de actividad en temáticas específicas.
Este análisis interactivo proporciona una visión integral del rendimiento de los videos en TikTok, considerando variables clave como la duración, engagement, verificación del autor, categoría del contenido y su evolución temporal. Las visualizaciones permiten descubrir patrones y tendencias útiles para la toma de decisiones estratégicas en la creación de contenido, revelando, por ejemplo, qué temáticas generan mayor interacción, cómo influye la duración del video, y el impacto de la verificación del autor en el alcance del contenido.