0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

オリジナルキーボードレイアウト(FMIX配列)の検討2 - スコア算出方法

Last updated at Posted at 2025-07-14

概要

オリジナルキーボードレイアウト(FMIX)の検討の補足。スコア算出方法を変えたものを掲載。

キーボードレイアウトアナライザ

スコア

元記事のスコア
image-3.png

レイアウト 英字 ローマ字 ローマ字
(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が特定のスコア算出方法に最適化されすぎているためと考えられる。

スコア(対数距離)

対数距離採用
image.png

レイアウト 英字 ローマ字 ローマ字
(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、ローマ字はワカサギがよい。

スコア(負荷ベース)

筆者の感覚に基づいた負荷表ベースのスコア

負荷表
image.png

算出したスコア値は大きいほど負荷が低いことを示す。負荷表の数値に客観的な根拠はないが、筆者の感覚にはあっている。具体的には人差し指は下に、中指と薬指は上に、移動しやすいとして、負荷を設定している。

レイアウト 英字 ローマ字 ローマ字
(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)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?