【MONOEYES】Run Run連続再生の確率



A Mirage In The Sun - MONOEYES

実はMONOEYES「A Mirage In The Sun」収録の「Run Run」を、俺は2曲持っている。
A Mirage In The Sunを購入するよりも前にiTunesでRun Runだけ購入してしまったのである。
その後になってA Mirage In The Sunを購入・iTunesライブラリにインポートしたので、
結果的に「A Mirage In The Sun」の「Run Run」が俺のiTunesライブラリ上では全く同じ曲が2曲存在していることになっている。

要するにRun Run1曲分余分に金を使っていることになる(あほ)。
Run Runを結構気に入ってしまって、PVばっか見ていたのだが、
あほらしくなったのでRun Runだけ買っちまえ!
⇒めっちゃええやんアルバムごと買っちまえ!
という経緯によるものである。

こういう場合、A Mirage In The Sun全体をシャッフル再生すると、
当然「Run Run」だけはどっかで2回流れることになるが、
そうなるとこの確率はどんなもんなんだ?というのが(懲りずに)また少し気になり始めた。
というのもどうもA Mirage In The Sunシャッフルをしていると、
Run Runが連続する確率が高いように感じたのである。
以前の検証において、ストレイテナーのSILLY PARADEが連続する確率は0.00367%という計算結果が出ているが
これは母体の数がA Mirage In The Sunとは比べ物にならないほど大きい(ストレイテナー全手持ちの曲257曲(当時))からであり
A Mirage In The Sun収録の12曲(実態としてRun Runが1曲かぶってるので俺のiTunesライブラリ上では13曲になっている)を母体数とすれば
ストレイテナーのSILLY PARADE連続よりは確率が高いことは明らかである。
1曲かぶっているRun Runが連続する確率はどれくらいか?
調べてみた。


 


 


まずは理論値から追ってみる。
A Mirage In The Sunに収録されているのは12曲だが、Run Runが被ってるので全部で13曲になる。
この13曲をランダムで再生するとき、「Run Run」がどこかのタイミングで連続するケースを考えればよい。

例えば以下のようなケースが考えられる(便宜上、かぶっているRun Runを(1)と(2)でわけている)
(1)Run Run(1)⇒Run Run(2)⇒他11曲
この確率は

1/13*1/12*11/11*10/10*…*1/1  
=1/13*1/12  


で計算される。
最初の2曲はRun Run(1)が1/13、Run Run(2)が1/12の確率となり、
最初の2曲でRun Runが出そろったので残り11曲は何が流れてもいい計算である。

ここで、Run Run(1)とRun Run(2)は厳密に2曲を分けた考え方であり、
連続さえしていればその順番は問わない(Run Run(2)⇒Run Run(1)でもいい)ため
この確率は順序逆転版も考慮すると2倍になる。
よってこのケースでのRun Run連続再生確率は


1/13*1/12*2
≒0.012821…


となる。百分率にすると約1.3%弱というところである。この時点で割と高い。

同様の連続ケースは
(2)Run Run2曲を除く11曲のどれか⇒Run Run(1)⇒Run Run(2)⇒残り9曲のどれか
(3)Run Run2曲を除く11曲のどれか⇒Run Run2曲を除く残り10曲のどれか⇒Run Run(1)⇒Run Run(2)⇒残り8曲のどれか

というように連続する部分を1つずつずらしていくと全12ケースを考えることができる。
計算してみればわかるのだが各ケースで↑と同じ確率が導かれるので、
全体として「Run Runが連続する確率」は


(1/13*1/12*2)*12
≒0.153846…


という計算結果になる。
百分率で表すと約15.4%。これはかなり高い。




本当にこのくらいの確率になるのか、簡単なシミュレータプログラムを作って検証してみる。
プログラムは以下のとおりである。

import java.util.*;  
import java.text.*;  
import java.io.*;  

public class AMirageInTheSunShuffleSimulation {

private static final File RESULT_FILE = new File("shuffle_result.txt");  
private static final int SIMULATE_COUNT = 100000;  
  
private static final DateFormat YYYYMMDDHHmmSSsss = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");  
private static final int LOG_COUNT = 10000;  
  
private static final String[] A_Mirage_In_The_Sun = new String[] {  
	"Cold Reaction"  
	,"Like We've Never Lost"  
	,"Just A Little More Time"  
	,"My Instant Song"  
	,"Run Run(1)"  
	,"Run Run(2)"  
	,"グラニート"  
	,"End Of The Story"  
	,"Do I Have To Bleed Again"  
	,"Get Me Down"  
	,"明日公園で"  
	,"Wish It Was Snowing Out"  
	,"Remember Me"  
};  
  
public static void main(String[] args) {  
	try {  
		printLog("1.Start");  
		  
		shuffleSimulation();  
		  
		printLog("2.End");  
	} catch(Throwable e) {  
		e.printStackTrace();  
	}  
}  
  
private static void shuffleSimulation() throws Throwable {  
	BufferedWriter bw = null;  
	int runrunContinuityCount = 0;  
	try {  
		bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(RESULT_FILE)));  
		  
		for (int i=0; i < SIMULATE_COUNT; i++) {  
			<span style="color: green;">// 今回曲目リストを取得</span>  
			String musicListString = makeShuffleList();  
			// Run Runが連続しているかチェック  
			boolean isRunRunContinuity = isRunRunContinuity(musicListString);  
			if(isRunRunContinuity) {  
				runrunContinuityCount++;  
			}  
			  
			<span style="color: green;">// 結果ファイルへの出力文字列を生成</span>  
			StringBuilder sb = new StringBuilder();  
			sb.append(String.valueOf(i+1));  
			sb.append("	");  
			sb.append(String.valueOf(isRunRunContinuity == true ? "○" : "×"));  
			  
			String[] musicArray = musicListString.split("\t");  
			for (int j=0; j &lt; musicArray.length; j++) {  
				sb.append("	");  
				sb.append(musicArray[j]);  
			}  
			  
			bw.write(sb.toString());  
			bw.newLine();  
			bw.flush();  
			  
			if (i &gt; 0 &amp;&amp;  i % LOG_COUNT == 0) {  
				printLog("	Current Round[" + String.valueOf(i) + "]");  
			}  
		}  
		double runrunContinuityProbability = (double)runrunContinuityCount / (double)SIMULATE_COUNT * 100.00;  
		DecimalFormat dc = new DecimalFormat("00.000");  
		printLog("総シャッフル回数   :" + String.valueOf(SIMULATE_COUNT));  
		printLog("Run Run連続回数    :" + String.valueOf(runrunContinuityCount));  
		printLog("Run Run連続再生確率:" + dc.format(runrunContinuityProbability) + "%");  
		  
	} catch(Throwable e) {  
		throw e;  
	} finally {  
		if (bw != null) {  
			bw.close();  
		}  
	}  
}  
  
private static String makeShuffleList() {  
	List<string> musicList = new ArrayList();  
	for (int i=0; i &lt; A_Mirage_In_The_Sun.length; i++) {  
		musicList.add(A_Mirage_In_The_Sun[i]);  
	}  
	  
	StringBuilder musicListString = new StringBuilder();  
	while (musicList.size() &gt; 0) {  
		int randomIndex = (int)(Math.random() * musicList.size());  
		String music = musicList.get(randomIndex);  
		musicList.remove(randomIndex);  
		  
		musicListString.append(music);  
		musicListString.append("	");  
	}  
	  
	return musicListString.substring(0 , musicListString.length() - 1);  
}  
  
private static boolean isRunRunContinuity(String musicListString) {  
	boolean result = false;  
	String beforeMusic = "";  
	String[] musicArray = musicListString.split("\t");  
	  
	for (int i=0; i &lt; musicArray.length; i++) {  
		  
		<span style="color: green;">// 1曲目ならbeforeMusicに曲名設定して速攻で次の曲へ</span>  
		if (i == 0) {  
			beforeMusic = musicArray[i];  
			continue;  
		}  
		<span style="color: green;">// 今の曲と前の曲がともに「Run Run」で始まってたら連続とみなす</span>  
		String currentMusic = musicArray[i];  
		if (beforeMusic.startsWith("Run Run") &amp;&amp; currentMusic.startsWith("Run Run")) {  
			return true;  
		} else {  
			beforeMusic = currentMusic;  
		}  
		  
	}  
	  
	return false;  
}  
  
private static void printLog(Object msg) {  
	StringBuilder sb = new StringBuilder();  
	sb.append(YYYYMMDDHHmmSSsss.format(new Date()));  
	sb.append(" ");  
	if (msg != null) {  
		sb.append(msg.toString());  
	}  
	  
	System.out.println(sb.toString());  
}  

}


100,000(10万回)シャッフルしてその中で「Run Run」が何回連続するかを計算する。
各回でRun Runが連続したかどうかを○か×であらわし、その曲目リストそのものをTAB区切りで繋げてファイルにも出力している。
結果は15.439%となった。
理論値に比較的近い(理論値よりは少し高めだ)が概ね予想通りといったところである。




というわけで約15.4%の確率でRun Runが連続することになるようだ。
つまり100回シャッフル再生したらうち15回はRun Runが連続している可能性が高いことになる。
10回シャッフル再生してもうち最低1回はRun Runが連続している可能性が高いとみなせる。
そりゃ高頻度だなと感じるだろう。
冒頭述べたとおりストレイテナーのSILLY PARADEと比べると、
母体数の違いもあってはるかに高い確率となった。

こうした事情もあってかRun Runを聴きすぎて最早歌詞を暗記してしまった。
昔のSpace Sonicに近いものがある。
どうでもいいけど細美って英語歌詞にやたら「just」を使う気がする。
気のせいかね。