ひゃまだのblog

ひゃまだ(id:hymd3a)の趣味のブログ

多重比較のアルファベットの付け方をpythonスクリプトを作ってみた

(2025-05-31 初稿 - )

ずいぶんと長いこと放置中だったが、以下のページのスクリプトpythonで作成してみた。

というのも、上記のページに質問をしてくれた奇特な学生さんがいたので、ボケ防止で作成してみた。

最初に言っておくが、統計処理を専門で行うならば、R等の専門ソフトウェアを使う方が100倍も良い。

頭の体操のつもりで見るならば、以下をどうぞ。

統計ソフトでtukey等の多重検定を行うと、気がきいたものならば、アルファベットの符号を付けてくれるが、符号まで付けてくれないものもあるため、そんなときのためのスクリプト

ちなみに、アルファベットの符号の付け方を、英語では「Letter Grouping」や「Compact Letter Display (CLD)」というらしく、当然のことながら既にpythonライブラリがあるそうなので、統計処理を専門とする方はそちらを参照のこと。

以下のページも大変参考になった。多謝 m(__)m

試験データの前提

以下のような平均値を持つ試験区を多重検定した結果、5%水準で有意差がある組合せが以下のとおりだったとする。

(サンプルデータ)

A区 B区 C区 D区 E区 F区
50 20 60 40 10 30
※平均値はサンプルで数字を当てはめただけ
【例】 5%水準で有意差のある区

  (A, B) ,  (A, E),   (B, C),   (C, E),   (C, F)

アルファベット符号の付け方の考え方

あくまでも筆者の考えた方法であり、正式なものは上記のサイト等で学んでね。

  1. 各試験区の平均値の大きい順に並べる
  2. 有意差のある区を文字列にして、その出現数をカウントし配列に
  3. 隣の区の*数と比較し、同じならばアルファベットは同じ、違ったらアルファベットを一つ増加する(a → b)配列を作成
  4. 処理しやすいように列方向の入力用対戦表(マトリックス)を作成
  5. 処理間に有意差がある場合で、隣の処理区より*数が多い場合はアルファベットを入力、ただし、有意差の部分は*を入力
  6. 処理間に有意差のない場合は、前のアルファベットと同じものを入力
  7. 最終の結果を見やすいように、対戦表の行と列を入れ替え、'-'と'*'を削除後アルファベットの符号のうち、ユニークなもののみ表示する

作成したスクリプト

最初に適当に書き上げたが、ChatGPTさんにうかがって大分手直しをしていただいた。

スクリプトの信頼性も増したと思われる。便利な時代になったもんだ。

#!/usr/bin/python3
# 有意差のアルファベットを付ける
# ver 0.01 start 2025-05-30
# ver 0.02 2025-05-31 chatgpt による修正

# global
# 各区の平均値(辞書型)  ★ これを変更 exp_avg_dic = { "A":50, "B":20, "C":60, "D":40, "E":10, "F":30 } # 各処理区の平均値の大きい順(文字列) sorted_exp_str = "" # 有意差のある組合せ ★ これを変更 sig_list = [ ["A", "B"], ["A", "E"], ["B", "C"], ["C", "E"], ["C", "F"] ] sig_str = "" sig_dic = {} sig_alph = {} alph_list = [] # 平均値の大きい順にソート sorted_dic_avg = sorted(exp_avg_dic.items(), key=lambda x:x[1], reverse=True) #print(sorted_dic_avg) for i in range(len(sorted_dic_avg)):     sorted_exp_str += sorted_dic_avg[i][0] #print(sorted_exp_str) # sig_listを文字列(str)に sig_str = ''.join([item for pair in sig_list for item in pair]) #print(sig_str) # sig_strの文字列をカウント  for i in list(sorted_exp_str):     sig_dic[i] = sig_str.count(i) #print("sig_dic: ",sig_dic) num_list = list(sig_dic.values()) #print("num_list:", num_list) # 隣と比較し差があったらアルファベットを増やす char_num = 96           # アルファベット初期値 'a'-1 for i in range(len(num_list)):     if i == 0 or num_list[i] < num_list[i - 1] or num_list[i] == 0:         char_num += 1     alph_list.append(char_num) #print("alph_list: ",alph_list) sig_str = list(sig_dic.keys()) #print(sig_str) # 初期結果保存用対戦表 rslt_matrix = [[ '-' for j in range(len(sig_str))] for i in range(len(sig_str))] # 最終結果保存用対戦表 trans_matrix = [[ '-' for j in range(len(sig_str))] for i in range(len(sig_str))] zero_flag = 0 for i, key in enumerate(sig_str):     sig_num = sig_dic[key]     if sig_num > 0:         for j in range(i, len(sig_str)):             if len(sig_str) - j > sig_num:                 rslt_matrix[i][j] = chr(alph_list[i])  # アルファベット保存             else:                 rslt_matrix[i][j] = '*' if zero_flag == 0 else chr(alph_list[i])     else:         zero_flag = 1         for j in range(i, len(sig_str)):             rslt_matrix[i][j] = chr(alph_list[i]) #print(rslt_matrix) # 初期対戦表を最終版対戦表に変換 for i in range(len(rslt_matrix)):     for j in range(len(rslt_matrix[0])):         #print(i,j)         trans_matrix[i][j] = rslt_matrix[j][i] # Print Matrix print("     ", ',   '.join(sig_str)) for label, row in zip(sig_str, trans_matrix):     uniq = sorted(set(row) - {'-', '*'})     print(f"{label} , {row} {''.join(uniq)}")

少し長いスクリプトになってしまったが、できるだけコメントを入れたつもり。

不明な点は、ChatGPTやGemini等の生成AIに聞く方が良いかもしれない。

それでは、未来ある研究者達に幸多からんことを。(^^)/

関連ページ