総合順位が個々の最高順位よりも上となる確率
たとえばトライアスロン3種目で、総合順位が個々の種目のどの順位よりも上になることがある。
これはちょっと意外に思えるので、問題をうんと単純化して2種目で考えてみよう。
赤、青、黄の3人の、数学と英語のテスト結果が上の図のようだったとすると、
青は数学でも2位、英語でも2位でありながら総合順位は1位だ。
なので、(総合順位) > (個々の種目の最高順位) はあり得ることなのだ。
しかし下の図のような状況だと、青が総合1位となるには、英語、数学のどちらかで1位を取らないといけない。
なので、総合順位が上になるかどうかは、周囲の状況で変わってくる問題だったのだ。
さて、トライアスロン3種目の場合は、2種目で線で描いた状況を、立体化して面で描けば良いわけだ。
赤と黄に足を引っ張る不得意種目があったなら、平均的な青が総合1位なることだってあり得る。
では、総合順位が個々の最高順位よりも上となる人は、全体のうちどれくらい居るのだろうか。
ちょっと考えても分からなかったので、パソコンでシミュレーションを行った結果がこれ。
2科目の場合、全体の 1/3 が、
3種目の場合、全体の 1/4 が、
N種類の場合、全体の 1/(N+1) が、
個別の順位よりも総合順位の方が上という、シンプルな結果となった。
この結果からすると、
・種目数が少なければ、突出せずとも満遍なくこなす人が上位に行くことがある。
・種目数が多くなるにつれて、どの分野でも負けないだけでは不十分で、突出した得意分野が望まれる。
以上、シミュレーションの結果は間違い無いだろうと思っているが、
ではなぜ全体の 1/(N+1) となるのか、きちんとした証明ができていない。
2科目、3種目の図を見ると、なんとなく分かるような気もするのだが、うまく説明できない。
誰か賢い人、考えてみて。
# -*- coding: utf-8 -*- """ 総合力ってどのくらいあるの? たとえばトライアスロン3種目で、総合順位が個々の種目の最高順位よりも上となる確率は? """ import numpy as np from statistics import mean class GeneOrder: N_MEMBER = 5000 # 参加人数 # 競技の数を2〜15まで変えて試してみる def run(self): for n_subj in range( 2, 16 ): # 競技の数を変えてみる results = [] for repeat in range( 10 ): # 10回繰り返して平均をとる ret = self.each_run( n_subj ) results.append( ret ) # print( results ) val = mean(results) pred = 1/(n_subj+1) # 結果はおそらく1/(競技数+1) になると予想 # 競技数, 実験値, 予想値, 食い違い print( "{}, {:.5f}, {:.5f}, {:.05f}".format( n_subj, val, pred, val-pred ) ) # 個々の試行 # n_sub: 競技の数 def each_run(self, n_subj): points = [] # 各種目ごとの得点配列 orders = [] # 各種目ごとの順位配列 # 各種目について得点を付ける for i in range( n_subj ): # いろんな分布で試してみよう x_arr = np.random.rand( self.N_MEMBER ) # N個の一様乱数 # x_arr = np.random.normal( 0, 1, self.N_MEMBER ) # N個の正規分布 (平均, 分散, 出力数) # x_arr = np.random.beta( 4, 2, self.N_MEMBER ) # β分布、非対称でやってみよう # 順位についての話なので、分布形状は関係ないようだ。 points.append(x_arr) # 各種目について順位を付ける for i in range( n_subj ): x_arr = points[i] n_order = x_arr.argsort() # 得点に対する順位を得る orders.append( n_order ) # 総合得点を付ける total_points = np.zeros( self.N_MEMBER ) for m in range( self.N_MEMBER ): sum = 0 for i in range( n_subj ): sum += points[i][m] total_points[m] = sum # 総合順位を付ける n_arr = np.array(total_points) total_order = n_arr.argsort() # Min(個別順位)を得る total_min = np.zeros( self.N_MEMBER ) for m in range( self.N_MEMBER ): min_order = self.N_MEMBER + 1 # 最小の順位を得る for i in range( n_subj ): if orders[i][m] < min_order: min_order = orders[i][m] total_min[m] = min_order # 出力してみよう """ for m in range( self.N_MEMBER ): row = [] for i in range( n_subj ): row.append( points[i][m] ) for i in range( n_subj ): row.append( orders[i][m] ) row.append( total_points[m] ) row.append( total_order[m] ) row.append( total_min[m] ) print( ",".join( map(str, row) ) ) """ # 総合順位 < Min(個別順位)をカウント cnt = 0 for m in range( self.N_MEMBER ): if total_order[m] < total_min[m]: cnt += 1 # 結果を返す ratio = cnt/self.N_MEMBER # print( "{}, {}, {}".format( n_subj, cnt, ratio ) ) return ratio if __name__ == '__main__': me = GeneOrder() me.run()