Primeira vez aqui? Seja bem vindo e cheque o FAQ!
x

Considere que os gastos mensais de uma pessoa podem ser modelados por uma distribuição normal. Se essa pessoa investe 250000 reais e tem um ganho de 1% líquido ao mês, por quantos meses em média ela consegue viver sem trabalhar?

+1 voto
81 visitas
perguntada Mai 18 em Estatística por Pedro Henrique T (16 pontos)  

Marcelo recebeu 250000 reais de herança e deseja ficar um
período sem trabalhar. Ele por levar uma vida minimalista e já
possuir imóvel, tem gastos mensais que podem ser bem modelados
por uma distribuição normal com média 3000 e variância 1000.
Considere também que ele tem acesso a um investimento que dá
líquido 1% ao mês. (a) Por quantos meses em média ele consegue
viver sem trabalhar? (b) Plot a distribuição do número de meses
que ele pode ficar sem trabalhar. (c) Considere agora que a
variância da sua distribuição de gastos aumenta para 2000. Como
isso afeta os resultados? Sugira uma métrica mais robusta que a
média para informar o número de meses que ele pode ficar sem
trabalhar. Observação: Esse exercício pode ser implementado de
duas formas. Usando um loop while e usando uma recursão. Faça
uma função para cada uma das formas em python.

Compartilhe

1 Resposta

0 votos
respondida Mai 18 por Pedro Henrique T (16 pontos)  
editado Mai 21 por Pedro Henrique T

Com uma quantidade investida de 250000 reais, um rendimento de 1% sobre o valor na conta e considerando a distribuição do gasto mensal como sendo normal com média 3000 e variância 1000, o cálculo básico realizado tanto na programação utilizando o while, quanto na programação utilizando recursão é

\[AP_{i}= AP_{i-1}+R_{i}-G_{i},\]

ou seja, a aplicação no final do mês atual é igual a aplicação no final do mês anterior mais o rendimento menos o gasto do mês atual. Este cálculo deve ser realizado até que o valor da aplicação no mês anterior seja menor do que o gasto no mês atual.

Para simplificar a programação, no caso do While, decidi fazer o loop enquanto a aplicação fosse maior ou igual a 0, embora, ao encontrar a condição de parada, o algoritmo retorne o contador de meses com um mês contabilizado a mais. Devido a isso, deve ser subtraída uma unidade do contador de meses. A mesma ideia vale para a versão recursiva, de modo que o caso base da recursão é definido quando a aplicação assumir valores negativos.

A seguir tem-se as implementações de ambos os algoritmos.

import numpy as np
from scipy.stats import norm as rnorm
import matplotlib.pyplot as plt
from collections import Counter


#Versão com While.
def tempo_sem_precisar_trabalhar(aplicacao,variancia):
    meses=0
    while(aplicacao>=0):
        rendimento=0.01*aplicacao
        gastos_mensais= float(rnorm.rvs(loc=3000, scale=np.sqrt(variancia), size=1))
        aplicacao=aplicacao+rendimento-gastos_mensais
        meses+=1
    aplicacao=aplicacao+gastos_mensais
    meses=meses-1
    return {"resto_da_aplicação":aplicacao,"meses_sem_trabalhar":meses}

#Versão recursiva.
def func_recursiva(aplic,variancia,meses=0):
    if(aplic<0):return meses-1
    else:
        rendimento=0.01*aplic
        gastos_mensais=float(rnorm.rvs(loc=3000, scale=np.sqrt(variancia), size=1))
        aplic=aplic+rendimento-gastos_mensais
        meses=meses+1
        return func_recursiva(aplic,variancia,meses)

O algoritmo com While, além de retornar os meses, também retorna o valor que sobrou na conta de aplicação. Para o algoritmo recursivo, decidi deixá-lo de tal forma que ele retornasse apenas o que é de real interesse, ou seja, o contador de meses.

Para conseguir saber por quantos meses em média Marcelo consegue viver sem trabalhar é preciso replicar este cenário uma quantidade razoavelmente grande de vezes.

A seguir tem-se o código utilizado para replicar este cenário, calcular a quantidade média de meses sem trabalhar e gerar os gráficos de interesse.

 mc=[]
for i in range(1,50000+1):
    valores=tempo_sem_precisar_trabalhar(250000,1000)
    mc.append(valores)

mst=[]
resto=[]
for i in mc:
    mst.append(i.get("meses_sem_trabalhar"))
    resto.append(i.get("resto_da_aplicação"))

np.mean(mst)
y=Counter(mst)
x=[str(i) for i in np.unique(mst)]
plt.bar(x,y.values(), color="red")
plt.xlabel('meses sem trabalhar')
plt.ylabel('Freq')

A quantidade média de meses sem trabalhar, considerando uma distribuição de gastos com variância igual a 1000 é 179.5747 meses. O gráfico abaixo mostra a distribuição do número de meses que ele pode ficar sem trabalhar.

A imagem será apresentada aqui.

Se considerarmos que a variância de sua distribuição de gastos aumenta para 2000, a média de meses sem trabalhar passa a ser 179.5727 meses e a distribuição do número de meses que ele pode ficar sem trabalhar passa a ter uma dispersão maior, o que já era de se esperar. Em outras palavras, se a variância do gasto muda de 1000 para 2000, a média do número de meses sem trabalhar não muda, mas tem-se uma incerteza maior com relação ao valor informado pela estimativa da média.
A imagem será apresentada aqui.

Como a média é uma métrica que sofre uma grande influência de valores extremos, uma métrica robusta seria a mediana.

Quanto à quantidade restante na aplicação, percebeu-se que essa quantidade possui uma distribuição que é muito próxima a de uma uniforme quando a variância do gasto mensal é alta, já para valores da variância do gasto baixos (por exemplo var=10) essa similaridade com a uniforme não é observada.

O gráfico abaixo mostra a densidade da quantidade restante na aplicação quando a variância do gasto mensal é igual a 1000.
A imagem será apresentada aqui.

A seguir tem-se a implementação em R do problema. Apesar das rotinas serem muito semelhantes em Python e em R, o tempo de processamento foi infinitas vezes menor no R. Não cheguei a calcular os tempos, mas ao rodar o Monte Carlo para n=50000, demorou mais de 30 minutos para retornar o resultado no Python, enquanto que no R demorou menos de 3 minutos. Como sou iniciante no Python, posso ter implementado de um certo modo ineficiente, mas se alguém souber algum outro motivo para essa diferença de tempo de processamento, ficarei muito grato em saber.

tempo_sem_precisar_trabalhar=function(aplicacao,variancia){
  meses=0
    while(aplicacao>=0){
          rendimento=0.01*aplicacao
          gastos_mensais=rnorm(1,mean = 3000,sd = sqrt(variancia))
          aplicacao=aplicacao+rendimento-gastos_mensais
          meses=meses+1
    }
  aplicacao=aplicacao+gastos_mensais
  meses=meses-1
  return(list(resto_da_aplicacao=aplicacao,meses_sem_trabalhar=meses))
}

mc=list()
for(i in 1:50000) mc[[i]]=tempo_sem_precisar_trabalhar(250000,1000)

resto_da_aplicacao_mc=as.numeric(lapply(mc,function(x)x=x[[1]]))
meses_sem_trabalhar_mc=as.numeric(lapply(mc,function(x)x=x[[2]]))

X11();plot(hist(resto_da_aplicacao_mc))
X11();plot(as.factor(meses_sem_trabalhar_mc))




func_recursiva=function(aplic,variancia,meses=0){

  if(aplic<0) return(meses-1)
  else
    rendimento=0.01*aplic
    gastos_mensais=rnorm(1,mean = 3000,sd = sqrt(variancia))
    aplic=aplic+rendimento-gastos_mensais
    meses=meses+1
    return(func_recursiva(aplic,variancia,meses))

}

x=0
for(i in 1:50000)x[i]=func_recursiva(250000,1000)
x11();plot(as.factor(x))
comentou Mai 19 por danielcajueiro (5,376 pontos)  
Eu não analisei o seu codigo com cuidado, mas o fato de vc ficar chamando 50000 vezes a função torna o codigo mais lento, visto que o Python diferentemente do R, não é uma linguagem que segue o paradigma funcional. O float que vc usa aparentemente é desnecessario.  Com certeza olhando com cuidado, dá pra otimizar varias outras coisas.
comentou Jul 7 por Victor Candido (21 pontos)  
Pedro, muito boa a solução.

Gostei bastante. Principalmente o seu primeiro código, que mostra diferentes formas de recursão. Bastante ilustrativo. Eu também levaria em consideração o comentário do professor acerca do número de vezes que você chama a função para fazer a recursão.

Att.
...