概要
コンジョイント分析などで使う直交表(直交配列表)を、水準表から作成する方法を紹介します。
直交表について
直交表は、複数の因子(要因)の水準の組み合わせを効率よくまとめた表のことです。
すべての組み合わせを試すのではなく、
最小限の実験数で因子の影響をバランスよく調べるために使います。
例えば、3つの因子がそれぞれ3つの水準を持つ場合、
全組み合わせは 3×3×3=27 通りですが、直交表を使えば9通りの実験で済みます。
🎯例:3因子 × 3水準 の水準表
実験No | 因子A | 因子B | 因子C |
---|---|---|---|
1 | 低 | 小 | 青 |
2 | 中 | 中 | 赤 |
3 | 高 | 大 | 黄 |
🎯例:3因子 × 3水準 の直交表(一例)
実験No | 因子A | 因子B | 因子C |
---|---|---|---|
1 | 低 | 小 | 青 |
2 | 低 | 中 | 赤 |
3 | 低 | 大 | 黄 |
4 | 中 | 小 | 赤 |
5 | 中 | 中 | 黄 |
6 | 中 | 大 | 青 |
7 | 高 | 小 | 黄 |
8 | 高 | 中 | 青 |
9 | 高 | 大 | 赤 |
直交表は「効率的に実験やアンケートを設計したい」場合に非常に役立ちます。
なぜ直交表が便利なのか?
コンジョイント分析では商品のデザインや価格、色など複数の条件を組み合わせたパターンを作成しますが、
すべての組み合わせを網羅するとパターン数が膨大になり、回答者の負担が大きくなってしまいます。
例えば、3つの因子がそれぞれ4段階あると、全組み合わせは 4×4×4=64 通り。
これをすべて回答してもらうのは現実的ではありません。
直交表を使うと、この64通りを例えば16パターン程度に減らしつつ、
因子の効果を偏りなく評価できるようになります。
これにより、回答者の負担を減らしながら有効な分析が可能になります。
注意点:交互作用について
直交表を使った実験では、複数の因子の組み合わせで結果を調べますが、
因子同士が影響し合い、ある因子の効果が他の因子の水準によって変わることがあります。
これを交互作用(インタラクション) と言います。
実験No | 因子A | 因子B | 因子C | 効果(例) |
---|---|---|---|---|
1 | 低 | 小 | 青 | 5 |
2 | 低 | 大 | 赤 | 3 ⚠️ |
3 | 高 | 小 | 黄 | 7 |
4 | 高 | 大 | 青 | 10 ⚠️ |
⚠️の箇所は、因子Bの「大」が因子Aの「低」と「高」で効果が異なっている部分です。
つまり因子Bの効果が因子Aの水準に依存しています。。
🔍交互作用への対策
-因子の組み合わせ(パターン)数を増やす
-同じ条件で繰り返し実験しサンプル数を増やす
これらにより交互作用の影響を把握しやすくなります。
サンプルデータ
コンジョイント分析や直交表設計を行う際、実際の細かい数値データではなく、ざっくり丸めた値(カテゴリ化された水準)を使うのが一般的です。
❓なぜ丸めた値を使うの❓
1. 組み合わせ数を抑えるため
細かい値をそのまま使うと水準の数が増え、組み合わせパターンが爆発的に増えてしまいます。
丸めることで直交表のサイズを抑え、実験設計が現実的になります。
2. ノイズを抑えて傾向を捉えやすくするため
実データの細かい数値にはノイズが含まれがちです。
水準をざっくり分けることで、全体の傾向や効果を見やすくなります。
3. 結果の解釈と活用がしやすいため
実務では「どのレベルが良いか」を知りたいケースが多く、
細かすぎる数値よりも、大まかな水準のほうが解釈しやすく、応用もしやすいからです。
環境
python3.x
jupyter lab
コード解説
import pandas as pd
📚 サンプルデータを読み込む
#=============================================
# CSVを読み込む
#=============================================
levels_df = pd.read_csv("levels.csv")
📚水準リストを作る
#=============================================
# 各列ごとにユニーク値(非NA)を水準として抽出
#=============================================
factor_levels = {}
for col in levels_df.columns:
unique_levels = levels_df[col].dropna().unique().tolist()
factor_levels[col] = unique_levels
print(factor_levels)
#=============================================
# 因子ごとにユニークな水準リストを作る
#=============================================
factor_levels = {}
for col in levels_df.columns:
factor_levels[col] = levels_df[col].dropna().unique().tolist()
-
factor_levels = {}
→ 最終的に「因子名:水準リスト」の形で保存する空の辞書を用意。 -
for col in levels_df.columns: → すべての列名を順番に処理。
-
levels_df[col].dropna()
→ 欠損値を除外してデータの正しい水準だけを対象にする。 -
.unique() → ユニークな値だけを抽出。
-
.tolist() → NumPy配列をPythonのリストに変換。
-
factor_levels[col] = → 因子名をキーにして、その水準リストを辞書に格納。
❓何をしているコード❓
データフレーム levels_df
の各列(因子)について
欠損値(NaN)を除いたユニークな値のリスト(=水準)を作成し
辞書にまとめています。
📚 L9直交表の水準番号
#=============================================
# L9直交表の水準番号(0始まり)
#=============================================
orthogonal_index = [
[0, 0, 0, 0],
[0, 1, 1, 1],
[0, 2, 2, 2],
[1, 0, 1, 2],
[1, 1, 2, 0],
[1, 2, 0, 1],
[2, 0, 2, 1],
[2, 1, 0, 2],
[2, 2, 1, 0],
]
- orthogonal_index = → 4つの因子の水準の組み合わせ(条件)を指定しているリスト。
それぞれの小リストが「1回の実験の組み合わせ」を表しています。
各要素の数字は、該当する因子の水準番号(0から始まる) を意味します。
たとえば [0, 1, 2, 0]
なら
- 因子1は水準0
- 因子2は水準1
- 因子3は水準2
- 因子4は水準0
という組み合わせで実験を行う、ということです。
このように、実験計画法の「直交表」は
少ない実験回数で因子の影響を効率的に調べるための組み合わせ表として使われます。
❓3因子の場合のL9直交表は❓
3因子のため、各サブリストは長さ3になります。
各要素はそれぞれの因子の水準(0〜2)を表します。
orthogonal_index_3factor = [
[0, 0, 0],
[0, 1, 1],
[0, 2, 2],
[1, 0, 1],
[1, 1, 2],
[1, 2, 0],
[2, 0, 2],
[2, 1, 0],
[2, 2, 1],
]
📚 直交表を作る因子の順番を決める
#=============================================
# 直交表を作る順番を決める
#=============================================
# 必ず factor_levels の全列を使う
selected_factors = list(factor_levels.keys())
-
factor_levels → 因子名をキー、水準リストを値に持つ辞書。
-
list(factor_levels.keys()) → その辞書の全ての因子名(列名)を順番にリスト化。
このリスト selected_factors
は、直交表を作成するときに
どの因子をどの順番で使うかを決めるためのものです。
📚 水準リストも順番を合わせる
#=============================================
# 水準リストも順番を合わせる
#=============================================
selected_levels = [factor_levels[f] for f in selected_factors]
-
[factor_levels[f] for f in selected_factors]
→selected_factors
に基づいて、factor_levels
の水準リストを因子の順番に合わせて取り出す。
❓何をしているコード❓
具体的にはリスト内包表記を使い、
各因子名 f
に対応する水準リストを取り出し、
まとめて selected_levels
に格納しています。
実験計画表(直交表)を作る際に、
因子名と水準の対応が崩れずに保持されます。
📚直交表を作成
#=============================================
# L9のインデックスを水準値に変換しながら直交表を作成
#=============================================
data_OA = []
for row in orthogonal_index:
entry = [selected_levels[i][row[i]] for i in range(len(selected_factors))]
data_OA.append(entry)
# DataFrame化(列名も元の因子名のまま)
df_OA = pd.DataFrame(data_OA, columns=selected_factors)
-
orthogonal_index → 直交表の各行ごとに因子の水準番号(0始まり)を持つリスト。
-
selected_levels → 各因子の水準リストを因子の順番に合わせて並べたリスト。
-
for
→row[i]
(水準番号)を使って対応する因子i
の水準値をselected_levels[i][row[i]]
で取り出す。
→ 「水準番号」から「実際の水準値」に変換した実験条件のリストentry
を作成。
これで実際に使える直交表(実験計画表)が完成しました。
❓何をしているコード❓
水準番号を使って、各因子の「実際の水準値」に変換し、1行分の実験条件を作り
直交表を作成してます。
📚 CSVに出力
#=============================================
# コンジョイント分析用に行列入れ替えます
#=============================================
df_OA = df_OA.T
#=============================================
#保存
#=============================================
df_OA.to_csv("直交表.csv", index=True, encoding="utf-8-sig")
-
df_OA.T → コンジョイント分析で使いやすい形に行列を入れ替え。
📨 output
まとめ
「どんな調査をしたいのか」「何を目的に分析するのか」をしっかり決めることが
とても大切です。
目的や調査内容がはっきりしていないと、
水準表の内容がブレてしまい、調査や分析の意味が薄れてしまいます。
だから、直交表を作る前に目的 をクリアにしましょう!
次の投稿では、コンジョイント分析を解説します。
https://qiita.com/iwakazusuwa/items/84a9822b16f2ea6c97d0