1 Configuración y Carga de Datos

##### UNIVERSIDAD CENTRAL DEL ECUADOR #####
#### AUTOR: MARTIN SARMIENTO ####
### CARRERA: INGENIERÍA EN PETRÓLEOS #####


#### VARIABLE LATITUD ####
## DATASET ##
setwd("~/R/LATITUD")
# Cargar dataset
Datos <- read.csv("DataSet_.csv", sep = ";", fileEncoding = "latin1")
# Estructura de los datos
str(Datos)
## 'data.frame':    7142 obs. of  26 variables:
##  $ fid                  : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ objectid             : int  127 128 129 130 131 132 133 134 135 136 ...
##  $ code                 : chr  "Arg-00001" "Arg-00002" "Arg-00003" "Arg-00004" ...
##  $ country              : chr  "Argentina" "Argentina" "Argentina" "Argentina" ...
##  $ plant_name           : chr  "Aconcagua solar farm" "Aconcagua solar farm" "Altiplano 200 Solar Power Plant" "Altiplano 200 Solar Power Plant" ...
##  $ operational_status   : chr  "announced" "announced" "operating" "operating" ...
##  $ longitude            : num  -68.9 -68.9 -66.9 -66.9 -68.9 ...
##  $ latitude             : num  -33 -33 -24.1 -24.1 -33.3 ...
##  $ elevation            : int  929 929 4000 4000 937 865 858 858 858 858 ...
##  $ area                 : num  0 0 4397290 5774 0 ...
##  $ slope                : num  0.574 0.574 1.603 6.243 0.903 ...
##  $ slope_type           : chr  "Plano o casi plano" "Plano o casi plano" "Plano o casi plano" "Moderado" ...
##  $ curvature            : num  0.000795 0.000795 -0.002781 -0.043699 0.002781 ...
##  $ curvature_type       : chr  "Superficies planas o intermedias" "Superficies planas o intermedias" "Superficies planas o intermedias" "Superficies cóncavas / Valles" ...
##  $ aspect               : num  55.1 55.1 188.7 270.9 108.4 ...
##  $ aspect_type          : chr  "Northeast" "Northeast" "South" "West" ...
##  $ ghi                  : num  6.11 6.11 8.01 7.88 6.12 ...
##  $ solar_aptitude       : num  0.746 0.746 0.8 0.727 0.595 ...
##  $ solar_aptittude_class: chr  "Alta" "Alta" "Alta" "Alta" ...
##  $ humidity             : num  0 0 53.7 53.7 0 ...
##  $ wind_speed           : num  3.78 3.78 7.02 8.33 3.87 ...
##  $ wind_direction       : num  0 0 55.1 55.1 0 ...
##  $ ambient_temperature  : num  12.6 12.6 6.8 6.8 13.1 ...
##  $ optimal_tilt         : int  31 31 26 26 31 33 30 30 30 30 ...
##  $ peak_power_per_hour  : num  4.98 4.98 6.39 6.39 4.97 ...
##  $ total_power          : num  25 66.2 101 107 180 ...
# Cargamos las librerias
library(dplyr)
## 
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(gt)
library(e1071)

2 Cálculo de Intervalos y Frecuencias

#Extraer variable
Variable <- na.omit(Datos$latitude)
N <- length(Variable)

# Cálculo Límites Decimales #
# Cálculos básicos 
min_dec <- min(Variable)
max_dec <- max(Variable)
k_dec <- floor(1 + 3.322 * log10(N))
rango_dec <- max(Variable) - min(Variable)
amplitud_dec <- rango_dec / k_dec

# Generamos los cortes exactos
cortes_dec <- seq(min(Variable), max(Variable), length.out = k_dec + 1)
cortes_dec[length(cortes_dec)] <- max(Variable) + 0.0001

# Frecuencias 
inter_dec <- cut(Variable, breaks = cortes_dec, include.lowest = TRUE, right = FALSE)
ni_dec <- as.vector(table(inter_dec))
hi_dec <- (ni_dec/N)*100

# Cálculos de Frecuencias 
sum_ni <- sum(ni_dec)
hi_dec <- (ni_dec / sum_ni) * 100 
Ni_asc_dec <- cumsum(ni_dec)
Hi_asc_dec <- cumsum(hi_dec)
Ni_desc_dec <- rev(cumsum(rev(ni_dec)))
Hi_desc_dec <- rev(cumsum(rev(hi_dec)))

# Construcción del Dataframe Decimal
TDF_Decimal <- data.frame(
  Li = round(cortes_dec[1:k_dec], 2),
  Ls = round(cortes_dec[2:(k_dec+1)], 2),
  MC = round((cortes_dec[1:k_dec] + cortes_dec[2:(k_dec+1)]) / 2, 2),
  ni = ni_dec,
  hi = round(hi_dec, 2),
  Ni_asc = cumsum(ni_dec),
  Ni_desc = rev(cumsum(rev(ni_dec))),
  Hi_asc = cumsum(round(hi_dec, 2)),
  Hi_desc = rev(cumsum(rev(round(hi_dec, 2)))))


# Cálculo Límites Enteros #
BASE <- 10
# Cálculos básicos
min_int <- floor(min(Variable) / BASE) * BASE
max_int <- ceiling(max(Variable) / BASE) * BASE
k_int_sug <- floor(1 + 3.322 * log10(N))
Rango_int <- max_int - min_int
Amplitud_raw <- Rango_int / k_int_sug

Amplitud_int <- ceiling(Amplitud_raw / 10) * 10
if(Amplitud_int == 0) Amplitud_int <- 10

# Generar cortes enteros
cortes_int <- seq(from = min_int, by = Amplitud_int, length.out = k_int_sug + 2)

cortes_int <- cortes_int[cortes_int <= (max_int + Amplitud_int)]

# Asegurar cobertura del máximo
while(max(cortes_int) < max(Variable)) {
  cortes_int <- c(cortes_int, max(cortes_int) + Amplitud_int)
}

K_real <- length(cortes_int) - 1
lim_inf_int <- cortes_int[1:K_real]
lim_sup_int <- cortes_int[2:(K_real+1)]

# Frecuencias 
inter_int <- cut(Variable, breaks = cortes_int, include.lowest = TRUE, right = FALSE)
ni_int <- as.vector(table(inter_int))

# Cálculos de Frecuencias
hi_int <- (ni_int / N) * 100
Ni_asc_int <- cumsum(ni_int)
Ni_desc_int <- rev(cumsum(rev(ni_int)))
Hi_asc_int <- cumsum(hi_int)
Hi_desc_int <- rev(cumsum(rev(hi_int)))

# Construcción del Dataframe Entero
TDF_Enteros <- data.frame(
  Li = lim_inf_int,
  Ls = lim_sup_int,
  MC = (lim_inf_int + lim_sup_int) / 2,
  ni = ni_int,
  hi = round(hi_int, 2),
  Ni_asc = Ni_asc_int,
  Ni_desc = Ni_desc_int,
  Hi_asc = round(Hi_asc_int, 2),
  Hi_desc = round(Hi_desc_int, 2))

3 Tabla de Distribución de Frecuencias

3.1 Tabla con Límites Decimales

#### Crear de fila de totales ####
totales_dec <- c("TOTAL", "-", "-", sum(TDF_Decimal$ni), 100, "-", "-", "-", "-")
TDF_Dec_Final <- rbind(mutate(TDF_Decimal, across(everything(), as.character)), totales_dec)

# Generar GT Decimal
TDF_Dec_Final %>%
  gt() %>%
  tab_header(title = md("**Tabla N°1 de Distribución de Frecuencias de Latitud (°)**")) %>%
  cols_label(
    Li = "Lim. Inf", 
    Ls = "Lim. Sup", 
    MC = "Marca Clase", 
    ni = "Frec. Abs (ni)", 
    hi = "Frec. Rel (%)", 
    Ni_asc = "Ni (Asc)", 
    Ni_desc = "Ni (Desc)", 
    Hi_asc = "Hi Asc (%)", 
    Hi_desc = "Hi Desc (%)"
  ) %>%
  tab_options(heading.title.font.size = px(14), column_labels.background.color = "#F0F0F0")
Tabla N°1 de Distribución de Frecuencias de Latitud (°)
Lim. Inf Lim. Sup Marca Clase Frec. Abs (ni) Frec. Rel (%) Ni (Asc) Ni (Desc) Hi Asc (%) Hi Desc (%)
-53.15 -48.16 -50.66 3 0.04 3 7141 0.04 99.99
-48.16 -43.17 -45.67 0 0 3 7138 0.04 99.95
-43.17 -38.18 -40.68 1 0.01 4 7138 0.05 99.95
-38.18 -33.19 -35.69 166 2.32 170 7137 2.37 99.94
-33.19 -28.2 -30.7 201 2.81 371 6971 5.18 97.62
-28.2 -23.21 -25.71 319 4.47 690 6770 9.65 94.81
-23.21 -18.22 -20.72 1247 17.46 1937 6451 27.11 90.34
-18.22 -13.23 -15.73 1899 26.59 3836 5204 53.7 72.88
-13.23 -8.24 -10.74 1073 15.03 4909 3305 68.73 46.29
-8.24 -3.25 -5.75 1363 19.09 6272 2232 87.82 31.26
-3.25 1.74 -0.76 159 2.23 6431 869 90.05 12.17
1.74 6.73 4.23 368 5.15 6799 710 95.2 9.94
6.73 11.71 9.22 342 4.79 7141 342 99.99 4.79
TOTAL - - 7141 100 - - - -

3.2 Tabla con Límites Enteros

#### Crear de fila de totales ####
totales_int <- c("TOTAL", "-", "-", sum(TDF_Enteros$ni), 100, "-", "-", "-", "-")
TDF_Int_Final <- rbind(mutate(TDF_Enteros, across(everything(), as.character)), totales_int)

# Generar GT Enteros
TDF_Int_Final %>%
  gt() %>%
  tab_header(
    title = md("**Tabla N°2 de Distribución de Frecuencias de Latitud (°)**")) %>%
  cols_label(
    Li = "Lim. Inf", 
    Ls = "Lim. Sup", 
    MC = "Marca Clase", 
    ni = "Frec. Abs (ni)", 
    hi = "Frec. Rel (%)", 
    Ni_asc = "Ni (Asc)", 
    Ni_desc = "Ni (Desc)", 
    Hi_asc = "Hi Asc (%)", 
    Hi_desc = "Hi Desc (%)"
  ) %>%
  
  fmt_number(columns = c(Li, Ls), decimals = 0) %>%
  fmt_number(columns = c(hi, Hi_asc, Hi_desc), decimals = 2) %>%
  tab_options(heading.title.font.size = px(14), column_labels.background.color = "#F0F0F0")
Tabla N°2 de Distribución de Frecuencias de Latitud (°)
Lim. Inf Lim. Sup Marca Clase Frec. Abs (ni) Frec. Rel (%) Ni (Asc) Ni (Desc) Hi Asc (%) Hi Desc (%)
-60 -50 -55 3 0.04 3 7141 0.04 100
-50 -40 -45 0 0 3 7138 0.04 99.96
-40 -30 -35 300 4.2 303 7138 4.24 99.96
-30 -20 -25 1216 17.03 1519 6838 21.27 95.76
-20 -10 -15 2821 39.5 4340 5622 60.78 78.73
-10 0 -5 2064 28.9 6404 2801 89.68 39.22
0 10 5 604 8.46 7008 737 98.14 10.32
10 20 15 133 1.86 7141 133 100 1.86
20 30 25 0 0 7141 0 100 0
TOTAL - - 7141 100 - - - -

4 Gráficos

4.1 Gráfico 1 – Frecuencia Local

color_sutil <- "#B0C4DE"

par(mar = c(8, 5, 4, 2)) 
barplot(TDF_Enteros$ni, 
        names.arg = TDF_Enteros$MC,
        main = "Gráfica N°1: Distribución de Cantidad de Plantas Solares por Latitud",
        cex.main = 1,
        xlab = "", 
        ylab = "Cantidad",
        col = color_sutil,
        space = 0,
        las = 2, 
        cex.names = 0.7)
mtext("Latitud (°)", side = 1, line = 4)

4.2 Gráfico 2 – Frecuencia Global

color_grafico <- "#B0C4DE"

par(mar = c(8, 5, 4, 2))
barplot(TDF_Enteros$ni, 
        main="Gráfica N°2: Distribución de Cantidades Globales de las Plantas Solares por Latitud",
        cex.main = 0.9,
        xlab = "",
        ylab = "Cantidad",
        names.arg = TDF_Enteros$MC,
        col = color_sutil,
        space = 0,
        cex.names = 0.7,
        las = 2,
        ylim = c(0, sum(TDF_Enteros$ni))) 
mtext("Latitud (°)", side = 1, line = 4)

4.3 Gráfico 3 – Porcentaje Local

color_grafico <- "#B0C4DE"

par(mar = c(8, 5, 4, 2))
barplot(TDF_Enteros$hi, 
        main="Gráfica N°3: Distribución Porcentual de las Plantas Solares por Latitud",
        cex.main = 1,
        xlab = "",
        ylab = "Porcentaje (%)",
        col = color_sutil,
        space = 0,
        names.arg = TDF_Enteros$MC,
        cex.names = 0.7,
        las = 2,
        ylim = c(0, max(TDF_Enteros$hi) * 1.1))
mtext("Latitud (°)", side = 1, line = 4)

4.4 Gráfico 4 – Porcentaje Global

color_grafico <- "#B0C4DE"

par(mar = c(8, 5, 4, 2))
barplot(TDF_Enteros$hi, 
        main="Gráfica N°4: Distribución Porcentual Global de las Plantas Solares por Latitud",
        cex.main = 1,
        xlab = "",
        ylab = "Porcentaje (%)",
        col = color_sutil,
        space = 0,
        names.arg = TDF_Enteros$MC,
        las = 2,
        cex.names = 0.7,
        ylim = c(0, 100)) 
mtext("Latitud (°)", side = 1, line = 4)

4.5 Gráfico 5 – Diagrama de Cajas (Boxplot)

par(mar = c(5, 5, 4, 2))
boxplot(Variable, 
        horizontal = TRUE,
        col = color_sutil,
        xlab = "Latitud (°)",
        cex.main = 0.9,
        main = "Gráfica N°5: Distribución de la Latitud en las Plantas Solares")

4.6 Gráfico 6 – Ojivas de Frecuencia Acumulada

par(mar = c(5, 5, 4, 10), xpd = TRUE)

# Coordenadas
x_asc <- TDF_Enteros$Ls  
x_desc <- TDF_Enteros$Li 
y_asc <- TDF_Enteros$Ni_asc
y_desc <- TDF_Enteros$Ni_desc

# 1. Dibujar la Ascendente 
plot(x_asc, y_asc,
     type = "b", 
     main = "Gráfica N°6: Ojivas Ascendentes y Descendentes de la Distribución de la Latitud en las Plantas Solares",
     cex.main = 0.7,
     xlab = "Latitud (°)",
     ylab = "Frecuencia Acumulada",
     col = "black",
     pch = 19, 
     xlim = c(min(x_desc), max(x_asc)), 
     ylim = c(0, sum(TDF_Enteros$ni))
)

# 2. Agregar la Descendente 
lines(x_desc, y_desc, col = "blue", type = "b", pch = 19)

grid()
legend("right", 
       legend = c("Ascendente", "Descendente"), 
       col = c("black", "blue"), 
       lty = 1, 
       pch = 1, 
       cex = 0.6, 
       inset = c(0.05, 0.05),
       bty = "n")

5 Indicadores Estadísticos

## INDICADORES DE TENDENCIA CENTRAL
# Media aritmética
media <- round(mean(Variable), 2)

# Mediana
mediana <- round(median(Variable), 2)

# Moda 
max_frecuencia <- max(TDF_Enteros$ni)
moda_vals <- TDF_Enteros$MC[TDF_Enteros$ni == max_frecuencia]
moda_txt <- paste(round(moda_vals, 2), collapse = ", ")

## INDICADORES DE DISPERSIÓN 
# Varianza
varianza <- var(Variable)

# Desviación Estándar
sd_val <- sd(Variable)

# Coeficiente de Variación
cv <- round((sd_val / abs(media)) * 100, 2)

## INDICADORES DE FORMA 
# Coeficiente de Asimetría
asimetria <- skewness(Variable, type = 2)

# Curtosis
curtosis <- kurtosis(Variable)

# Outliers
outliers_data <- boxplot.stats(Variable)$out

if(length(outliers_data) > 0) {
  num_out <- length(outliers_data)
  min_out <- round(min(outliers_data), 2)
  max_out <- round(max(outliers_data), 2)
  
  # Formato Total [Min; Max]
  msg_atipicos <- paste0("  ", num_out, " [", min_out, " ; ", max_out, "]")
} else {
  msg_atipicos <- "No hay presencia de valores atípicos"
}


tabla_indicadores <- data.frame(
  "Variable" = c("Latitud (°)"),
  "Rango_MinMax" = paste0("[", round(min(Variable), 2), "; ", round(max(Variable), 2), "]"),
  "X" = c(media),
  "Me" = c(mediana),
  "Mo" = c(moda_txt),
  "V" = c(varianza),
  "Sd" = c(sd_val),
  "Cv" = c(cv),
  "As" = c(asimetria),
  "K" = c(curtosis),
  "Outliers" = msg_atipicos
)

# Generar Tabla GT
tabla_conclusiones_gt <- tabla_indicadores %>%
  gt() %>%
  tab_header(title = md("**Tabla N°3 de Conclusiones**")) %>%
  tab_source_note(source_note = "Autor: Martin Sarmiento") %>%
  cols_label(
    Variable = "Variable",
    Rango_MinMax = "Rango",
    X = "Media (X)",
    Me = "Mediana (Me)",
    Mo = "Moda (Mo)",
    V = "Varianza (V)",
    Sd = "Desv. Est. (Sd)",
    Cv = "C.V. (%)",
    As = "Asimetría (As)",
    K = "Curtosis (K)",
    Outliers = "Outliers" 
  ) %>%
  tab_options(
    heading.title.font.size = px(16),
    column_labels.background.color = "#f0f0f0"
  )

tabla_conclusiones_gt
Tabla N°3 de Conclusiones
Variable Rango Media (X) Mediana (Me) Moda (Mo) Varianza (V) Desv. Est. (Sd) C.V. (%) Asimetría (As) Curtosis (K) Outliers
Latitud (°) [-53.15; 11.71] -12.73 -14.82 -15 95.67181 9.781197 76.84 0.2528149 0.1926481 4 [-53.15 ; -38.97]
Autor: Martin Sarmiento

6 Conclusiones

La variable “Latitud” fluctúa entre -53.15° y 11.71° y sus valores se encuentran alrededor de -14.82°, con una desviación estándar de 9.781197, siendo una variable heterogénea, cuyos valores se concentran en la parte media alta de la variable con la agregación de valores atípicos de 4 outliers; por todo lo anterior, el comportamiento de la variable es regular.