概要
オリジナルキーボードレイアウト(FMIX)の検討の補足。スコア算出方法を変えたものを掲載。
キーボードレイアウトアナライザ
スコア
| レイアウト | 英字 | ローマ字 | ローマ字 (k→c) |
|---|---|---|---|
| qwerty | 21.12 | 20.17 | 21.10 |
| Colemak | 54.45 | 61.10 | 64.03 |
| FMIX14 | 54.33 | 63.68 | 64.28 |
| FMIX14R | 48.03 | 66.16 | 62.11 |
| MTGAP | 53.23 | 53.16 | - |
| ワカサギ | 53.40 | 68.48 | - |
| 大西 | 45.82 | 70.09 | - |
英字はColemak、ローマ字は大西がよい。KLA系のスコアでよいとされるMTGAPのスコアはそれほど高くない。これはスコア算出方法がカスタマイズされているからというよりも、MTGAPが特定のスコア算出方法に最適化されすぎているためと考えられる。
スコア(対数距離)
| レイアウト | 英字 | ローマ字 | ローマ字 (k→c) |
|---|---|---|---|
| qwerty | 36.12 | 32.39 | 34.38 |
| Colemak | 63.65 | 67.46 | 70.34 |
| FMIX14 | 63.68 | 70.13 | 70.57 |
| FMIX14R | 58.04 | 72.12 | 69.07 |
| MTGAP | 63.15 | 61.40 | - |
| ワカサギ | 62.30 | 74.92 | - |
| 大西 | 55.55 | 74.62 | - |
英字はFMIX14、ローマ字はワカサギがよい。
スコア(負荷ベース)
筆者の感覚に基づいた負荷表ベースのスコア
算出したスコア値は大きいほど負荷が低いことを示す。負荷表の数値に客観的な根拠はないが、筆者の感覚にはあっている。具体的には人差し指は下に、中指と薬指は上に、移動しやすいとして、負荷を設定している。
| レイアウト | 英字 | ローマ字 | ローマ字 (k→c) |
|---|---|---|---|
| Colemak | 0.359 | 0.359 | 0.384 |
| FMIX14 | 0.346 | 0.322 | 0.383 |
| FMIX14R | 0.293 | 0.404 | 0.370 |
| MTGAP | 0.320 | 0.295 | 0.320 |
| ワカサギ | 0.328 | 0.372 | 0.311 |
| 大西 | 0.314 | 0.382 | 0.370 |
スコア(混合)
スコア(対数距離)✕スコア(負荷ベース)3→英字Colemakが70となるように正規化
| レイアウト | 英字 | ローマ字 | ローマ字 (k→c) |
|---|---|---|---|
| qwerty | 9.4 | 11.4 | 8.5 |
| Colemak | 70.0 | 74.2 | 82.7 |
| FMIX14 | 67.5 | 69.2 | 82.8 |
| FMIX14R | 52.1 | 89.3 | 78.3 |
| MTGAP | 61.9 | 55.5 | 58.8 |
| ワカサギ | 62.6 | 85.4 | 68.9 |
| 大西 | 53.4 | 87.3 | 62.9 |
データ
英字データは以下からダウンロードさせてもらった
https://note.com/yinouet1001/n/ne973d48e5f59
ローマ字データは以下からダウンロードさせてもらった
https://note.com/illlilllililill/n/nc099239c5565
ローマ字(k→c) データは上記ローマ字データのkをcに一括置換した
解説?
直感的には対数距離をとるスコア(対数距離)のほうがより現実に即しているように思えるが、そもそも距離に対する負荷の設定の妥当性がないので、スコアとスコア(対数距離)でどちらが正しいか一概にはいえない。妥当性を検証する方法はないか?スコア(負荷表ベース)は、ある程度、自分の好みが反映できているスコアとは考える。そこで、スコア(混合)は、スコア(対数距離)とスコア(負荷表ベース)の相乗をとることで、一つのスコアに依存しないものとした。スコア(混合)をみると、英字ではColemakが優秀。ローマ字では、大西やワカサギ FMIX14Rが優秀であった。 好みを反映させているとはいえ自分が推しているFMIX14Rが一番というのも出来過ぎなので、新たなスコア算出方法の追加検討が必要かもしれない。
履歴
2025/7/29 スコア(混合)の表の数値が間違っていたので修正
付録
スコア(負荷表ベース)の算出コード
import os
def create_score_map(keylayout):
"""
キーレイアウト文字列とスコアのリストから、
文字とスコアのマッピング辞書、および全スコアの平均値を生成します。
Returns:
tuple: (文字とスコアがマッピングされた辞書, 全スコアの平均値)
"""
# 各キーに対応するスコアをリストとして定義
scores = [50, 30, 20, 25, 50, 40, 25, 20, 30, 50,
12, 15, 11, 10, 20, 20, 10, 11, 15, 12,
40, 35, 25, 20, 35, 25, 20, 30, 40, 50]
# keylayoutの各文字とscoresの値を対応付けた辞書を作
score_map = {char: score for char, score in zip(keylayout, scores)}
# 全スコアの平均値を計算
average_score = sum(scores) / len(scores) if scores else 0
return score_map, average_score
def analyze_text_score(filepath, score_map, base_average_score):
"""
テキストファイルを読み込み、キーレイアウトのスコアを分析します。
計算された1文字あたりのスコアを、全キーの平均スコアでさらに正規化します。
Args:
filepath (str): 分析対象のテキストファイルのパス。
score_map (dict): 文字とスコアのマッピング辞書。
base_average_score (float): 全キーのスコアの平均値。
Returns:
float: 最終的に正規化されたスコア。
"""
total_score = 0
char_count = 0
try:
# 'utf-8'エンコーディングでファイルを開く
with open(filepath, 'r', encoding='utf-8') as f:
# ファイルの内容を全て小文字に変換して読み込む
text = f.read().lower()
for char in text:
# スコアマップに存在する文字の場合のみスコアを加算
if char in score_map:
total_score += score_map[char]
char_count += 1
except FileNotFoundError:
print(f"エラー: ファイル '{filepath}' が見つかりません。")
return 0.0
# 分析対象の文字がなければ0を返す
if char_count == 0:
print("警告: ファイル内にスコア分析対象の文字が見つかりませんでした。")
return 0.0
# テキストの1文字あたりの平均スコアを計算
text_average_score = total_score / char_count
# ゼロ除算を避ける
if base_average_score == 0:
print("警告: 基準となる平均スコアが0です。")
return 0.0
# 全キーの平均スコアでさらに正規化
final_normalized_score = text_average_score / base_average_score
return 1.0-final_normalized_score
def calculate_layout_score(key_layout,sample_filename):
# 1. スコアマップと全キーの平均スコアを作成
score_mapping, avg_score = create_score_map(key_layout)
# 3. テキストファイルを分析してスコアを計算
layout_score = analyze_text_score(sample_filename, score_mapping, avg_score)
# 4. 結果を表示
print(f"スコア({sample_filename}): {layout_score:.3f}")
def calculate_layout_scores(key_layout):
sample_filename = "english_sample.txt"
calculate_layout_score(key_layout,sample_filename)
sample_filename = "jap-n.txt"
calculate_layout_score(key_layout,sample_filename)
calculate_layout_score(key_layout,"jap-n-kc.txt")
print("\n")
# --- メインの処理 ---
if __name__ == "__main__":
# 2. 分析用のサンプルテキストファイルを作成
sample_filename = "english_sample.txt"
# キーボードのレイアウトを一行の文字列として定義
qwerty_layout =("qwertyuiop"
"asdfghjkl;"
"zxcvbnm,./")
print(f"キーレイアウト: {qwerty_layout}")
calculate_layout_scores(qwerty_layout)
fmix_layout = ("qwldkyfup;"
"asrtghneio"
"zxcvbjm,./")
print(f"キーレイアウト: {fmix_layout}")
calculate_layout_scores(fmix_layout)
fmixr_layout = ("qwrdlyfup;"
"asktghneio"
"zxcvbjm,./")
print(f"キーレイアウト: {fmixr_layout}")
calculate_layout_scores(fmixr_layout)
fmix2_layout = ("qwlpkyfuj;"
"asrtghneio"
"zxcvbdm,./")
print(f"キーレイアウト: {fmix2_layout}")
calculate_layout_scores(fmix2_layout)
fmix3_layout = ("qwldkyfuj;"
"asrtghneio"
"zxcvbpm,./")
print(f"キーレイアウト: {fmix3_layout}")
calculate_layout_scores(fmix3_layout)
layout = ("qwrdlyfuj;"
"asktghneio"
"zxcvbpm,./")
print(f"キーレイアウト: {layout}")
calculate_layout_scores(layout)
colmak_layout = ("qwfpgjluy;"
"arstdhneio"
"zxcvkm,./")
print(f"キーレイアウト: {colmak_layout}")
calculate_layout_scores(colmak_layout)
wakasagi_layout = ("qprdcbkuyx"
"atnswmheio"
"/,lgjfv;z.")
print(f"ワカサギ: {wakasagi_layout}")
calculate_layout_scores(wakasagi_layout)
layout = ("ypoujkdlcw"
"inea,mhtsr"
"qz/.:bfgvx")
print(f"mtgap: {layout}")
calculate_layout_scores(layout)
layout = ("qlu,.fwryp"
"eiao-ktnsh"
"zxcv;gdmjb")
print(f"大西: {layout}")
calculate_layout_scores(layout)


