Exercícios

Introdução

A visualização de dados é uma etapa fundamental no processo de análise, pois permite transformar informações numéricas em representações gráficas capazes de facilitar a interpretação de padrões, tendências e relações entre variáveis. Por meio de gráficos adequados, torna-se possível compreender resultados complexos de forma mais intuitiva, apoiar tomadas de decisão e comunicar descobertas de maneira eficiente.

Neste exercício foram desenvolvidas diferentes técnicas de visualização utilizando a linguagem R, combinando recursos do R Base e da biblioteca Plotly para construção de gráficos estáticos e interativos. As atividades abordam análises relacionadas a desempenho computacional em ambientes de Fog Computing, distribuições estatísticas, monitoramento de recursos computacionais e exploração de dados da plataforma Netflix.

As questões de 1 a 6 utilizam funções tradicionais do R para geração de gráficos, incluindo linhas, barras, histogramas, pizza e boxplots. Já as questões de 7 a 10 empregam o Plotly, permitindo visualizações interativas para análise de conteúdos da Netflix, distribuição por país, evolução temporal e comportamento de gêneros cinematográficos. O objetivo principal deste trabalho é aplicar conceitos de visualização de dados para representar informações de maneira clara, identificar comportamentos relevantes nos conjuntos analisados e interpretar os resultados obtidos a partir dos gráficos produzidos. —

Questão 1

Foram utilizados os dados de tempo médio de resposta (Mean Response Time – MRT) para diferentes quantidades de fog nodes e diferentes intervalos entre requisições. O primeiro gráfico compara diretamente o desempenho entre cenários com e sem Fog Computing, enquanto os gráficos de barras utilizam escala logarítmica para facilitar a comparação entre valores muito distintos.

Os resultados mostram que o aumento do número de fog nodes reduz significativamente o tempo de resposta do sistema. O cenário com apenas 1 fog apresenta elevados tempos iniciais, enquanto configurações com 10 ou 15 fogs apresentam desempenho mais estável e rápido. Isso indica que a distribuição do processamento próxima à origem dos dados melhora a eficiência computacional.

clock <- c(0.1, 0.5, 1, 1.5, 2, 2.5, 3)

MRT_1F <- c(
  517.1468515630205, 85.13094142168089, 30.333207896694553,
  12.694776264558937, 3.3041601673945418, 1.1823111717498882,
  1.1892293502386786
)

MRT_3F <- c(
  156.68929936163462, 11.540837783562276, 0.4512835621696538,
  0.4509797929766453, 0.4502068233039181,
  0.4496185276300172, 0.4543157082191288
)

MRT_5F <- c(
  83.90319666471157, 0.3068151086494968,
  0.30522314133037304, 0.3072588968084928,
  0.30655265997285697, 0.3055812715727718,
  0.3053297166713006
)

MRT_10F <- c(
  29.55430642951759, 0.19832832665772515,
  0.1971923924717474, 0.19796648905716516,
  0.19615594370806338, 0.2034569237883263,
  0.19617420889447737
)

MRT_15F <- c(
  11.317736530583566, 0.167364215666193,
  0.16172168266811013, 0.16701085329580515,
  0.1598052657153692, 0.1645934043532696,
  0.16216563797118075
)

MRT_sem_F <- c(
  11.93430909937736, 0.6095414637034009,
  0.6060645101029295, 0.612167181646899,
  0.6146761002685637, 0.6096747087200697,
  0.6125810476877268
)

layout(matrix(c(
  1,1,
  2,3,
  4,5,
  6,6
), nrow = 4, byrow = TRUE))

plot(
  clock,
  MRT_1F,
  type = "b",
  pch = 16,
  col = "black",
  ylim = c(0, 550),
  xlab = "Time between Things requests",
  ylab = "Response Time (sec.)",
  main = "Response Time Analysis"
)

lines(clock, MRT_3F, type = "b", pch = 15, col = "red")
lines(clock, MRT_5F, type = "b", pch = 17, col = "blue")
lines(clock, MRT_10F, type = "b", pch = 18, col = "green")
lines(clock, MRT_15F, type = "b", pch = 8, col = "purple")
lines(clock, MRT_sem_F, type = "b", pch = 4, col = "orange")

legend(
  "topright",
  legend = c(
    "1 Fog", "3 Fogs", "5 Fogs",
    "10 Fogs", "15 Fogs", "Without Fog"
  ),
  col = c("black","red","blue","green","purple","orange"),
  pch = c(16,15,17,18,8,4),
  cex = 0.8
)

plot_bar <- function(data, title_leg){

  barplot(
    matrix(c(MRT_sem_F, data), nrow = 2, byrow = TRUE),
    beside = TRUE,
    names.arg = clock,
    log = "y",
    col = c("#E6E6E6", "#666666"),
    xlab = "Time between Things requests",
    ylab = "Response time (s)",
    main = title_leg[2]
  )

  legend(
    "topright",
    legend = title_leg,
    fill = c("#E6E6E6", "#666666"),
    cex = 0.8
  )
}

plot_bar(MRT_1F, c("Without Fog", "1 Fog"))
plot_bar(MRT_3F, c("Without Fog", "3 Fogs"))
plot_bar(MRT_5F, c("Without Fog", "5 Fogs"))
plot_bar(MRT_10F, c("Without Fog", "10 Fogs"))
plot_bar(MRT_15F, c("Without Fog", "15 Fogs"))

Questão 2

Foi criado um gráfico de barras empilhadas para representar a relação entre qualidade percebida da refeição e faixa de preço. Cada barra mostra a proporção das categorias “Good”, “Very Good” e “Excellent”.

Observa-se que refeições classificadas como “Excellent” tornam-se mais frequentes em faixas de preço mais altas, enquanto avaliações “Good” predominam em refeições mais baratas. O resultado sugere uma associação positiva entre aumento do preço e percepção de qualidade.

meal_data <- matrix(
  c(
    53.8, 43.6, 2.6,
    33.9, 54.2, 11.9,
    2.6, 60.5, 36.8,
    0.0, 21.4, 78.6
  ),
  nrow = 3,
  byrow = FALSE
)

colnames(meal_data) <- c(
  "$10-19",
  "$20-29",
  "$30-39",
  "$40-49"
)

rownames(meal_data) <- c(
  "Good",
  "Very Good",
  "Excellent"
)

barplot(
  meal_data,
  main = "Qualidade da Refeição por Faixa de Preço",
  xlab = "Faixa de Preço",
  ylab = "Porcentagem",
  col = c("#A8D5BA", "#4A90E2", "#F5A623"),
  legend.text = TRUE,
  args.legend = list(x = "topright")
)

Questão 3

Foi realizado o filtro do mês de maio no dataset airquality e posteriormente as temperaturas foram convertidas de Fahrenheit para Celsius utilizando a expressão fornecida no enunciado. Em seguida, foi criado um histograma acompanhado de uma curva de densidade.

O gráfico mostra a distribuição das temperaturas durante o mês de maio, permitindo observar a faixa mais frequente de valores e possíveis concentrações. A curva de densidade suaviza a distribuição e auxilia na identificação do comportamento geral das temperaturas.

maio <- subset(airquality, Month == 5)

maio$TempC <- (maio$Temp - 32) / 1.8

temp_clean <- na.omit(maio$TempC)

hist(
  temp_clean,
  probability = TRUE,
  main = "Histograma das Temperaturas em Maio",
  xlab = "Temperatura (°C)",
  ylab = "Densidade",
  col = "lightblue",
  border = "white"
)

lines(
  density(temp_clean),
  col = "red",
  lwd = 2
)

Questão 4

Foi utilizado o dataset de vendas por país fornecido no exercício para construir um gráfico de pizza contendo proporções percentuais, legenda e cores distintas para cada categoria.

O gráfico permite identificar rapidamente quais países possuem maior participação no total de vendas. Países com fatias maiores representam maior contribuição relativa ao volume total comercializado, facilitando comparações proporcionais entre regiões.

sales <- data.frame(
  Country = c(
    "US",
    "UK",
    "Australia",
    "Germany",
    "France",
    "Canada"
  ),
  
  Sales = c(
    150,
    120,
    90,
    80,
    70,
    60
  )
)

pct <- round(
  sales$Sales / sum(sales$Sales) * 100,
  1
)

labels <- paste0(
  sales$Country,
  " (",
  pct,
  "%)"
)

colors <- rainbow(nrow(sales))

pie(
  sales$Sales,
  labels = labels,
  col = colors,
  main = "Porcentagem Total de Vendas por País"
)

legend(
  "topright",
  legend = sales$Country,
  fill = colors,
  cex = 0.8
)

Questão 5

Utilizou-se o conjunto InsectSprays para construir boxplots comparando diferentes inseticidas, removendo a exibição dos outliers conforme solicitado.

Os resultados mostram diferenças relevantes na mediana e dispersão da quantidade de insetos entre os tratamentos. Inseticidas com menores medianas indicam maior eficiência no controle populacional, enquanto caixas mais dispersas sugerem maior variabilidade nos resultados experimentais.

boxplot(
  count ~ spray,
  data = InsectSprays,
  outline = FALSE,
  col = "yellow",
  main = "Contagem de Insetos por Tipo de Inseticida",
  xlab = "Inseticida",
  ylab = "Quantidade de Insetos"
)

Questão 6

Os arquivos de monitoramento foram processados convertendo o tempo (currentTime) para horas contínuas e transformando diferentes unidades de memória para megabytes. Em seguida, foram produzidos gráficos temporais para cada cenário de carga computacional.

Os gráficos permitem observar a evolução do consumo de memória ao longo do tempo. Cenários com maior workload tendem a apresentar utilização mais intensa ou variável dos recursos computacionais, evidenciando impacto direto da carga de trabalho sobre o consumo de memória da máquina virtual.

process_mem <- function(file_name, title){

  if(file.exists(file_name)){

    df <- read.csv(file_name)

    df$currentTime <- as.POSIXct(df$currentTime)

    df$currentTime <- as.numeric(
      difftime(
        df$currentTime,
        df$currentTime[1],
        units = "hours"
      )
    )

    convert_mem <- function(mem_str){

      value <- as.numeric(
        str_extract(mem_str, "[0-9.]+")
      )

      unit <- toupper(
        str_extract(mem_str, "[A-Za-z]+")
      )

      if(unit %in% c("TB","T")){
        return(value * 1000000)
      }

      if(unit %in% c("GB","G")){
        return(value * 1024)
      }

      if(unit %in% c("MB","M")){
        return(value)
      }

      if(unit %in% c("KB","K")){
        return(value / 1024)
      }

      return(value)
    }

    df$usedMemory <- sapply(
      df$usedMemory,
      convert_mem
    )

    plot(
      df$currentTime,
      df$usedMemory,
      type = "l",
      col = "blue",
      lwd = 2,
      xlab = "Tempo (horas)",
      ylab = "Memória Utilizada (MB)",
      main = title
    )
  }
}

layout(matrix(1:4, nrow = 2, byrow = TRUE))

process_mem(
  "monitoringCloudData_NONE.csv",
  "Memory Analysis - NONE"
)

process_mem(
  "monitoringCloudData_0.1.csv",
  "Memory Analysis - 0.1"
)

process_mem(
  "monitoringCloudData_0.5.csv",
  "Memory Analysis - 0.5"
)

process_mem(
  "monitoringCloudData_1.csv",
  "Memory Analysis - 1.0"
)

Questão 7

Foi filtrado o conjunto Netflix para considerar apenas conteúdos associados a um único país de origem. Posteriormente, selecionaram-se os dez países com maior quantidade de produções e foi criado um gráfico de pizza utilizando Plotly.

Os resultados revelam concentração de conteúdo em poucos países, indicando desigualdade na distribuição da produção disponível na plataforma. Países com maiores fatias representam forte participação no catálogo da Netflix.

netflix <- read.csv(
  "netflix_titles.csv",
  stringsAsFactors = FALSE
)

q7_data <- netflix %>%
  filter(
    !is.na(country),
    country != "",
    !grepl(",", country)
  ) %>%
  count(country, sort = TRUE) %>%
  head(10)

plot_ly(
  q7_data,
  labels = ~country,
  values = ~n,
  type = "pie"
) %>%
  layout(
    title = "Top 10 Países com Mais Conteúdo"
  )

Questão 8

Com base nos dez países identificados anteriormente, foi construída uma tabela interativa utilizando Plotly contendo o nome do país e a quantidade total de conteúdos disponíveis.

A tabela complementa o gráfico da questão anterior ao apresentar valores absolutos, permitindo comparações mais precisas entre países além da percepção visual fornecida pelo gráfico de pizza.

plot_ly(
  type = "table",

  header = list(
    values = c(
      "<b>País</b>",
      "<b>Total de conteúdos</b>"
    ),

    align = "center",

    fill = list(
      color = "gray"
    ),

    font = list(
      color = "white",
      size = 12
    )
  ),

  cells = list(
    values = list(
      q7_data$country,
      q7_data$n
    ),

    align = "center"
  )
)

Questão 9

Os dados foram agrupados por década de lançamento e tipo de conteúdo (filme ou série). Em seguida, foi produzido um gráfico de linhas com Plotly utilizando cores distintas para cada categoria.

Observa-se crescimento significativo da quantidade de produções ao longo das décadas mais recentes. Além disso, filmes apresentam maior volume absoluto em comparação às séries, embora ambos mostrem tendência de expansão do catálogo da plataforma ao longo do tempo.

q9_data <- netflix %>%
  filter(!is.na(release_year)) %>%
  mutate(
    Decade = floor(release_year / 10) * 10
  ) %>%
  group_by(Decade, type) %>%
  summarise(
    Count = n(),
    .groups = "drop"
  )

series_data <- q9_data %>%
  filter(type == "TV Show")

movies_data <- q9_data %>%
  filter(type == "Movie")

plot_ly() %>%

  add_trace(
    data = series_data,
    x = ~Decade,
    y = ~Count,
    type = "scatter",
    mode = "lines+markers",
    name = "Séries",
    line = list(color = "blue")
  ) %>%

  add_trace(
    data = movies_data,
    x = ~Decade,
    y = ~Count,
    type = "scatter",
    mode = "lines+markers",
    name = "Filmes",
    line = list(color = "yellow")
  ) %>%

  layout(
    title = "Quantidade de Conteúdo por Década",
    xaxis = list(title = "Década"),
    yaxis = list(title = "Quantidade")
  )

Questão 10

Foram selecionados apenas filmes lançados entre 2000 e 2010. Para obras com múltiplos gêneros, considerou-se apenas o primeiro gênero listado, conforme solicitado. O gráfico de barras agrupadas compara a quantidade anual de lançamentos dos gêneros “Dramas”, “Action & Adventure” e “Comedies”.

Os resultados permitem identificar diferenças temporais entre gêneros cinematográficos. Alguns apresentam maior frequência de lançamentos em determinados períodos, evidenciando mudanças no perfil de produção e preferência do catálogo ao longo dos anos analisados.

q10_data <- netflix %>%

  filter(
    release_year >= 2000,
    release_year <= 2010,
    type == "Movie"
  ) %>%

  mutate(
    First_Genre = str_trim(
      sapply(
        str_split(listed_in, ","),
        `[`,
        1
      )
    )
  ) %>%

  filter(
    First_Genre %in% c(
      "Dramas",
      "Action & Adventure",
      "Comedies"
    )
  ) %>%

  group_by(
    release_year,
    First_Genre
  ) %>%

  summarise(
    Count = n(),
    .groups = "drop"
  )

plot_ly(
  q10_data,
  x = ~release_year,
  y = ~Count,
  color = ~First_Genre,
  type = "bar",

  colors = c(
    "#1f77b4",
    "#ff7f0e",
    "#2ca02c"
  )
) %>%

  layout(
    barmode = "group",

    title = "Filmes por Gênero entre 2000 e 2010",

    xaxis = list(
      title = "Ano",
      dtick = 1
    ),

    yaxis = list(
      title = "Quantidade de Filmes"
    )
  )