Introdução

Nesta aula, vamos construir e visualizar diferentes maneiras de gerar sequências de valores que podem ser usadas como base para esquemas de reforço. A ideia central é simples: dependendo da distribuição ou regra usada para gerar os intervalos ou razões, obtemos propriedades distintas de variabilidade, previsibilidade e dispersão.

Ao longo do material, veremos:

  1. amostras determinísticas baseadas em progressões aritméticas;
  2. amostras determinísticas baseadas em progressões geométricas;
  3. séries geométricas inteiras;
  4. uma discretização determinística da distribuição normal;
  5. a progressão de Fleshler e Hoffman (1962);
  6. uma adaptação inteira dessa progressão para esquemas VR;

Preparação do ambiente

em que cada \(x_i\) representa, por exemplo:

  • um intervalo em um esquema VI;
  • uma razão em um esquema VR;
  • ou uma amostra de valores com propriedades específicas de dispersão, assimetria ou previsibilidade.

Ao longo da aula, veremos cinco estratégias principais:

  • amostra determinística por série aritmética;
  • amostra determinística por série geométrica;
  • amostra determinística aproximando uma distribuição normal;
  • progressões de Fleshler e Hoffman para esquemas variáveis.

Amostra determinística por série aritmética

Uma série aritmética cresce ou decresce por uma diferença constante. Seu formato geral é:

\[\begin{align} x_i = \bar{x} + \left(i - \frac{N+1}{2}\right)d \end{align}\]

em que:

  • \(N\) é o número de termos;
  • \(\bar{x}\) é a média desejada;
  • \(d\) é o passo.

Função

aritmetica = function(N, media, passo) {
  
  d_max = 2 * media / (N - 1)
  
  if (passo >= d_max) {
    stop(paste("Passo muito grande. Use passo <", round(d_max, 3)))
  }
  
  x = media + (1:N - (N + 1)/2) * passo
  
  return(x)
}

Exemplo

x = aritmetica(N = 12, media = 30, passo = 3)
x
##  [1] 13.5 16.5 19.5 22.5 25.5 28.5 31.5 34.5 37.5 40.5 43.5 46.5

Visualização

plot(x, type = "b", pch = 16,
     xlab = "Posição na sequência",
     ylab = "Valor",
     main = "Série aritmética")
abline(h = mean(x), lty = 2)

Interpretação

Essa função é útil quando queremos uma sequência perfeitamente previsível, simétrica em torno da média e com espaçamento constante entre valores.

Ela pode ser usada para construir listas didáticas de intervalos ou razões, mas não produz a irregularidade típica de um esquema variável real.

Amostra determinística por série geométrica

Em uma série geométrica, cada termo é obtido multiplicando o anterior por uma razão constante \(r\).

\[\begin{align} x_i = a r^{i-1} \end{align}\]

Quando queremos fixar a média da sequência, podemos resolver o valor inicial \(a\) a partir da soma total desejada.

Função

geometrica = function(N, media, r) {
  a = media * N * (r - 1) / (r^N - 1)
  x = a * r^(0:(N-1))
  x
}

Exemplo

x = geometrica(N = 10, media = 20, r = 1.2)
x
##  [1]  7.704551  9.245462 11.094554 13.313465 15.976158 19.171389 23.005667
##  [8] 27.606801 33.128161 39.753793
mean(x)
## [1] 20

Visualização

plot(x, type = "b", pch = 16,
     xlab = "Posição na sequência",
     ylab = "Valor",
     main = "Série geométrica")
abline(h = mean(x), lty = 2)

Interpretação

Comparada à série aritmética, a progressão geométrica produz uma expansão mais rápida entre valores sucessivos. Em esquemas de reforço, isso pode ser interessante quando se quer maior concentração de valores pequenos e poucos valores muito grandes, ou o oposto, dependendo da ordem da série.

Série geométrica inteira

Em alguns contextos, especialmente em esquemas VR ou VI discretizados em unidades inteiras, queremos sequências compostas apenas por números inteiros.

A função abaixo procura sequências geométricas inteiras cuja média seja um inteiro positivo especificado.

Função

geometricas_inteiras = function(media, N_max = NULL, r_max = NULL) {
  if (media %% 1 != 0 || media < 1) {
    stop("A média deve ser um inteiro positivo.")
  }
  
  resultados = data.frame(
    N = integer(),
    r = integer(),
    a = integer(),
    soma = integer(),
    stringsAsFactors = FALSE
  )
  
  series = list()
  
  if (is.null(N_max)) {
    N_max = 100
  }
  
  idx = 1
  
  for (N in 2:N_max) {
    soma_total = media * N
    
    if (soma_total < (2^N - 1)) {
      break
    }
    
    r = 2
    while (TRUE) {
      S = sum(r^(0:(N - 1)))
      
      if (S > soma_total) {
        break
      }
      
      a = soma_total / S
      
      if (a %% 1 == 0 && a >= 1) {
        serie = a * r^(0:(N - 1))
        
        resultados[idx, ] = list(
          N = N,
          r = r,
          a = a,
          soma = sum(serie)
        )
        
        series[[idx]] = serie
        idx = idx + 1
      }
      
      r = r + 1
      
      if (!is.null(r_max) && r > r_max) {
        break
      }
    }
  }
  
  if (nrow(resultados) == 0) {
    return(list(resumo = NULL, series = NULL))
  }
  
  resultados$serie = vapply(series,
                            function(x) paste(x, collapse = ", "),
                            character(1))
  
  list(
    resumo = resultados,
    series = series
  )
}

Exemplo

Vamos buscar séries inteiras com média 12:

res_geo_int = geometricas_inteiras(media = 12, N_max = 12, r_max = 10)
res_geo_int$resumo
## # A tibble: 4 × 5
##       N     r     a  soma serie
##   <int> <dbl> <dbl> <dbl> <chr>
## 1     2     2     8    24 8, 16
## 2     2     3     6    24 6, 18
## 3     2     5     4    24 4, 20
## 4     2     7     3    24 3, 21

Se houver séries disponíveis, vamos inspecionar uma delas:

if (!is.null(res_geo_int$series)) {
  res_geo_int$series[[1]]
}
## [1]  8 16

Visualização

if (!is.null(res_geo_int$series)) {
  res_geo_int$series[[1]]
}
## [1]  8 16

Interpretação

Esse tipo de função é especialmente útil quando há restrições práticas: por exemplo, razões precisam ser inteiras e, ainda assim, queremos preservar certa estrutura geométrica.

Amostra determinística baseada na distribuição normal

Agora vamos construir uma amostra determinística inspirada na distribuição normal. A ideia é dividir a distribuição acumulada em fatias de mesma probabilidade e representar cada fatia por seu valor esperado condicional.

A distribuição normal com média \(\mu\) e desvio-padrão \(\sigma\) tem densidade:

\[\begin{align} f(x) = \frac{1}{\sigma\sqrt{2\pi}} \exp\left( -\frac{(x-\mu)^2}{2\sigma^2} \right) \end{align}\]

Função

A função abaixo gera \(N\) valores que cobrem sistematicamente a distribuição.

normal_deterministica = function(N, mu = 0, sigma = 1, embaralhar = TRUE) {
  p = seq(0, 1, length.out = N + 1)
  z = qnorm(p)
  
  x = numeric(N)
  
  for (i in 1:N) {
    a = z[i]
    b = z[i + 1]
    
    da = if (is.infinite(a)) 0 else dnorm(a)
    db = if (is.infinite(b)) 0 else dnorm(b)
    
    prob_fatia = pnorm(b) - pnorm(a)
    x[i] = mu + sigma * (da - db) / prob_fatia
  }
  
  if (embaralhar) {
    x = sample(x)
  }
  
  x
}

Exemplo

serie_normal = normal_deterministica(N = 20, mu = 30, sigma = 5, embaralhar = TRUE)
serie_normal
##  [1] 35.76604 25.31969 29.05377 32.27064 32.99160 26.21853 31.59435 27.72936
##  [9] 22.76373 34.68031 37.23627 28.40565 29.68626 33.78147 24.23396 27.00840
## [17] 30.94623 40.31356 19.68644 30.31374
mean(serie_normal)
## [1] 30
sd(serie_normal)
## [1] 5.086893

Visualização

plot(serie_normal,
     type = "b",
     pch = 16,
     xlab = "Posição na sequência",
     ylab = "Valor",
     main = "Amostra determinística baseada na normal")
abline(h = mean(serie_normal), lty = 2)

Veja também o histograma de valores:

hist(serie_normal,
     breaks = 8,
     main = "Distribuição dos valores gerados",
     xlab = "Valor")

Interpretação

Esse método é útil quando se quer cobrir o espaço de valores de forma regular, sem depender de amostragem puramente aleatória.

Progressão de Fleshler e Hoffman (1962)

Fleshler e Hoffman propuseram uma progressão para distribuição de intervalos em esquemas variáveis, buscando evitar problemas associados a listas arbitrárias ou excessivamente irregulares.

A função abaixo implementa a forma contínua dessa progressão.

Função

fleshler_hoffman = function(media, N) {
  if (!is.numeric(media) || length(media) != 1 || media <= 0) {
    stop("`media` deve ser um número positivo.")
  }
  
  if (!is.numeric(N) || length(N) != 1 || N < 1 || N %% 1 != 0) {
    stop("`N` deve ser um inteiro positivo.")
  }
  
  t = numeric(N)
  
  for (n in 1:N) {
    if (n == N) {
      t[n] = media * (1 + log(N))
    } else {
      t[n] = media * (
        1 + log(N) +
          (N - n) * log(N - n) -
          (N - n + 1) * log(N - n + 1)
      )
    }
  }
  
  return(t)
}

Exemplo

fh = fleshler_hoffman(media = 30, N = 20)
fh
##  [1]   0.7628222   2.3424993   4.0100244   5.7757494   7.6519720   9.6534561
##  [7]  11.7981392  14.1081127  16.6110143  19.3420561  22.3470762  25.6873023
## [13]  29.4471295  33.7475414  38.7709506  44.8116047  52.3917509  62.5856931
## [19]  78.2831374 119.8719682
mean(fh)
## [1] 30

Visualização

plot(fh,
     type = "b",
     pch = 16,
     xlab = "Posição na sequência",
     ylab = "Valor",
     main = "Progressão de Fleshler e Hoffman")
abline(h = mean(fh), lty = 2)

Veja também o histograma da distribuição

hist(fh,
     breaks = 10,
     main = "Valores de Fleshler e Hoffman",
     xlab = "Valor")

7. Adaptação inteira para VR baseada em Fleshler e Hoffman

Para esquemas de razão variável (VR), precisamos de valores inteiros e, além disso, razões não podem ser zero. A função abaixo adapta a sequência contínua de Fleshler e Hoffman para uma sequência inteira com média preservada.

Função

fh_ratio = function(media, N, seed = NULL) {
  
  if (!is.null(seed)) set.seed(seed)
  
  x = fleshler_hoffman(media, N)
  
  x_int = floor(x)
  
  x_int[x_int < 1] = 1
  
  soma_alvo = media * N
  dif = soma_alvo - sum(x_int)
  
  if (dif > 0) {
    frac = x - x_int
    idx = order(frac, decreasing = TRUE)
    x_int[idx[1:dif]] = x_int[idx[1:dif]] + 1
    
  } else if (dif < 0) {
    frac = x - x_int
    idx = order(frac)
    
    for (i in idx) {
      if (x_int[i] > 1) {
        x_int[i] = x_int[i] - 1
        dif = dif + 1
        if (dif == 0) break
      }
    }
  }
  
  x_int = sample(x_int)
  
  return(x_int)
}

Exemplo

Vamos gerar um exemplo de VR 20 com 30 elementos.

vr_fh = fh_ratio(media = 20, N = 30, seed = 123)
vr_fh
##  [1] 13 19 12  2  8 17 25  9  3 21 50 30  7 43  6 38  5 88 34 16  2  1 28 23 60
## [26] 11 14  1 10  4
mean(vr_fh)
## [1] 20
sum(vr_fh)
## [1] 600

Visualização

plot(vr_fh,
     type = "b",
     pch = 16,
     xlab = "Posição na lista",
     ylab = "Razão",
     main = "Lista VR inteira baseada em Fleshler-Hoffman")
abline(h = mean(vr_fh), lty = 2)

Veja também o histograma

hist(vr_fh,
     breaks = 10,
     main = "Distribuição de razões na lista VR",
     xlab = "Razão")

A vantagem dessa abordagem é combinar:

  • média controlada;
  • valores inteiros;
  • ausência de zeros;
  • dispersão inspirada em uma progressão clássica.