記載のようなケースは、「打ち切りモデル」と呼ばれるモデルで解決できるように思います。打ち切りモデルというのは、本来は存在するデータ(つまり質問の緑線部分)が打ち切られて観測データとして存在しないケースにおいて本来の確率分布のモデルパラメータ(平均・分散)を推計しようというものです。
打ち切りモデルの考え方は、打ち切られてしまった緑線部分を欠損値とみなして欠損値部分のモデルパラメータが存在することを前提に、観測値の尤度が最大になるようにモデルパラメータをフィッティングさせていくというものです。
このモデルを構築するには、確率モデル専用のソフトウェアであるstanが必要です。(もしかするとpymcでもできるかもしれませんが、私は触ったことがないのでわかりません)stanは、pythonとは別もののモデリングソフトウェアですが、pythonからpystanモジュールを介してキックできるようになっているのでstanの使い方をマスターすれば、何とかなるはずです。
それなりに使いこなそうとすると、ベイズ推計・MCMCなどの前提知識が必要となるのであまり手軽とはいえませんが、ほかに方法がなさそうであれば、試してみる価値があるかと思います。
私自身は実装経験がないので、ただちにサンプルコードを示すことができませんが、「stan 打ち切りモデル」で検索すればstanのサンプルコードが見つかるはずです。
stanのチュートリアルに該当するものがあったので、実験しました。
python
1sample = stats.norm.rvs(loc=0,scale=0.5,size=10000) # 推計したいデータ
2Choice = sample[sample<-0.5] # -0.5以上は観察されないことにした実験用データ
3
4# stan本体のコード
5stancode = """
6data {
7 int<lower=0> N_obs; // 観測値の件数
8 int<lower=0> N_cens; // 打ち切られたデータの件数
9 real y_obs[N_obs]; // 観測値
10 real<lower=max(y_obs)> U; // 打ち切りポイント
11}
12parameters {
13 real<lower=U> y_cens[N_cens]; // 打ち切られたデータ 必ず打ち切りポイント以上になると設定
14 real mu; // 推計したい平均
15 real<lower=0> sigma; // 推計したい分散
16}
17model {
18 y_obs ~ normal(mu,sigma); // 観測値が正規分布に従うことを示すモデル
19 y_cens ~ normal(mu,sigma); // 欠損値が正規分布に従うことを示すモデル
20}
21"""
22model = pystan.StanModel(model_code=stancode) # コードのコンパイル
23
24standata = {'N_obs':len(Choice), # stanに与えるデータの生成
25 'N_cens':10000, # 打ち切られたデータは10000件とした
26 'y_obs':Choice,
27 'U':np.max(Choice)}
28
29result = model.sampling(data=standata) # samplingの実行
30
結果として平均は0.030とそれなりのものが得られました。(観測値の件数が1630件と本来のデータの20%弱からの推計なので、いいほうだということもできそうです)
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。