« 2020年2月 | トップページ | 2020年4月 »

2020年3月

2020年3月29日 (日)

LASSO に関する幾つかの補足

当ブログに LASSO に関する記事が有りますが、ここでは表題の通り、 LASSO に関する幾つかの補足を書きたいと思います。

LASSO や否や?

スパース・モデリングは LASSO だけではない では、説明変数がスパースになることの説明で用いられる図が2種類有ることを書きました。

LASSO 最小二乗推定値
\(\beta_1\)
\(\beta_2\)
\(l_1\)ノルム最小化
\(\beta_1\)
\(\beta_2\)

その記事を書いた後で、図の \(l_1\) ノルム最小化の方も LASSO と言うのではないかという疑問が生じて、ずっと気になっていました。今も確証は持てないのですが、おそらく \(l_1\) ノルム最小化の方は LASSO とは言わないと思います。次の記事が参考になります。

スパースモデリングはなぜ生まれたか? 代表的なアルゴリズム「LASSO」の登場

この記事から、私は

  • データにノイズが混入している場合に \(l_1\) 正則化項を用いて最適化する方法を LASSO と呼ぶのに対して
  • 劣決定系に対する最適化(すなわち図の \(l_1\) ノルム最小化)はノイズの無い場合の話しで、 LASSO の前段階の理論である

と理解しました(自信は無いですが)。

L1 ではなく \(l^1\) ・・・、でも \(l_1\)

スパースモデリングに関するインターネット上の記事のほとんどで、有限次元ベクトル \(v\) のノルム

\[ \|v\|_1 = \sum |v_i| \]

を L1 ノルムと表記し、これを用いた正則化を L1 正則化と呼んでいます。しかし、これは大文字の L ではなく、小文字の \(l\) で表記するべきです。大文字で表記するのは、関数 \(f\) のノルムです。

\[ \|f\|_1 = \int |f(x)|dx \]

そんな訳で、当ブログでは 「L1 正則化」ではなく 「\(l_1\) 正則化」と表記しています。

ところが、最近気付いたのですが、 \(l_1\) ではなく、 \(l^1\) が正しい表記でした。したがって、本当は 「\(l^1\) 正則化」とすべきでしょう。でも、上付き添え字だと指数と間違える恐れも有るので、下付きの 「\(l_1\) 正則化」で行くことにします。

ところで、多くの記事で 「L1 正則化」と表記されている理由は、これが小文字だと 「l1 正則化」となってアルファベットの「l (エル)」と「I (アイ)」そして数字の「1」が区別しにくいからだろうと思っています。普通のフォントでは仕方ないですね。当ブログでは MathJax のおかげで「\(l\)」が識別出来るので小文字で表記出来るのでした。

2020年3月28日 (土)

デバッグで新たなバグ作成 (<span class="sl_ft" style="font-weight:normal">FlatTable</span> )

FlatTable(ビリヤードの配置図ソフト)でも LongDriver(フットボールのプレイブック・ソフト)と同様の不具合が見られたので、修正しました。 FlatTable は何故か一見正常に動作しているように見えたのですが、デバッガーで見るとエラーは発生していました。デバッグ内容は基本的には LongDriver と同じく、 touchEvent 処理時に下記コードで仮想マウスパッドを再表示するというものです。

        curPage.exPad.setAttribute("display", "none");
        setTimeout(function(){
            curPage.exPad.setAttribute("display", "inline");
        }, 10);

ところが、このデバッグの所為で新たなバグを生むことにもなりました。 FlatTable は初期配置を指定出来るのですが、そこでバグを作ることになりました。初期配置を処理するコードが配置図を作成するときに使用するコードと兼用になっている箇所が有ります。例えば、球の経路を描画するルーチンなどです。そういう所に上記の再表示コードを入れると、正しく初期配置を表示しなくなったのです。上記コード内の curPage.exPad は仮想マウスパッドですが、初期配置を表示する時点では、この仮想マウスパッドは未だ作成されていないため、 undefined のエラーが発生しました。それで、上記コードを実行する前に curPage.exPad の存在を確認することでエラーを回避しました。もう大丈夫なはずです。

FlatTable は JavaScript も SVG も初めて扱った時のソフトなので、今回コードに目を通してみて「ナンダカナァ」と思うところも有りました。書き直そうかという考えが無くは無いのですが、今さら手間を掛けるのも「ナンダカナァ」といったところです。

2020年3月22日 (日)

<span class="sl_ft" style="font-weight:normal">LongDriver</span> のデバッグ結果

フットボールのプレイブックソフト LongDriver がスマートフォンで操作出来なかったことに関して、デバッグは 90% 程度出来て、必要な操作は可能な状態になりました。しかし、これ以上の改善の見通しは立っていません。解決方法は、既に以前の記事で示したように、要素を再表示することす。ただし、要素は複数有るので、その点は変更しています。

下記の表は LongDriver 内の各要素に対する操作の可否を表したものです。第1行は要素を表しています。第2行以下は操作を表し、黒は正常、赤は異常を表しています。ただし、異常と言っても、同じ操作を再度実施すれば、それを実行することが出来ます。今回のバグは1つの操作だけで単純に可否が決まっているのではなく、複数の操作の連なりで可否が決まります。表には2つの操作の結果を記しています。第1の操作は 「click→」 など 「→」 の付いている欄、第2の操作は同一行の他の欄になっています。例えば、 dummy の click の後、 pad の drag は可能とか、 hbar の click の後、 vbar の scroll は不発(ただし、2発目は成功する)など。

操作の可否
dummypadhbarvbar
click→-clickclick
dragscrollscroll
clickclick→clickclick
-scrollscroll
click-click→click
-dragscroll
click--click→
--scroll
clickdrag→clickclick
-scrollscroll
clickclickscroll→click
-dragscroll
clickclickclickscroll→
-dragscroll

表にはデバッグしきれなかった赤い欄が4カ所残っています。これらに共通しているのは、画像の下側と左右に有る茶色のバー (hbar, vbar)の操作の連なりが「click ⇔ scroll」になっていることです。それ以上の解明は出来ていません。とは言え、例えば、 「click」 が不発だったとしても、再度 「click」 すれば、実行出来るという程度にはなっています。

それにしても、スマートフォンは変態過ぎます。それから、 Chrome のデバッガーにスマートフォン・モードが有ったのは、大いに助かりました。

2020年3月21日 (土)

非表示⇒表示の実行は同一関数内では無意味・・・たぶん

先に書いた LongDriver のデバッグ記事 touchEvent の奇妙な振る舞い⇒迂回策 で、対症療法として仮想マウスパッドを表示し直すという考えを書きました。その際、非表示のコードと表示のコードを

    // code-A
    ground.pad.setAttribute("display", "none")    // (1)
    ground.pad.setAttribute("display", "inline")  // (2)

のように続けて書いたら期待した効果は得られず、

        // code-B
        ground.pad.setAttribute("display", "none");
        setTimeout(function(){
            ground.pad.setAttribute("display", "inline");
        }, 10);

のように、間にディレイを入れると良いと書きました。実は、ディレイを入れるだけならば下記コードもアリですが、これでは LongDriver の不具合は解消されません。

        // code-C
        ground.pad.setAttribute("display", "none");
        setTimeout(function(){return;}, 10);    // (3)
        ground.pad.setAttribute("display", "inline");

このことより、不具合解消に必要なのはディレイではない他の何かだと思われます。裏付けの無い推測ですが、表示に関わるコードは、それが置かれている関数を抜け出る時にまとめて反映されるのではないかと思います。その時、不要な処理は省略されるのではないでしょうか。すなわち、 code-A で (1) は省略されて仮想マウスパッドは非表示化されずに、ただ表示されたままのため、表示し直す効果が得られなかったのではないでしょうか。実際、 code-C を実行した時、仮想マウスパッドが一瞬でも非表示化されることはありませんでした。 (3) の 101000 すなわち 1000ms に増やしても非表示化は確認されませんでした。 code-B では、それが置かれている関数を抜けた後で setTimeout() で指定されている関数を実行するので、非表示と表示が確実に実施されるのだと思います。

そういう訳で、仮想マウスパッドの表示し直しは code-B で行いました。

2020年3月16日 (月)

touchEvent の奇妙な振る舞い⇒迂回策

フットボールのプレイブック・ソフト LongDriver がスマートフォンで正常に動作していないことは既に書いていますが、いくつか有る不具合のうち1つは改善出来ました。その不具合と対策は以下の通りです。

スマートフォンでの LongDriver

まず、選手を移動する手順(期待される動作)は次の通りです。この手順は、正常に動作した場合のもので、実際は 4. で異常が発生します。

    選手移動手順
  1. 画像の上下に配置している選手のダミーマークをタップ
  2. フィールドに薄い灰色のシート(←仮想マウスパッド)が表示される
  3. そのパッドに指をタッチして動かすとフィールドの選手が移動する
  4. 上記 3. を繰り返す
  5. 画像の左右に有る茶色バーをタップ
  6. 仮想マウスパッドが消える

手順の 3. 4. で発生するイベント touchstart, touchmove, touchend に応じてイベントハンドラー startDrag(), drag(), endDrag() が実行されます。3つのハンドラーとも evt.preventDefault() を実行しています。 startDrag() でイベント touchmove に対するハンドラー drag() が登録され、 endDrag()drag() が解除されます。

function startDrag(evt){
	evt.preventDefault();
	・・・
	pad.addEventListener(touchmove, drag, {passive: false});
}

function drag(evt){
	evt.preventDefault();
	・・・
}

function endDrag(evt){
	evt.preventDefault();
	・・・
	ground.pad.removeEventListener(touchmove, drag, {passive: false});
	・・・
}

上記の選手移動手順を実行していて不思議なのは、 3. を最初に実行する時は問題が発生しないのに、 4. で 3. を繰り返そうとしても drag() が実行されず、選手の移動が出来ないことです。その時、 startDrag()evt.preventDefault()

  • Ignored attempt to cancel a touchstart event with cancelable=false, for example because scrolling is in progress and cannot be interrupted.

というエラーが発生します。これは、「スクロールか何かの最中なので evt.preventDefault() 出来ない」ということです・・・スクロール?? そんなことしていないのに? なお、 endDrag()evt.preventDefault() ではこのエラーは発生していません。

選手移動の手順を一通り終了して再度実施すると、同じく 3. は実行出来て 4. でエラーが発生します。これも不思議です。選手移動モードを一旦抜ける(手順の 5. 6.)と、エラーメッセージに有る 「scrolling is in progress」 がキャンセルされるということなのでしょうか? 手順の 6. は hidePad() というハンドラーで実現されています。また、再実行の入り口では手順の 1. 2. で pickup() というハンドラーが実行されます。しかし、これらのハンドラー内で「scrolling is in progress」 のキャンセルに関わりそうな箇所は有りません。何故、手順の再実行が可能なのか不明です。

とにかく、手順を最初から実施すれば、 3. は実行できるので、試しに、デバッガーのコンソールから

ground.pad.setAttribute("display", "none")

ground.pad.setAttribute("display", "inline")

を続けて実行してみました。これらは仮想マウスパッドを非表示および表示するコードです。これを実行すると、直後の1回だけ選手移動(つまり 3.)が出来ました。カラクリは判りませんが、とにかく、仮想マウスパッドを表示しなおせばエラーは発生しないわけです。そこで、そのコードを endDrag() に追加しました(1)。ただし、非表示と表示のコードをただ並べただけではダメで、幾ばくかのディレイが必要です(注意)。数百ミリ秒から試してみて、 10 ミリ秒でもOKなことは確認済みです(最小値かどうかは未確認)。

(注意):訂正有り(非表示⇒表示の実行は同一関数内では無意味・・・たぶん

function endDrag(evt){
	・・・
	if (ground.isTouchPnl){			// (1) 6行追加
		ground.pad.setAttribute("display", "none");
		setTimeout(function(){
			ground.pad.setAttribute("display", "inline");
		}, 10);
	}
}

取り敢えず、これで選手の移動は出来るようになりました。しかし、未だ解決出来ていない不具合は有ります。デバッグはもう少しかかりそうです。

追記:LongDriver にアクセスしただけではキャッシュが残っていて、デバッグの効果が反映されないかも知れません。 LongDriver のキャッシュをクリアーしてからアクセスする必要が有ります。

« 2020年2月 | トップページ | 2020年4月 »