Vue.js で SJIS コードの CSV をダウンロードさせる

結構探してベストプラクティスっぽいものが無かったので記録として。

サーバーサイドでデータを作る

CSV 形式でデータをダウンロードさせる方法はいくつかあるのですが、Javascript のコードが UTF8 になっているので、これ以外の形式でダウンロードさせるときには結構工夫が必要です。
特に、古めの Excel で直接開こうとするとき SJIS コードが必要になり、これが結構厄介です。

方法としては、

  • サーバーサイドの Laravel 側で SJIS 形式でデータを作って、ブラウザで直接ダウンロード
  • クライアントサイドの Javascript で SJIS 形式データを作って、ダウロードさせる

前者のほうが簡単に見えますが、ブラウザ側で Vue.js を使ったりして、WEB API 経由でデータを取ろうとする途端に厄介毎に巻き込まれます。
ならば、後者のほうで UTF8 で WEB API を呼び出して、Vue.js 側で SJIS 変換すればよい、と思いつつもピッタリのサイトが見つかりませんでした。

結論から言えば、encoding.js を使って UTF8 から SJIS に変換できます。

Vue.js でダウンロードさせる

手順は2つになります。

  • Web API 経由で、JSON 形式でデータを取得
  • 取得したデータを encoding.js でコンバートしてダウンロード

Web API 経由でデータを取得したほうが、Vue.js などの SPA では必須になります。API の呼び出しは axios を使っています。

axios.post(url, { params: params })
.then(function(response){
    var head = "...";
    var filename = "sample.csv";
    this.downloadCsv(head, response.data, filename );
}

適当なパラメーターをサーバーサイドへ POST します。
取得できるデータは JSON 形式としておきます。

CDN で encoding.js をインクルードして、downloadCsv 関数と downloadCsvBlob 関数を定義します。
downloadCsvBlob 関数は、Edge と Chrome の両方を動作させるための共通関数です。この関数は、【JavaScript】Axiosを使ってCSVをダウンロードしたい | ゆとって生きたい。 から持ってきています。

<script src="https://cdnjs.cloudflare.com/ajax/libs/encoding-japanese/1.0.30/encoding.js"></script>

function downloadCsv( head, items, filename ) {
    var csv = "";
    items.forEach(function(it) {
        csv += Object.keys(it).map(function(item){
        return it[item]
        }).join(',') + "\n";
    }.bind(csv))
    csv = head + "\n" + csv ;
    csv = new Encoding.stringToCode(csv)
    csv = Encoding.convert( csv, 'SJIS');
    csv = new Uint8Array( csv );
    this.downloadCsvBlob( csv, filename );
}

function downloadCsvBlob(blob, fileName) {
    if (window.navigator.msSaveOrOpenBlob) {
        // for IE,Edge
        var blob = new Blob([blob], { "type" : "text/csv" });    
        window.navigator.msSaveOrOpenBlob(blob, fileName);
    } else {
        // for chrome, firefox
        const url = URL.createObjectURL(new Blob([blob], {type: 'text/csv'}));
        const linkEl = document.createElement('a');
        linkEl.href = url;
        linkEl.setAttribute('download', fileName);
        document.body.appendChild(linkEl);
        linkEl.click();
        URL.revokeObjectURL(url);
        linkEl.parentNode.removeChild(linkEl);
    }
}

コード変換の肝は、以下の部分ですね。
いくつか試してみたのですが、この順番でないとうまく動かないようです。変数 csv を省略しようとする動かなくなったりするのは、内部データの使い方の問題だと思いますが、ひとまず、以下の形で UTF8 から SJIS に変換ができるようになります。

    csv = new Encoding.stringToCode(csv)
    csv = Encoding.convert( csv, 'SJIS');
    csv = new Uint8Array( csv );

これでブラウザ上のボタンをクリックすると SJIS 形式のデータをダウンロードさせることができます。当然のことながら、Web API を叩かないで、ブラウザ上だけで計算してデータをダウンロードさせることも可能です。

参考先

カテゴリー: 開発 | Vue.js で SJIS コードの CSV をダウンロードさせる はコメントを受け付けていません

学童でプログラミング教室を開いた3年間の話

少しプライベートな話になってしまうが記録として残しておこう。
ひょっとすると個人が特定できてしまうかもしれないが、特定せずに「マックで女子高生が話していた」程度に捉えてほしい。

プログラミング教室の事始め

板橋区のとある学童でプログラミング教室を隔週で開催している。板橋区は学童を「あいキッズ」という形で民間に委託しており、それを受けた民間の会社やNPO法人が委託した予算内でいろいろな試みをしている。私が関わっている「放課後NPOアフタースクール」もそのひとつで、あいキッズの中で、いくつかの学習企画を立てている。

その昔、学童といえば共働きの鍵っ子や、母子家庭の子が預けられる子というイメージが強かったのだが、最近はそうでもない。共働きの家庭がクラスの半分に及び、学校が終わってから親が家に変えるまでの数時間の間、小学生は学童ですごすことはごく普通な日常となっている。だいたい、学年で約半分の子は学童に通っていたりする。

学童は保育園と同じ様に保育の場ではあるもの、「あいキッズ」が民間に委託されている特性から、

  • 学童で何かを学習させる
  • 学童で何かを運動させる
  • 学童で何かを食べさせる

の用途もあいキッズに含まれている。学習や運動は、職員が行う折り紙教室やレゴ作り、サッカー、鬼ごっこなど、毎日細かなイベントが組まれている。お誕生日会や宿題の面倒などもあいキッズの役割である。

そして「放課後NPOアフタースクール」の場合は、職員が行うイベントとは他に、「市民先生」と呼ばれる板橋区から通えるような距離の民間の先生を呼んできて、1時間程児童に何かを教えるという学習スタイルが組まれている。

その中でプログラミング教室の打診を受けたのは、3年間のことで、まだ小学校でプログラム研修が本格化する前だった。しかし、既に Scratch などの子供向けのプログラミング教材は整いつつあった。最初は週1という話であったのだが、フリーランスにとって週1で時間を取られるのは難しく、隔週にしてもらった。これは金額的に安いというのも最初の理由である。

プログラミング教室の準備

子供向けプログラミング教室と言えば、月1万円の月謝を取るところも少なくはない。教材に至っては、LEGO などを使って5,6万円するものもある。一般向け(いわば富裕層向け)にならば、その値段でも殺到するかもしれないが、学童でのプログラミング教室では到底無理である。同時に、あいキッズに委託している金額もそう多くはないので、プログラミング教室だけにお金を掛けるわけにはいかない。

よって、

  • できるだけ、低予算(ノートパソコンのみ)で行う
  • 印刷教材は、あいキッズ側で受け持って貰う
  • 毎回のパソコンのセッティングはあいキッズ側で行って貰う

という条件で始めた。大抵のプログラミング教室では据え置きのPCかノートPCが使われる。専用の場所が確保されるため、PC や教材を据え置くことができる。しかし、今回のあいキッズの場合は、共同の教室での開催となるので、毎回ノートPCを設置/片付けが必要になる。これを毎回、私ひとりで行うのは大変なので、あいキッズの職員にやってもらう(結果、あいキッズのアルバイトがやることなった)。

同時に、児童分の印刷教材を家でプリントアウトすると大変なので、これもあいキッズ側で行って貰う。印刷教材も低予算にするために、毎回数枚のカラープリントで済ませている。実は、印刷教材はなくてもよかったのだが、プログラミング教室を始めるときに

  • 参加する児童から、いくらかの月謝(300円程度)を取る

ことに決めた。これは、プログラミングが人気になりつつあったと、パソコンを使わざるを得ないので、人数を制限したかったからだ。月謝はあまり意味はない。学童の場合には、月1,000円でもキツイ家庭があるので、300円程度と設定している。
このため、300円分の何かのお返しをしようというわけで、印刷教材をつくることにした。実際の時給は度外視である。

パソコンを毎回移動しないといけないために、ノートPCを購入することにした。
新品では難しいので、中古の Windows 7 を探し貰うことにした。ノート PC の選定や購入に関しては、本来ならば私がやるところなのだが、それだと「お金」が掛かってしまうので、これもあいキッズ側でやってもらうことにした。
ノートPC は機種はばらばらだが8台ぐらいまで用意した。これを2人交代で使うとして、16人までの教室として設定した。

この「費用」にいちいち細かく言及するのは、このプログラミング教室を「ボランティア」でやる気はなかったということだ。いや、実質ボランティアかもしれないが、完全な無償の場合には長く続かない(実際、市民先生で残っているのは私ひとりだけだそうだ)。いくらかの報酬を貰い、それに見合うだけの仕事というスタイルとることに決めているし、実際よかったと思っている。

金額的には月1万円(源泉徴収、振込手数料などが抜かれるので、実際は9,500円位になる)で請けおっている。
仕事としては到底割に合わないことが理解できるだろう。

初年度の意気込み

ノートPC も準備してもらい、ある程度の印刷教材を用意して、4月からスタートした。
教えるプログラム言語は Scratch と決めておき、いずれは Python か Arduino で電子工作、という妄想を抱いていた。

そう、妄想は第1回目から打ち砕かれてしまうのだ、

  • 教室にいる人数が予定よりも多い。どうやら水増しで 20 人位になっていた。
  • 白板みたいなものがないので、解説ができない、話を効聞かない
  • みな一斉に同じことをやる、ということが出来ない、待てない

一応、小学3年より上という制限を付けたのだが、いやいや無理、社会人の社員研修とは全く違う。これは自分の子を考えて分かったことで、20 人位あつまると教室は騒がしくなんともできない状態になってしまう。

3、4回ぐらいまでは自前な教材に沿ってぽちぽちやっていたのだが、諦めた。これは好き勝手やって貰うほうがよい。教えるという教師的な目線ではなくて、プログラミング教室に居るおっちゃんのイメージに切り替えた。

毎回、印刷教材を5分だけ解説する。その後は自由に Scratch で遊ぶ。何か聞かれたら答える。私自身も暇なときは Scratch で遊ぶ。そんな適当な雰囲気にすることにした。

学習障害っぽい子がいる

学習障害の場合、心理学的言えば、多動性、注意欠陥、アスペルガーと色々な症候群があるのだが、ちょっと発達障害っぽい子がいた。実際、板橋区では小学校の中に発達障害のクラスを別途もうけているところが多い。「5組」と言ったりする。

その昔、今で言えば発達障害っぽい子がクラスに1人か2人はいたものだ。授業中に無闇に騒いでみたり、椅子に座っていられなかったり、大声を出したり、逆に緘黙症だったりと。今でいえば、軽い発達障害なんだけど、みな同じクラスにてちょっと変な子だった。それでも友達だった。

そうい意味で、学童でもちょっと変な子が混じっていて、その子も友達の輪に入っている。
仮に「H君」と呼ぼう。正確な症例はあえて聞かなかったが、5組な子なそうで、あいキッズの職員も手を焼いているとのこと。H君は、当時小4だった。

  • ひとりでノートPCを占有できないと騒ぎ立てる
  • ペアで組んでいる子に順番を渡さない
  • プログラムが上手くいかないと拗ねる
  • 拗ねると、ロッカーとか入って中味をぐちゃぐちゃにする

もう、まったくまともに扱ったら胃が痛くなる感じである。
ちなみに、あいキッズの職員に「プログラミング教室をやっている間は、H君がいないから楽なんですよ」と言われてしまいました。その分、プログラミング教室は大変なんですけどね。まあ、いいんですが。

H君の対応に対して、あるとき気付いた、

  • うちの小1の子と同じじゃないか。

なるほど、自分の息子(当時、小1)に Scratch を教えようとしたら全然覚えなくて、癇癪をおこして、遊び出して、云うことはきかない。なんだ、小1の子と同じだ、ことに気付いた。

それ以来、H君対応は私にとって楽になって、小1だと思うと全然苦にならなくなった。発達障害というのはそういうものだし、後にH君は落ち着くことなる。小5の後半位から落ち着き始めて、小6だと全然大丈夫になっていった。今回の新型コロナウィルス騒ぎで、卒業のお祝いを言えなかったのが残念なのだが、彼に対しては少しだけスキンシップを行うにした。頭をなぜたり、何かやっているときに肩を叩いてあげたり、逆に好きなことをやっているときはほおっておいたり。他の子のガードもあり、彼だけに私のノートPCを使っても貰っていた。子どもに特性にもよるけれども、H君にはちょうどそれがよかったらしい。いや、私はそう思う。

学生ボランティアの存在

プログラミング教室を始めるときに、ひとつ注文があって「誰かボランティアを付けてください」ということにした。これは、16人(結果的に20人位だが)を1人で相手をするのは無理だと思ったからだ。実際無理だ。本格的なプログラミング教室ならば、児童ひとりのノートPCを一台ずつ付けて、8人位が限界だ。

最初は、交代であいキッズの職員が担当していたのだが、パソコンに不慣れというか、どうも「教育」に不慣れなところがあって、なにかと疲れた。

3か月ぐらい経った頃だったが、大東文化大の学生がボランティア(アルバイト?)で常駐することになった。後から分かったことだが、教育学科で、その後は大学院に行った学生である。今年の3月に大学院を修士で卒業している。
この学生が、子ども達に無茶な注文(あれこれ暴れる、あれこれ喧嘩する、あれこれ走り回る)に対応してくれたので非常に助かった。彼女がいなかったらプログラミング教室は廻らなかっただろう。今年から居ないので、どうなるかわからないけど、ノウハウ的に3年間溜まったのでなんとかなると思う、まだ再開していないけど。

学童は半分しつけもやるので、「子どもを叱る」というのが頻発する。大人が真剣に子どもを叱ると、子どものほうも真剣に泣いたり反省したりする。へらへらとあしらうと、へらへらと返してくる。
私は子どもたちを「教育」する立場でははない(教育免許も持ってないし、そういう学習も受け手は無い)ので、其処のは踏み込まないこにした。あくまでプログラマ的な立場や、心理学的な立場(ユング心理学とか)での立場を守って、踏み込み過ぎないようにしている。

Scratch を自由に扱う

最初は、Pyton や Arduino と思っていたのだが、横並びの授業はできないことがわかったので、Scratch を自由に扱うことにしている。パソコンを使っているので、

  • キーボードを自分で打つ
  • Youtube は見ない

というルールにしている。Youtube を見ると回線がパンクするという理由もある。
Scratch には色々なゲームがアップされているので、これは自由に検索して使ってよいことにしている。一応、毎回課題やプリントは配っているのだが、無視するのは自由(苦笑)。課題をこなすのも自由である。
女の子のほうが比較的まじめに課題シートをやるのだが、必ずしもそうではない。ずっと絵を書いている子もいれば、やっぱり飽きて来なくなってしまった子もいる。
別の Scratch 教室に通っている子は、どんどん課題をこなしたり自由に作品を作ったりする。作品を作っている横で3人で交代で Scratch のゲームをしている子たちもいる。いろいろ雑多だ。

キーボードを自分で打つというルールは、キーボードに慣れるためだ。他に、ゲームをやりたいときに検索ボックスに自分でローマ字で打つことにしている。横でアルファベットを教えてあげるけど、キーボードを打つのは子ど自身だ。間違っても根気よくアルファベットを言う。

何か友達がゲームをしていて、あのゲームがしたい、と私(先生)に聞いてきたときは、友達に直接聞いて、ということにしている。学童の場合、学年はばらばらだけど皆顔見知りなのでそれなりに「友達」だったりする。なので、聞けば教えてくれる。最初は友達じゃなくても教えてくれる。これは重要だ。

プログラミング教室内でも、いくつかのブームがあって、

  • ファミスタ野球ブーム
  • ペーパーマインクラフトブーム

なんてのがある。試しに2台ほど、本物の?マインクラフトを入れたのだが、そのうちにペーパーマインクラフトのほうに戻ってしまうのは不思議なところだ。

いまでは「支える」ことに集中している。

来なくなった子も何人かいる

3年間やっているが、途中で来なくなった子もいる。プログラミング教室は他の部活動?(サッカーとか)に比べると抜ける子はそう多くないそうなのだが、それでもいる。

  • タイピングソフトを所望していたが、そのうち来なくなった
  • 絵を書いていたが、来なくなった
  • 塾が忙しくなって来なくなった

私はパソコンが好きでやっているのだけど、向かない/面白くない人もいるのも分かる。なんで、プログラミング自体が向かない、ゲーム自体がたいして面白くないという子や人もいる。そういう場合は、サッカーとか書道とか別の活動をやればよいのだ。

小学校で本格的にプログラミング授業がはじまると、このあたりが問題になってくると思う。プログラミングだけが特別とは言わないし、逆にプログラミングをやらなくてもいいと思う場合も多い。プログラミングをやらないから「論理思考ができない」とは思わない。ただ、いくつかのプログラミング手法が、論理思考の手助けになることは確かなことだ。

あと、小6になると中学受験で来なくなった子が多くなる。その子は往々にして Scratch ができる子なので、もったいないといえばもったいないけど、限られた時間は限られた時間になるので、そこは中学受験に割り振られれうのだろう。

今後の方針

4月から4年目となるのだが、この新型コロナウィルスのおかげでまだスタートしていない。
一般的なプログラミング教室とは異なり、学童で行うプログラミング教室は、学童そして「子どもを安全に預かる」ことが最優先になる。なので、無理矢理教えようとしないのが長く続くコツとなる。教えたりするのはおまけだったりする。

が、さすがに3年目のペーパーマインクラフトブームは長く続きすぎたので、もうちょっと教材を考えようかなと思っている。

ちなみ、ペーパーマインクラフトは、マイクラ remix-2-2 on Scratch で遊べる。いやー、よくできているので、長々と時間が潰せます(苦笑)。お試しあれ。

カテゴリー: 開発 | 2件のコメント

隠れSIRモデルを試作して、東京都の感染者を予測する

実地な値を使って検証するのは避けていたのだけど、現在の状況を見て解説することにします。

隠れ感染者が一定量いる

現在、東京都の新規患者が100人/日を超えています。指数関数的増加(差分が1.0以上となるので複利的に増加する)が理解できていれば、次の増加が100人ではなく、それ以上にとなることは容易に推測ができます。

ただし、単純に「指数関数的増加」とはいえ、いったいどのくらいの増加数なのか?を予測しておくことは大切なことです。

新型コロナウィルスの厄介な点は、

  • 感染率がインフルエンザと同程度に低い(麻疹などよりもかなり低い)
  • 潜伏期間が2週間と長い
  • 感染しても無症状な人が一定量(8割程度)いるらしい

ところです。このため、麻疹のように一気に拡散&重症化する場合は、発病後すぐに家や病院にこもるために、あまり外側に拡散されることがないとありません。潜伏期間が長いと、いつ罹患したのかがやっかいです。クラスター対策班がクラスターの追跡ができなくなってきているのはこのためです。同時に、感染しても無症状であれば、感染したまま普通の生活を送ることになります。無症状であるために、病院に行くこともなく家で休むこともなく PCR 検査や検体検査を受けることしません。このため、本人の意図とは関係なく、ウィルスが蔓延してしまいます。

進化論的に言えば、これが新型コロナウィルスの「生存戦略」ということになります。

隠れ感染者を推測する

潜伏期間中であったり無症状な感染者を「隠れ感染者」と呼びましょう。この「隠れ感染者」は数値の上ではでてきません。毎日、定期的に発表される新規感染者とは別に扱う必要があります。

では、どうやって「隠れ感染者」を推測するのでしょうか?

感染の因果関係として、

  • 新規感染者が発生する
  • 新規感染者は潜伏期間(2週間)前に何処かで感染している
  • 新規感染者を感染させた元の感染者がいる

ことが条件になります。実際は海外から帰国した感染者もいるので誤差でるのですが、おおまかな東京都の感染者の状況はこの感染の因果関係にあてはめられます。

これを SIR モデルに当てはめてみます。

新規感染者 dIt/dt を発症した日(14日前)に「隠れ新規感染者」として設定します。
隠れ新規を累積して、隠れ累積患者数を計算します。このとき、その日の新規患者を取り除きます。これは新規患者としてカウントして隔離されるためです。
隠れ累計と隠れ新規の関係から、感染率が計算できます。感染率 β は、もとの SIR モデルの感染率や基本再生産数とは異なる定義となるため、このモデル独自のものです。もう少し式変形をして、基本再生産数と比較できるようにしていきます。

既に新規感染者が計測されている日から14日さかのぼったところの感染率βが算出できます。
これをもとにして、予測感染率β*を推測します。
一般に、何らかの環境の操作(外出の自粛など)が行われない限り、予測感染率は前日の感染率を踏襲するはずです。

この予測感染率 β* から、予測隠れ新規患者数を計算します。
予測隠れ新規の数は、14日後に予測新規患者数となり、新規の感染者数が予測できるというモデルです。

Excel で予測する

これを Excel 使って計算してみましょう。

東京都 新型コロナウイルス陽性患者発表詳細 – 東京都_新型コロナウイルス陽性患者発表詳細 – 東京都オープンデータカタログサイト

4/6 付けの東京都の患者データを使って予測してみます。

青いセルが予測の部分です。「患者累積」と「隠れ累積」が大きくずれているのは、新規患者をうまく拾えていないのと、発症までの潜伏期間が2週間と長いために潜在的な患者が滞留してしまっているのが理由です。
単純計算いけば、新規患者数100人×14日間 = 1400人以上は滞留していることになります。

2週間ほどさかのぼって、感染率の予測値を入れます

  • 0.160 は、3/22 までの大まかな平均値です。4/6 付けで新規患者数が83人と若干減っているので実効感染率が一時的に下がっていますが、いまのところ外れ値として処理しています。継続して下がっていれば、この感染率をさげます。
  • 4/4 からの 0.080 は土日で自粛が効果的に行われたとみなして下げてあります。

感染率の絶対値は、特に意味はありません。いずれ実効再生産数のような割り出しが必要になります。
ここでは、相対的な値となっています。

それぞれの値をプロットしたの下の図です。

予測患者数累積が非常にあがっていることが分かります。

対数軸にプロットしたとき、患者累積と隠れ累積の差が大きくならないように注意が必要です。

現時点でプロットしてみたところ

  • 4/11 頃に患者数の累積が2,000人を超える
  • 新規患者は500人のピークがある
  • 4/4 の自粛は、4/18 頃に効果が現れるので、それまでは同じペースで自粛が必要となる
  • 増え方は急ではあるが、きちんと自粛をすれば、患者数が1万人を超えるのは4月末以降の予想となる

問題は、新規患者数が500人/日程度発生するが、医療崩壊を起さずにこれを受け入れらるか?ということです。
このモデルで計算したときには、「隠れ累積患者数」が4,000人程度いることと2週間遅れで発病することをあわせると、かなり厳しい状態と言えます。ただし、軽症/重症者が混在するので、この比率が問題になります。

データ

Excel データは以下でダウンロードが可能です。

参考文献

カテゴリー: 開発 | 隠れSIRモデルを試作して、東京都の感染者を予測する はコメントを受け付けていません

感染症数理モデルでシミュレーションする(その2)

3週間ほど経ち状況が変わってきていますが、感染症数理モデルの話を引き続き

SEIR モデルを JS で書く

新型コロナウィルスの専門家委員会から「基本再生産数 R0」や「実効再生産数 R」という言葉でてきます。他にも専門用語がでてきますが、これらを一般的に解説するかどうかの前に「その専門分野ではどのような使い方をされているのか?」を正確に把握するする必要があります。まあ、それが「専門分野」なのですから、同じ言葉を使っていても専門分野ごとに多少の違いはあるし、逆に同じ用語を他の分野でも同じ様に使っている場合もあります。どちらにせよ、その分野での専門用語の把握が必要です。

そんな訳で、2週間ほど前になりますが、SEIR モデルを Javascript で書きました。元の Python からそのまま JS に書き替えて、そのあと R0 を取り込めるようにしています。ちょっと、R0 の意味が分からなくてコードが間違えていたのですが、先日直したので、ここにコードの解説をしておきます。

SEIR モデルの数式

実は、Wikipedia を見ると、日本語のものと英語のものと SEIR モデルの式が若干違います。感染率 β の部分で総数 N が出てくるのですが、日本語の場合は、β(N) のように総数に依存するのですが、英語版のほうは β は N から独立しています。
感染率が総数 N に依存するのは変な感じがするので、英語版のほうを使うことにしました。

The SEIR model

出生率 Λ と死亡率 μ は短期間なので、0 とみなせます。これを書き方えたのが下の式になります。

  • N: 全体の総数
  • S: 未感染者
  • E: 潜伏期間中
  • I: 発症者
  • R: 回復者/免疫を得た人

になります。イギリスで発表された全国民が感染して免疫を得るという方式は、この SEIR モデルの、R になるということです。SEIR モデルの場合、感染して潜伏→発症→回復という順番になるのですが、かならず回復するというモデルなので、今回のような新型コロナウィルスのように発症後に死亡するケースがある場合には、致死率が2%程度だとしても相当の死亡者が予想されます。

即効撤回されたのは、良い判断でした。

この式の中でのパラメータとして、以下の3つがあります。

  • α: 潜伏率
  • β: 感染率
  • γ: 回復率

これらは、潜伏期間 lp と発症期間 ip で書き替えることができます。

  • α = 1/lp : 潜伏帰還の逆数
  • γ = 1/ip : 発症期間の逆数

肝心の感染率 β の値ですが、基本再生産数 R0 との関係が以下のようになります。

死亡率 μ が 0 となるので、R0 は 感染率 β と 回復率 γ との比になります。
式の中では感染率 β を使うことになるので、次のように書き替えます。

この式から分かることは、

  • 感染率 β と回復率 γ が等しいときに R0 が 1.0 になる
  • 感染率 β が回復率 γ が大きいときに R0 は 1 を超えて、感染が拡大する
  • 感染率 β が回復率 γ が小さいときに R0 は 1 より小さくなり、感染は縮小していく

という現象になります。これが専門家会議の言う「基本再生産数 R0」の意味です。
なので、できるだけ R0 < 1.0 の状態を保ちながら、ピークを低く抑えましょうという対策の根拠になります。

SEIR モデルを JS に直す

この数式を Javascript に直すと次のようになります。
v のところが配列になっているのは Python コードの名残りです。

function seir_eq(v,t,alpha,beta,gamma,N) {

    S = v[0]
    E = v[1]
    I = v[2]
    R = v[3]
    ds = - beta * I / N * S             // dS/dt = -βI/N*S
    de = beta * I / N * S - alpha * E   // dE/dt = βI/N*S-αE
    di = alpha * E - gamma * I          // dI/dt = αE - γI
    dr = gamma * I                      // dR/dt = γI 

    return [ds,de,di,dr];
}

これを100日間繰り返すのが次の calc 関数です。
SEIR モデルに、試しに隔離率(T) を埋め込んでみて、発症者の一定割合を病院に隔離するというシミュレーションも入れておきます。
あと、S,E,I,R の数はマイナス値にはならないので繰り返し計算をするときに補正します。

function calc(state,alpha,beta,gamma) {
    var t_max = 100 ;
    var dt = 1 ;
    lst = []
    var N = Sinit + Einit + Iinit + Rinit
    console.log( state );

    for ( var i=0; i<t_max; i++ ) {

        var d =  seir_eq( state, i, alpha,beta,gamma, N )
        var Si = state[0]+d[0]
        var Ei = state[1]+d[1]
        var Ii = state[2]+d[2]
        var Ri = state[3]+d[3]
        // 感染者を発見して隔離する
        dx = Ii * T
        Ii = Ii - dx
        Ri = Ri + dx // 免疫者に加算

        // マイナス値を調節する
        if ( Si < 0 ) {
            Ei = Ei + Si; Si = 0;
        }
        if ( Ei < 0 ) {
            Ii = Ii + Ei; Ei = 0;
        }
        if ( Ii < 0 ) {
            Ri = Ri + Ii; Ii = 0;
        }

        state = [ Si, Ei, Ii, Ri ]
        // console.log( state );
        lst.push( state );
    }
}

グラフ化する

これに vue.js とグラフツールの c3.js を追加したが次の形です。

SEIR モデル シミュレータ

このグラフは基本再生産数 R0 が 10 のときのものです。10 というのは非常に多い値なのですが、いわゆるダイヤモンドプリンセス号のような閉鎖空間のクラスター(患者集団)の場合がこれに相当します。時間を追うごとに加速度的に感染者が広がります。

注目して欲しいのは、以下の3点です。

  • 発病者のピークは感染スタートよりも左にある
  • 潜伏期間中(黄色)のピークは、発病者(緑)のピークよりも左にある
  • 最終的にほとんどの人が回復者(赤)となる

このグラフでは潜伏期間2週間で考えているので、発病者(緑)のピークは感染スタートから2週間以降になります。感染スタート時にすべての人が感染する訳ではないので、幅を取って2週間から3週間というところです。これが、現在の花見や春休みのシーズがスタートとなったときに、2,3週間後に流行するのでは?という理由です。

当然のことながら、発病期間のピークの前に、潜伏期間のピークがあります。SEIR モデルは潜伏期間中には罹患させないモデルになっていますが、新型コロナウィルスは潜伏期間中も罹患させる可能性がある、または無症状の場合も感染さえる場合があるという「可能性」が指摘されています。
このため、潜伏期間中の人が活発に活動すると、その後に発症のピークが出るかもしれません。

SEIR モデルの場合は、最終的にほとんどの人が感染して回復します。というか、無限に計算を続ければ100%の人が感染し回復して終わるようになっています。
先に書きましたが、SEIR モデルの場合は発症→回復となるので、死亡者がいません。実際の新型コロナウィルスでは死亡するので、最終的な回復者数×死亡率が全体の死亡数になってしまいます。
このため、無防備な策は誤りです。

基本再生産数 R0 を 1 に近づける

基本再生産数 R0(あるいは実効再生産数 R)は、感染率 β と回復率 γ との比率になります。

R0 を 1.0 に近づける(1.0以下にする)というのはどういうことかというと、数式からは以下の2つの手段があります。

  • 感染率 β を下げる
  • 回復率 γ を上げる

感染率を低く押さえるというとは、いわゆる「誰かに罹患させる確率を減らす」ということです。移動を減らすとか、3つの条件が重なる場所を作らないあるいは行かない、というのがその手段です。
もうひとつは、回復率を上げるというのは、病床を増やす、体力を蓄えておいて軽症で済ませるなどがあります。

基本再生産数 R0 を 10,5,2 と変化させてみましょう。



発症者(緑)のピークが限りなく右にずれることがわかります。
つまり「ピークを平らにする」ということは、基本再生産数 R0 を限りなく1.0に近づける(あるいは1.0以下にする)ことであり、同時に感染者のピークを限りなく未来に追いやることができます。

そして、新型コロナウィルスに対しての有効なワクチンや予防接種ができるまでの時間稼ぎができます。

基本再生産数 R0 が 1.0 のときは?

実験として、基本再生産数 R0 が 1.0 のときはどうなるのかを見ていきましょう。

感染者数(緑)のグラフが非常に平らになりほとんど直線になります。
罹患した後に回復した人も全然増えていないように見えますが、実際は回復者が100日目で25人になります。

これから分かることは、

  • 感染がまったく広がらない訳ではない。わずかずつ感染は広がる
  • しかし、対処可能な感染者数となる

ことを示しています。確率的に感染者は発生するのですから、何処から感染するかは分かりません。しかし、感染して発病したとしても、十分に治療可能な病床が用意できる、ことを意味しています。

github

コードは github moonmile/seir-model: SEIR model simulator に公開しています。

おまけ 実効再生産数 R とは?

ここからは私的なメモです。

基本再生産数 R0 と実効再生産数 R の違いを記述しておきます。
専門家会議では、最初の NHK での解説で「基本再生産数 R0」という用語を使っていました。再生産数という言葉から一般的に「基本再生産数を 1.0 以下に抑えれば、なにかグラフが平たくなる」ことが理解できたと思います。

このグラフが出たのが 2/24 の NHK です。

この感染症の流行モデルの元ネタは当時の NHK の解説では何処にも出てきませんが、専門家会議に北大の西浦教授がいることと、西浦教授の2017の論文から、SEIR モデルがベースであることがわかります。

そのあと、色々な批判もあったのち、海外でもこの「平たくする」図がでてくるようになりました。

Flatten the curve | These guidelines are intended to help Flatten the Curve with the COVID19 outbreak, to help limit spread and reduce the load on hospitals and other healthcare.

ただし、これらの「ピークを平たくする」というイメージには、なんら数式的な根拠が示されていません。SEIR モデルを理解しているのか、それとも読者が SEIR モデルを理解できないと思っているのかは定かではないのですが、肝心の数理モデルはでてきません。twitter で #FlattenTheCurve というハッシュタグで拡散されつつありありますが、根拠は示されてません。

結果的に、発症時のピークを下げる=医療崩壊を防ぐことになるので、効果は同じだと思われるのですが、私が懸念するのは、

  • ピークを下げた時期の概算が示されていない
  • ピークを過ぎた後の発症数の裾野が、いつまで続くのか示されていない

のが問題だと思っています。

また、新型コロナウィルスの特徴として無症状な人が多いことから、新しい感染者を0人にすることはほぼ不可能です。天然痘のように全ての人にワクチンをうって撲滅しない限り 0 にはなりません。

同時に「クラスター対策」として言われるように、基本再生産数 R0 は状況によって大きく変わります。全体の平均として 1.0 以下におさえると、マクロの全体として発症者が押さえられるのは確かなのですが、個々の感染しやすい場所、あるいは感染しやすい季節や場所などのミクロの視点で見れば、基本再生産数は大きく変わり分布を持ちます。

このため「実効再生産数 R」として「実効」を付けて、基本再生産数 R0 になんらかのパラメータを掛けます。いわゆる事前条件を加味します。
どうやら疫学の場合の実効再生産数は、二次感染の平均を考慮するようです。このあたり、最近の専門家会議での解説をみると「実効再生産数 R」と区別されていることがわかります。

詳細は2020年3月19日付けの提言を読むとわかります。

「感染拡大地域では自粛検討を」専門家会議が提言【全文】

  • 基本再生産数(R0:すべての者が感受性を有する集団において1人の感染者が生み出した二次感染者数の平均値)
  • 実効再生産数(感染症の流行が進行中の集団のある時刻における、1人の感染者が生み出した二次感染者数の平均値)

基本再生産数は、一般的な都市での感染率 → 都市機能を保ったまま低く保つ必要がある(一般的なイベントの開催、通勤や通学の正常化など)
実効再生産数は、感染してしまった都市での感染率 → 緊急で下げる必要がある(北海道の緊急事態宣言、ロックダウン、都市封鎖)

のように区別します。

カテゴリー: 開発 | 感染症数理モデルでシミュレーションする(その2) はコメントを受け付けていません

感染症数理モデルでシミュレーションする(その1)

板橋区は来週の火曜日から休校になります。各自いろいろな意見があるわけですが、そのあたり代理戦争はせず、「自衛」という一点でこれを書き留めておきます。
というかですね、「クラスター対策」の説明がされていないような気がするし、検査がなぜ行われないか(あるいは行うのか)、どういう形で決定したのかわからないのが問題だと思うんですよ。個人的に。なので、個人的に調べて、個人的にブログに書き残すという方針なので、そのあたりはご容赦ください。

詳しい情報をたどる

から

2019-nCoVについてのメモとリンク

にたどり着いたあとに「なぜクラスター対策が重要か」

のところまで来て、

Dispersion vs. Control

ここにたどり着きました。

中澤さんのページのリンクがある

①(02251430大臣レク用)クラスター班設置プレス

に「クラスター」の解説があります。これに基づいて厚生労働省は動いていると思われるのですが、そこはさておき、ここにでてくる「SEIRモデル」とは何ぞや?というところからスタートします。

SEIRモデル

SEIRモデル – Wikipedia

を見ると、比較的簡単な微分の方程式です。摂動論(古いけど)をやってた自分としては、ああ、となるし、機械学習を少しかじれば、ああ、となる式でしょう。それほど難しくありません。
時間tによって、状況が変化するという典型的な式です。

難しくはないんですが、いざ数式に直すとすると結構難しそうなので、先人の知恵を辿ります。

新型コロナウイルスの流行を科学的に考えるためのヒント|ノルテ / 気象と波浪の研究者|note

上記の記事から、SEIR の意味がこれです。

  • Susceptible: 感染症に対して免疫を持たない者(無免疫者)
  • Exposed: 感染症が潜伏期間中の者(感染者)
  • Infected: 発症者
  • Recovered: 感染症から回復して免疫を獲得した者(回復者)

wikipedia の式と違うのは、短期間なので、「mは出生率及び死亡率」のmを0とみなすことができるからです。

Dispersion vs. Control からたどった先には、github の R のコードがあります。

[GitHub – HopkinsIDD/nCoV-Sandbox]

あと WHO からのデータはここです。

Situation reports

記号の意味を把握すると、先のS,E,R,Iの初期値の他に

  • β: 感染率
  • lp: 潜伏期間
  • ip: 感染期間

が必要になります。

そのまま R で解けばいいんですが、R が不慣れなので別なのがないかと探します。

感染症数理モデル事始め PythonによるSEIRモデルの概要とパラメータ推定入門 – Qiita

に python の実装があるので、そのまま流用します。

Python で SEIR モデルを動かす

python 自体も不慣れなので、コードとか変数とかはそのままなのですが、以下の3つをインストールした後に

pip install numpy
pip install scipy
pip install matplotlib

次のコードを実行します。

#include package
import numpy as np
from scipy.integrate import odeint
from scipy.optimize import minimize
import matplotlib.pyplot as plt

#define differencial equation of seir model
def seir_eq(v,t,beta,lp,ip):
    return [
        -beta*v[0]*v[2],
        beta*v[0]*v[2]-(1/lp)*v[1],
        (1/lp)*v[1]-(1/ip)*v[2],
        (1/ip)*v[2]]

#solve seir model
ini_state=[3000,0,5,0]
t_max=100
dt=1
t=np.arange(0,t_max,dt)
plt.plot(t,odeint(seir_eq,ini_state,t,args=(0.001,14,7)))

plt.legend(['Susceptible','Exposed','Infected','Recovered'])
plt.show()

パラメータの意味は、以下の通りです。

  • 初期S v[0]: 未感染者 3000
  • 初期E v[1]: 潜伏者 0
  • 初期I v[2]: 発症者 5
  • 初期R v[3]: 免疫獲得者 0
  • 感染率 beta : 0.001
  • 潜伏期間 lp : 14日
  • 発症期間 li : 7日

それっぽい数値を入れてみたのですが、あまり根拠はありません。実際は、それぞれの値は分布(分散)があるので、ランダム値でシミュレーションすることになるはずです。

意味合いとしては、閉鎖空間で3000人いたときに、初期状態で感染者が5人いたときの状況をしらべています。
感染率「0.001」の意味は、「基本再生算数:1人の感染者からうつる人数の目安となる」の R0(WHO で「1.4から2.5」)となるので

感染率 beta 
  = (初期感染者 * R0)/全体の人数
  = (5*1.4)/3000 = 0.0023

という計算となると思うんですが、よくわからないので適当にいれています。

追記:きちんと計算したものはこちら
http://www.moonmile.net/blog/archives/10384

感染率の分布を考える

実際は、感染率 beta や基本再生算数 R0 を推定するわけですが、現在のところ感染力ある程度推測されている(既存のインフルエンザよりも低い)ので、それを当てはめてみています。

ただし、インフルエンザ流行の「スーパースプレッダー」にあるように、感染はまんべんなく起こるわけではなく、とある閉鎖空間で一気に広がるであろうと想像されています。

となれば、感染率 beta には分布があるわけで、

  • とある空間では感染率 beta は限りなく 0 に近い
  • とある空間では感染率 beta は高い

というパターンになります。
今回、感染率の高い空間を「クラスター」と呼ぶわけで、それらは閉鎖空間であったり、不特定多数の人が密集している場であったりします。それらの「クラスター」同士をつなげないようにして、感染拡大を防ぐ、というのが「クラスター対策」の主旨ですね。

ひとまず「SEIRモデル」を数値計算してみたかったので、この後は感染率を分布(Θかσ)させるところへ。

カテゴリー: 開発 | 感染症数理モデルでシミュレーションする(その1) はコメントを受け付けていません

Scratch 3.0 で Web API 呼び出しの拡張ブロックを作る、の手始め

Scratch 3.0 の拡張ブロックの作り方が分かってきたので、Web API の呼び出しを作ってみる。

基本的なところは、Scratch 3.0でオリジナルブロックをつくろう – Qiita と同じで、もうちょっと先に進んでみよう、というところです。Scratch 自体が学習用なので、その目的に沿っているかどうかは分からないのですが、まぁ、ちょっとばかし無茶をやって業務で使ってみるのもアリかなぁと。「Scratch はプログラム言語なのか?」という質問が多い中で、じゃあ、実用的な業務で使うためにはこんなパターンがあるという例です。

適当な MDA ツールとして使う

ブロックを組み合わせてロジックを作る言語(ビジュアル言語とかブロックプログラミングとか)は、Scratch の他にどんなものがあるのか?というと、

なんてのがあります。この中に UML を含めてもいいかもしれません。ブロックを組み合わせて細かいロジック(加算や減算など)を組むものもあれば、ある程度コンポーネント化されたものを呼び出す MDA(モデル駆動型アーキテクチャ)的なものもあります。

Scratch の場合は、細かいロジックを組む所謂プログラム言語に属する訳ですが、手順を繋げたり条件分岐をうまく使えば MDA なツールとしても使える…と思ってみるわけです。

試してみるのは、

  • 適当な Web API を複数回呼び出す
  • Web API の戻り値で適当に分岐する
  • Web API の戻り値で適当に猫が喋る

あたりを想定して作っていきます。
テストデータの投入を自動化するとか、サンプルデータの投入あたりを考えてみます。

下準備

まずは、ローカル環境で Scratch 3.0 が動く環境を整えます。Linux 環境でやるのが望ましいのですが、Windows の WSL を使っても大丈夫です。というか、VSCode を使うと便利なので、WSL がお薦めです。

github からコードをダウンロード



$ git clone --depth 1 https://github.com/llk/scratch-vm.git $ git clone --depth 1 https://github.com/llk/scratch-gui.git

ビルド



$ cd scratch-vm $ npm i $ sudo npm link $ cd ../scratch-gui $ npm i $ sudo npm link scratch-vm

scratch-vm に拡張機能を使って、scratch-gui で UI を動かします。scratch-gui は React が使われているので、scratch-vm 内のコードを修正すると自動的にブラウザのほうでリロードが掛かります。

試しに実行

ローカル環境で http://localhost:8601/ とすれば、ブラウザで Scratch 3.0 が動く状態になります。



$ cd scratch-gui $ npm start


この状態で、ほぼ https://scratch.mit.edu/ と同じ状態になります。違いは、

  • 共有ができない
  • サーバーにコードが自動保存されない。

ことぐらいです。

ローカル環境では、「ファイル」メニューからローカルのコンピュータにコードを保存できます。この保存したファイルを本家の Scratch にアップロードすれば共有が可能になります。

ただし、今回のようなオリジナルな拡張ブロックを使っている場合は本家では動かないので、適宜ローカル環境で動かすか、社内で適当なサーバーを立てて(ラズパイ3とかでも十分です)そこにアクセスするか、という形になります。

多分、ラズパイ上に Scratch 3.0 のサーバーを立てて、そこから Arduino に接続させるとか、センサーのデータを読み取るとかするほうが PC よりも手軽かもしれません。そのあたりはおいおい模索していきます。

リモート環境で VSCode を動かす

WSL(Windows System Linux)にはリモート接続対応の VScode をインストールできます。



$ code .

WSL 上でこんな風に code コマンドを入れると、自動的に Windows 側で VSCode が立ち上がってくれます。

ドライブが共有になっているので、Windows 側で閲覧してもよいのですが、WSL 側とファイル競合が発生してまうので、リモート接続にします。ここで *.js のファイルを編集して保存すると自動的にブラウザのほうでリロードが掛かります。

scratch-vm の編集

拡張機能を「webapisample」にして作成していきます。



$ mkdir scratch-vm/src/extensions/scratch3_webapisample/ $ touch scratch-vm/src/extensions/scratch3_webapisample/index.js

scratch-vm/src/extensions フォルダーの中に、新しく「webapisample」フォルダーを作って index.js ファイルを作成します。



const ArgumentType = require('../../extension-support/argument-type'); const BlockType = require('../../extension-support/block-type'); const Cast = require('../../util/cast'); const log = require('../../util/log'); class Scratch3WebApiSample { constructor (runtime) { this.runtime = runtime; this._result = "" ; this._url = ""; this._result = ""; } getInfo () { return { id: 'webapisample', name: 'Web API Sample', blocks: [ { opcode: 'setUrl', blockType: BlockType.COMMAND, text: 'Set URL [TEXT]', arguments: { TEXT: { type: ArgumentType.STRING, defaultValue: "http://localhost:5000/api/Hello/" } } }, { opcode: 'getUrl', blockType: BlockType.REPORTER, text: 'URL' }, { opcode: 'getResult', blockType: BlockType.REPORTER, text: 'result' }, { opcode: 'callWebApiByGet', blockType: BlockType.REPORTER, text: 'Call Web API GET [TEXT]', arguments: { TEXT: { type: ArgumentType.STRING, defaultValue: "100" } } } ], menus: { } }; } setUrl( args ) { const text = Cast.toString(args.TEXT); this._url = text ; } getUrl() { return this._url ; } getResult() { return this._result ; } callWebApiByGet(args) { const text = Cast.toString(args.TEXT); const path = this._url + text ; var pr = fetch( path ) .then( res => res.text() ) .then( body => this._result = body ) ; return pr ; } } module.exports = Scratch3WebApiSample;

少し癖があるのですが、

  • getInfo 関数で、ブロックの情報を返す
  • opcode に対応する関数名を記述する
  • それぞれの関数内で Javascript で記述する

ブロックの種類にはいくつかあるのですが、

  • BlockType.COMMAND : コマンドブロック(非同期)
  • BlockType.REPORTER : 値ブロック(同期処理)

になります。Web API呼び出しでは、fetch を使うのですが、ここをコマンドブロックにすると戻り値が取れません。なので、値ブロックにして同期的に処理を行います。戻り値は fetch が返す Promise 型を使えば ok です。

Scratch 3.0の拡張機能を作ってみよう/応用 – Japanese Scratch-Wiki を参考にしてください。


   callWebApiByGet(args) {
        const text = Cast.toString(args.TEXT);
        const path = this._url + text ;
        var pr = fetch( path ) 
            .then( res => res.text() )
            .then( body => this._result = body ) ;
        return pr ;
    }

ここでは4つのブロックを作っていて、こんな感じになります。

Web API を実行する http://localhost:5000/api/Hello/ は後で、ASP.NET Core MVC で作ります。ここの呼び先は、PHP で作ってもいいし、nodejs でもいいし、Azure Functions でも構いません。

クラス内の変数の扱いは、JS なのでそれに則ります。このあたり、コード自体は Javascript なので、結構いろいろなことができます。

scratch-vm/src/extension-support/extension-manager.js のファイルに、拡張機能をインクルードするための行を追加しておきます。以下の「★」の部分です。



const builtinExtensions = { // This is an example that isn't loaded with the other core blocks, // but serves as a reference for loading core blocks as extensions. coreExample: () => require('../blocks/scratch3_core_example'), // These are the non-core built-in extensions. pen: () => require('../extensions/scratch3_pen'), wedo2: () => require('../extensions/scratch3_wedo2'), music: () => require('../extensions/scratch3_music'), microbit: () => require('../extensions/scratch3_microbit'), text2speech: () => require('../extensions/scratch3_text2speech'), translate: () => require('../extensions/scratch3_translate'), videoSensing: () => require('../extensions/scratch3_video_sensing'), ev3: () => require('../extensions/scratch3_ev3'), makeymakey: () => require('../extensions/scratch3_makeymakey'), boost: () => require('../extensions/scratch3_boost'), gdxfor: () => require('../extensions/scratch3_gdx_for'), webapisample: () => require('../extensions/scratch3_webapisample') // ★ };

最終的には id を使ったりするのでしょうが、いまはこのままで。

vscode でファイル保存して特にエラーが出なければ ok です。

scratch-gui の編集

scratch-gui では拡張機能を読み取るところを追加します。



$ mkdir scratch-gui/src/lib/libraries/extensions/webapisample

webapisample このフォルダーに2つの画像ファイルを置きます。

  • webapi.png
  • webapi-small.png

拡張機能を読み込むときに使われる画像ですね。面倒ななので字だけです(苦笑)。

scratch-gui/src/lib/libraries/extensions/index.jsx 追加の設定を記述します。



import webapisampleIconURL from './webapisample/webapi.png'; import webapisampleInsetIconURL from './webapisample/webapi-small.png'; // 省略 { name: "Web API Sample Blocks", extensionId: 'webapisample', iconURL: webapisampleIconURL, insetIconURL: webapisampleInsetIconURL, collaborator: 'moonmile', description: "You can call Web API.", featured: true, internetConnectionRequired: true, helpLink: 'http://moonmile.net/' } }

最初の import はアイコンを指定しているだけなので、直に iconURL や insetIconURL に指定してもよいでしょう。多言語化しないので、FormattedMessage を使わずに直書きしています。

ファイルを保存して、Scratch 3.0 側で拡張機能を読み込むと、オリジナルのブロックが現れます。Javascript のコードが間違っていたり、ブロックの opcode などの設定が間違っていると、拡張ブロックの部分が読み込めないので注意してください。

読み込めなかったときのデバッグ手段がないので、ちょっとずつブロックを増やしていくのがコツです。

Web API を作る

.NET Core を使ってテスト用の Web API サーバーを作ります。



$ dotnet new webapi -n hello

こんな風に hello プロジェクトを作った後に、Controllers/HelloController.cs を追加します。



using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; namespace hello.Controllers { [Route("api/[controller]")] [ApiController] public class HelloController : ControllerBase { // GET api/values/5 [HttpGet("{id}")] public ActionResult<string> Get(int id) { var text = "Hello api {id}"; System.Diagnostics.Debug.WriteLine(text); return text; } } }

数値の id を渡されたら「Hello api 100」のように返すだけの GET メソッドです。本来ならば、データベース検索をしてデータを返すところです。ASP.NET MVC の Web API は自動で JSON 形式で返すのですが、ひとまずこのままにしておきます。

もう一つ、XSS 対応をしておきます。Scratch 3.0 では http://localhost:8601/ で動くのですが、作成する Web API は http://localhost:5000/ で動くことになります。なので、クロスサイトスクリプトの実行状態になり、そのままでは次のようなエラーがでます。これは Chrome の F12 でエラー表示をしたところです。

この対策のために、Web API 側で CORS 対策をします。
Microsoft.AspNetCore.Cors パッケージを dotnet コマンドで入れた後に、



dotnet add package Microsoft.AspNetCore.Cors

Startup.cs に次の2行を追加します。



using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.HttpsPolicy; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace hello { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddCors(); // CORS 追加 services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseCors(o => o.AllowAnyOrigin()); // CORS 追加 app.UseHttpsRedirection(); app.UseMvc(); } } }

これで先のエラーがなくなります。dotnet run で Web API サーバーを動かしたあとに、ブラウザで http://localhost:5000/api/Hello/100 のように確認してみてください。

実行してみる

Scratch 3.0 と Web API サーバーを起動した状態で、次のようにブロックを組んでみます。

猫スプライトをクリックすると、「カウンタ」が+1されて、Web API が呼び出されます。Web API は同期的に呼び出されるので、戻り値が「結果」に入って、猫が喋る、という簡単なものです。

内部的にはちょっと複雑な(とはいえ、Web APIを呼び出しているだけだけど)ことになっていますが、表面的にはカウンタを使って何かの「結果」を取ってきているだけです。

実際、猫をクリックすると結果がカウントアップされていくのが分かります。きちんとデータベース検索をしてやれば、IDなどを渡して Web API 経由でデータを引き出すこともできます。

今後は

fetch を使って Web API を順次呼び出せることが分かったので、

  • CRUD を揃えて、RESTful な Web API にしておく。
  • データベース検索をする
  • やり取りを JSON 形式にして、プロパティの受け渡しができるようにする

を引き続き後日。

カテゴリー: 開発 | Scratch 3.0 で Web API 呼び出しの拡張ブロックを作る、の手始め はコメントを受け付けていません

マッチ棒とゴムのトリックの問題

下記のツイートをみて、ちょうど力学の解説によいと思ったのが落とし穴であった。ので、きちんとした解答を書き直し

を見て思いついたのが、支点の移動の話で、下記な図を描いたのだが、これは間違い。

image

さきについていた、

先進科学塾@名大「遊びで探る重心の世界」2017.10.22 | ひろじの物理ブログ ミオくんとなんでも科学探究隊 https://ameblo.jp/hamgon1971/entry-12321955194.html

の補足で作ったつもりだったのだけど、上の図じゃなくて、こんな感じになる。

石で支えているときは、左のように重心が支点外側にあって力点を掛けてペットボトルを支えている。このまま石を外すと、作用点だけが残るのでペットボトルが落ちる。

ここでマッチを使って左のように重心が支点の下に来るようにずらす。そうすると、支点の直下に重心が来る(支点自体が作用点である重心を支えるようになり、作用点=力点が等しくなる)、これによって、石がなくてもペットボトルは落ちずに支えられる、という仕組み

image

マッチの動画で「不思議」に見えるのは、ここの重心のずれ(支点への移動)がさりげなく行われるので、同じ格好でもペットボトルは落ちないという不思議さがうまれるのがミソ。

だから、極端な感じで先のブログにもあるように「指一本」で支えることも可能で、あらかじめ水色のマッチ棒の部分が固定化されていれば、一点で支えられる。

image

マッチ棒とゴムでは難しいので、実際に割りばしとビニール紐でやるとこんな感じになる。テーブルの上が平たいので左に落ちないので、やや浮いた形でバランスが取れる。下にぶらさがっている Linux ペンギンはちょうどテーブルの縁の真下に来る。

image

何処で勘違いしたのだろう

ミスリードになったところは、この部分で。

image image

こんな風に取っ手のついた傘の動きを考える。

この場合、支点は傘の柄の先にあって無理矢理上から押さえつけて、傘の開くところを支えてまっすぐにしている。

これを手を離すと、傘の棒の部分が内側にずれて、重心が移動し支点の真下に来る、

image

ここに話を結び付けたかったのだけど、実は違ったということ。実は支点の先に(左側)に棒が続くかどうかの違いなんだけど、そこに引っかかってしまった、というか墓穴を掘った。うーむ。

材料工学的には片持ち梁の問題

この支点の問題なんだけど、材料工学では典型的な「片持ち梁」の問題だったりする。

片持ち梁とは?1分でわかる構造、様々な荷重による応力と例題 http://kentiku-kouzou.jp/struc-katamotiharitoha.html#targetText=%E7%89%87%E6%8C%81%E3%81%A1%E6%A2%81%E3%81%AF%E3%80%81%EF%BC%91,%E8%87%AA%E7%94%B1%E3%81%AB%E3%81%97%E3%81%9F%E6%A2%81%E3%81%A7%E3%81%99%E3%80%82

片持ち梁の場合、一方が固定点で片方が自由点。自由点のほうに何かをぶら下げると、応力かかるという問題。先のマッチ棒と傘の重心移動は、もういっぽうも自由点なのだが、ちょうどその中間を考えるとこんな図になる。

片持ち梁は壁に固定する(壁自体が剛体だから)のだが、釘みたいに壁に打ち込むタイプはこんな感じに力が働く。釘の上としたに力が働くわけで、接着剤の場合は下の面積(はがれる)が問題だし、コンクリート打ち込みの場合は上の力が問題(上がひび割れる)になる。

image

また、中間となる支点に大きな力が掛かるので、ここがひび割れる。支点のひび割れに対しては力を分散するために梁を使うか、R を付ける。この R 部分がおもしろくて、こんな風に黄色の部分を余分につける。

image

片持ち梁でもそうなんだが、この直角の部分の角には応力集中が働くので R を付けて応力分散をする、さらに支えともなる。という面白い特性がでてくる。

さらに先の「量産~」でツインドリル制作の時に聞いたのだけど、プラモデルのような場合でも同じように応力集中が掛かるので、こわれないように R を付ける。この R は、さきの棚のような場合には後付けになるのだが、プラモデルの型抜きのようなものは、金型のほうを「削る」という後から加工でいけるという特性がある。金属の型って、一発でできることは少なくて、少しずつ削っていくのだが、

  • 金属の型のほうを削ると、材料のほうの厚みが増して強度があがる(安全性があがる)
  • 最初は直角であっても R を付けるときは、金属の型を削るだけなので、修正が簡単。

という加工工程としても、後から修正するほうが「安全に倒れる」という興味深い話があるので、そのあたり支点の移動とか応力の分散とかの話に繋げたかったというのがあるわけで。

このあたり、物理屋さんとしては、

  • 思考実験をして仮説を出す
  • 仮説を確認/証明するために実際の実験をする
  • 実験が仮説と違っていたら、仮説を疑う(物理法則は変わらない)

を繰り返す。

これはプログラムのバグ取りとか性能検証とかも同じで、ある程度仮説出して進める。実測データがいくつか取れるが、それが仮説とあっているか検証する。たまに仮説とあっていない場合(思うように性能があがらないとか、本来のバグとは違った箇所を直しているとか)があるので、無理に仮説に合わせようとしないで、一度保留にして仮説に立ち返る、というループになる、という話,

を忘れがちになるので忘備録としてメモしておく。

カテゴリー: 雑談 | マッチ棒とゴムのトリックの問題 はコメントを受け付けていません

Windows 7 で Scratch から micro:bit を扱えるようにする

学童のプログラミング教室で、Minecraft on Scratch から子供の興味を引きはがすべく、micro:bit を 5個(増税前、消費税8%の駆け込み)購入しました。

実はスイッチサイエンスさんはキャッシュレス還元に対応したそうなので、10/1 以降に購入したほうがお得だったわけですが。まあ、いいや、勢いで送料無料になる1万円まで大人買いです。

※ああ、結果だけ欲しい方は、一番最後にジャンプするといいです.

学童で子どもに試してみる

プログラミング教室をやっている学童に先に請求してもよいのですが、ここは実験も兼ねて自腹で購入。うまくいけば後で、欲しい子には2,000円也で購入してもらうか、学童に請求を上げるかというところなのですが。

あえなく「玉砕」です。

まず、数あるプログラミング教室の中で、私が行っているところは、

  • 小学3-6年生が10人ちょい雑多に集まっている感じ。
  • 予算の関係上、中古 ノート PC の Windows 7 を使っている。
  • 場所が共有スペースを使っているので、デスクトップ PC は置けない。
  • 有線 LAN が使えず、無線 LAN(私物の Pocket WiFi)を使っている。
  • ノート PC に Bluetooth が付随していないものが多い。
  • 中古のノートPCなので、USB が 1個しか生きていないものが多くて、USB ケーブルのマウスと付け替えないといけない。
  • そもそも、micro:bit(mbed) への HEX ファイルのドラッグ&ドロップが子供には難しい。

このプログラミング教室は、3年前から始めたのですが、プログラミングを教える…ってのは雑多な環境では難しかったので、「Scratch で遊ぶ」にシフトしました。いは、Scratch で作られているゲームならば、なんでも ok ってことで、ファミスタもどきとか青鬼もどきとか、いろいろ流行りがあって、今はマインクラフトもどきなのです。
ちなみに、ゲームばかりやっている子ばかりではなくて、Scratch でゲームを自作している子もいます。

  • ゲームを自作している子には、適宜質問に答える&適宜手伝う。
  • ゲームをしている子は、攻略法は友達同士で話し合ってね

というルールでやっています。学童の目的として「安全に子供を預かる」が有線なので、プログラム自体を教えるってのは二の次なのです。とはいえ、漠然と遊ばせるだけはつまらないので、毎回プリントを配るし(1回300円也を徴収しているので)、それなりに「パソコンに慣れる」ことを目的としています。

と、いう状況はさておき、プログラミング環境としてはあまりリッチな環境ではありませんが、そこは工夫次第というところです。

Scratch から micro:bit を操作する

micro:bit を操作する方法は2種類あります。

MakeCode を使ってプログラミング

https://makecode.microbit.org/

こんな感じでブロックを使ってプログラムをして、micro:bit に流し込みます。ダウンロードした後に HEX ファイルをドラッグ&ドロップする方法と、あらかじめ micro:bit とリンク(たぶん、BLEを使っている)させておいて「ダウンロード」ボタンを押したら直接流し込んでくれる方法です。

手元の PC でやると、この自動流し込みが便利なので操作的にはさほど気にならないのですが。Bluetooth の付いてないデスクトップPCとか、古い Windows 7 のノートPCだと結構な手間です。

あと、Scratch に慣れていると、この

  • プログラムをコンパイルして、マイコン(micro:bit)に流し込む

という流れが難しかったりします。そのあたりは、電子工作で Arduino を使っていれば慣れるので(というか慣れないといけない)ので、それはいずれやるつもり。

Scratch 3.0 から直接 micro:bit を操作

https://scratch.mit.edu/

もうひとつ、Scratch 3.0 の拡張機能を使う方法です。Scratch 3.0 では、あらかじめ micro:bit に scratch-microbit-1.1.0.hex なファームを書き込んでおいて、BLE 通信をしながら操作する方法です。これだと、いちいち micro:bit に書き込む必要がなくて、Scratch の操作だけで micro:bit を扱えます。

micro:bit と BLE 通信で連携をするので、

  • micro:bit のAボタンを押したら、猫に喋らせる
  • Scratch 猫をクリックしたら、micro:bit の LED を光らせる

という動きが簡単にできます。これだと、物理的なものを「プログラミングで操作する」というのが直感的にわかっていいです。内部は、ややこしいことになっているのですが。

Scratch で micro:bit を操作するためには、条件があって、

  • BLE 接続できること
  • Scratch Link を動かしておくこと

があります。micro:bit と BLE 通信をするので、Buetooth が必要なのはいいのですが、さて、Scratch Link がちょっと癖ものなのです。
Scratch Link の動作条件が、

  • Windows 10 以降
  • macOS

ということになっていて、Windows 7 では動かない。何故?ってことになります。

scratch-link
https://github.com/LLK/scratch-link

理由は、Scratch Link のコードを見るとわかります。Windows の場合、UWP で使われている Bluetooth モジュールを使っていて、これが Windows 10 以降しか入っていないんですよね。Windows 8 が出た頃に、BLE 通信が流行った時代があって、そのときに Windows 7 で動かそうとして悪戦苦闘した覚えがあります。結局 BLE 通信は無理なので Bluetooth のシリアル通信にしましたが。実は、Scratch Link 内部ではシリアル通信も対応しているのですが、インストール環境が Windows 10 以降になってしまっているので、これでも Winodws 7 は使えないのです。まあ、そのときは自前ビルドをするわけですが。

Scrach 3.0 のコードは Github で公開されているので、

の3つから調べることができます。scratch-microbit-1.1.0.hex のコードは見つからなかったのですが、まあ、これは BLE のペリフェラルなところなので省略してもokでしょう。

ざっと、調べたところこんな感じです。



Scratch on Browser WebSocket ^ | JSON-RPC v WebSocketServer JSONRPCWebSocket + didReceiveCall Scratch Link BLESession + DidReceiveCall + OnValueChanged ^ | BLE GATT v BLE micro:bit
  • Scratch 3.0 で WebSocket を使っている
  • Scratch Link は WebSocketServer で待ち受け
  • Scratch 3.0 – Scratch Link の間は JSON-RPC で通信
  • Scratch Link と micro:bit は BLESession で BLE 通信

そうなると、Scratch Link の JSON-RPC で受けているところを適当に WiFi に切り替えてやって、ラズパイや適当な Windows 10 を挟み込んだプロキシを作ればいけそうですね。

と思って、Scratch Link のコードを .NET Core で書き換えようとしたところ、Scratch 3.0 -> Scratch Link な URL ってどうなっているのか?と思い至りました。いやいや、WebSocket を使ったことがなかったので。

Scratch Link – Japanese Scratch-Wiki

を改めてみると、『そのため、Scratchはlocalhostに直接アクセスできないため、device-manager.scratch.mit.eduに接続する。』という一文があります。たしかに、scratch-vm のコードを検索すると、この URL が書いてあって、直接ローカルなPC(localhost とか 127.0.0.1 とか)には接続していないんですね。

なるほど!WebSocket って localhost が使えないのか!ってことでした。
思い込みで、localhost しか使えないのかと思っていたのですが、実は localhost「は」使えないという落とし穴が(苦笑)あったのですね。
なので、Scratch 3.0 は、拡張機能で WebSocket を使うたびに device-manager.scratch.mit.edu を呼び出して DNS で 127.0.0.1 を返して貰っています。

hosts を変更する

となれば、話は簡単です。
いちいち、ローカルホストに接続するために device-manager.scratch.mit.edu を呼び出しているということは、他の PC を呼び出したい場合は device-manager.scratch.mit.edu を通す必要がない、ということです。

なので、実現したい環境として、

  • Scratch 3.0 が動いている Windows 7
  • micro:bit と接続している BLE ありの Windows 10

という別々の環境を作った場合、Windows 7 から Windows 10 の Scratch Link への通信に切り替えてやればよいわけで、

  • Windows ならば、C:\Windows\System32\drivers\etc\hosts
  • Linux ならば /etc/hosts

を書き加えます。



192.168.1.28 device-manager.scratch.mit.edu

「192.168.1.28」なところは、Windows 10 のある PC の IP に書き換えてください。こうすることで、device-manager.scratch.mit.edu への呼び出しが偽装されて、micro:bit に繋がっている Scratch Link(Windows 10 あるいは macOS) へ接続されます。

2以上繋がっている場合は、こんな風に並ぶので名前で使い分ければよいでしょう。

scratch-vm のほうを書き換える

なお、もう一つの方は、scratch-vm にある WebScoket の接続先を書き換えます。

scratch-vm/scratch-link-websocket.js at develop · LLK/scratch-vm

scrach-gui/vm/link をあれこれやっているのは、自前でオリジナルなブロックを創ったり、Android の Firemate に繋げたりしたいので、こっちのほうはいずれ試してみる予定。

カテゴリー: 開発 | Windows 7 で Scratch から micro:bit を扱えるようにする はコメントを受け付けていません

Scratch から micro:bit を操作する Scratch Link を自前ビルドする

マインクラフト on Scratch から子供たちを脱却すべく(別に脱却する必要もないのだけど)、micro:bit を5個購入しました。

なんで5個なのかというと、スイッチサイエンスさんで10,000円以上だと送料が無料になるからです。消費税8%のうちの駆け込み需要かと思いきや、スイッチサイエンスさんは実はキャッシュレスの軽減税の対象になったそうなので、どちらが安いのか分からないのですが。まあ、5個購入しました。

左に移っているのは chibi:bit で、以前購入したものです。確か、猫ボードあたりと揉めたときに記念に買ったものです。まだ、micro:bit に BLE が技適が通っていなくて Bluetooth のチップを独自で乗せて独自に技適を通したもの…だったハズです。実は、本国(英国)から送って貰ったものが手元にあるはずなのですが、行方不明で。

それはさておき、micro:bit を使います。

micro:bit をブロックプログラミングする

プログラムしましょう | micro:bit

micro:bit は Scratch のようにブロックプログラミングができます。内部は Google の Blockly がベースになっていて Microsoft が開発というハイブリッドな環境が話題になりました。

ここのサイトは、micro:bit の mbed な機能を使って、USB 接続したドライブに HEX ファイルを落とし込むという方法でプログラムを変更します。Arduino IDE や mbed を使っていると、なじみのある方法です。

実は、ブロックだけじゃなくて、Python や JavaScript も使えるので、キータイプをしたい場合にはこっちのほうを使うといいかもしれませんね。特に JavaScript のほうはブロックにしてから JavaScript のコードを表示できるので、コードの比較ができて便利です。

Scratch から micro:bit を操作する

もうひとつのほうは、Scratch の拡張機能を使って micro:bit に Bluetooth 接続をする方法です。

動作環境が、

  • Windows 10 あるいは macOS であること
  • Windows 10 側に Scratch Link が動作していること

と若干敷居が高いのですが、micro:bit が Bluetooth 接続できます。micro:bit にはあらかじめ、”Scratch micro:bit HEX” をインストールしておいて、Scratch Link 経由で micro:bit に接続します。HEX ファイルは Scratch – micro:bit でダウンロードができます。ちなみに、chibi:bit のほうは、https://t.co/KiQDkQIgw3 からダウンロードが可能です。

Scratch 側で micro:bit のブロックを作って、micro:bit のボタンや加速度センサーによって、Scratch 側で動きを制御できます。

このあたりは、micro:bit サイトの MakeCode よりも試行錯誤ができて便利です。

?

仕組みはどうなっているのか?

さて、ここまできたら、どういう動作になっているのか?できれは自作でハックをしてみたいのがプログラマの性です。いずれは、Scratch 3.0 のほうに独自の拡張ブロックを入れて、ということも視野にいれて、

を参考にして、独自の Scratch 3.0 環境を作ります。
Ubuntu on Windows を立ち上げて、以下でインストールします。



$ git clone --depth 1 https://github.com/llk/scratch-vm.git 
$ git clone --depth 1 https://github.com/llk/scratch-gui.git

後は、ビルド


$ cd scratch-vm 
$ npm i 
$ npm link 
$ cd ../scratch-gui 
$ npm i 
$ npm link scratch-vm

あとは、npm start すれば、http://localhost:8601/ で接続できるようになります。


$ cd scratch-gui 
$ npm start


micro:bit 拡張機能のコードは以下にあります。



scratch-vm/src/extensions/scratch3_microbit/index.js

接続方法として

Scratch 3.0 <=> Scratch Link <=> micro:bit

になるわけですが、

  • Scratch 3.0 と Scratch Link の間は、JSON
  • Scratch Link と micro:bit の間は BLE

です。
拡張機能を自作したい場合は、JSON のところをフックすればよいので、適当な拡張機能をコピーすればなんとかできそう。

BLE 通信のほうは、実は Scratch Link は以下で公開されています。

LLK/scratch-link at master

このコードを改変してビルドをすれば、独自に BLE をフックできるハズです。
ざっと中身をみてみると、UWP の BLE を使っていて GATT で通信させています。GATT を使っているので、Windows 7 とかでは動かないわけです。
現状はラズパイでは動かないようですが、macOS のコード(swiftだけど)をうまく修正すれば、macOS 以外でも動くかもしれません。

自前の Scratch Link をビルドするには、ちょっとコツがあります。というか、対象の開発環境が古いみたいで Visual Studio 2019 ではビルドができません。
.NET Framework のバージョンを最新(v4.7.2)に上げた後に、エディタで以下の修正をします。

Windows/scratch-link/ScratchLink.csproj

  • Windows.winmd ファイルの参照先を自前のものに変えておく。

- <hintpath>C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.16299.0\Windows.winmd</hintpath>
+ <hintpath>C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.18362.0\Windows.winmd</hintpath>

最後の scratchVersion.targets を削除する



- <import project="..\scratchVersion.targets">

本来は、scratchVersion.targets の git あたりを修正するのがよいのですが、ひとまず参照自体を削除。バージョンが 0.0.0.0 になるので、ちょっとまずいのですが。

この修正が終わると、無事ビルドが通って

  • 自前の Scratch 3.0(scratch-gui, scratch-vm)を起動
  • 自前の Scratch Link を起動
  • micro:bit に BLE 接続する

ことができます。

カテゴリー: 開発, Scratch | Scratch から micro:bit を操作する Scratch Link を自前ビルドする はコメントを受け付けていません

掌握術のコールド・リーディングの話を少し

プログラミングは技術的な側面を押し出す理系的な面が多いけれど(この「理系」もかなり語弊があるが)、なにかと政治的な面に首を突っ込まないといけないことが多い…と言いますか、政治的な話でプロジェクトが潰されて現場のプログラマが被害を被るということが多々あります。

実は、アジャイル関係の教本には「政治的なことは別なところで解決してくれ」とはじめにと書いてることもあり、政治的な話を避ける傾向があります。が、ケント・ベック氏が10数年前に来日時に話していた通り「私たちの頃は、社会不適合者がプログラミングをしていたが、これからは社会的なコミュニケーションが重要視されると思う。娘の姿をみているとそう思う」なのです。ときに、XP がペアプログラミングで相互コミュニケーションを重要視したように、何かを技術的な側面だけで解決できるとは限らない、ということです。まあ、私自身も、いまとなっては「古い人間」なので、政治的な問題は苦手なところが多くできるだけ避けてはいるのですが、そのあたりは、技術者らしく政治的なものも技術的側面で解決するという脇道も考えるのです。

さて、某K議員の発言もあり、政治的な発言が「空疎」であると同時に、なにか深い意味がありそうなという「深読み」をする面もあり、いったいどちらなのだろうか?と思うところもあるでしょう。そのあたりの結論は脇に置いて(その問題は私の関知するところではないので)、もっと某K議員の天然ではないところに注目してみます。

目の前の人の共感を得る方法

会話というものが、瞬時的に1対1で行われる以上、相手からの好意を引き出すというのは円滑なコミュニケーションをする上で重要なことです。円滑なという言葉を使いましたが、狡猾なという言い方に変えても同じです。要は、相手に嫌悪感を与え防壁を作るよりも、うまく壁を取り除き(自分の壁は置いたままで)、自分の言葉刷り込ませるというテクニックを使います。

相手が好意を持つ(嫌悪感を持たない)ようにさせるためには、「あなたのことは特別です」という意図を伝えるのがベターです。一般的には、相手の目を見て会話する、という方法がとられますが、複数名に話しかけると同時にひとりに話しかけるということも可能です。

  • 会話をするときに、数秒間だけ相手のほうに顔を向ける
    → いわゆる、アイドルを見て「私だけを向いた!」という奴ですね。
  • 事前に調べた、その人しか分からない(と思われる)情報ををチラ見させる。
    → あなたのことを知ってますという方法
  • 会話の中で知った、その人の言葉を使う
    → あたなの言葉を私はきちんと聞いていますというアピール

人間も動物なので、自分だけが特別が扱いされるとうれしいものです。「うれしい」=警戒心緩むということですね。警戒心が緩むと、相対的に猜疑心が減るので、心の隙間に入りやすくなります。

ただし、よく営業トークである、相手に YES で同意するというのは、以前はよかったのかもしれませんが、最近は「胡散臭いやつ」や「なんでも YES と言えばいいと思っている奴」に見えるので、やめたほうがベターです。だんだん、人々は賢くなってきていますからね。優しい雰囲気は、老人にはいいのかもしれませんが。

この好意を与える方法の逆を取って、嫌悪感を与えるという方法も使えます。いわゆる、スケープゴート(生贄)をグループの中に作って、スケープゴート以外で団結させるという技ですね。先の好意を寄せるこの逆をすれば、グループの中に生贄を作れます。

  • その人からの質問をはぐらかして、他の人の質問を受け取る。
  • その人からの意見を取り上げた上で、別の人の意見に同意する。

これは某都知事がやっている方法で、たぶん無意識でやっています。この手の会話術は無意識でできる人(おそらく育ちだと思う)と、無意識ではできない人がいます。結果的には、無意識でできる人が、政治家向きなのですが(心理的なストレスが少ないので)、これを意識的にやる(会話をしているときに、裏で二重に会話を構成する)人は、政治家以外にもちらほらといるので注意が必要です。

相手の情報を事前チェックする

昔(30年前位だろうか)の営業としては、事前チェックは当たり前のことだったし、必須であったと思うのですが今はどうなんでしょう?昔はインターネットがなかったので、相手の情報を内密で得るのはなかなか困難でした。新聞なり図書なりを利用したり、事前に廻りの人に聞いたりするしかなかた訳で、コールド・リーディング(事前に知った相手の情報を利用する)の手法は占い師の秘匿の手段でもありました。

ただし、今だと事前に相手の情報を得るのは結構簡単です。

  • Google で相手の名前を検索する
  • Google で相手の会社を検索する、地図を見ておく
  • 商品情報や研究内容を検索する
  • 類似品の情報を検索する
  • 技術要素の用語を検索しておく

のように、相手の名前や社名で検索すれば結構でてきます。これは完全に事前ではなくても、会議中のトイレの中でも検索できるわけで、相手にとって「よく知っている人」に見えるようになります。つまり、警戒心を下げられるわけです。

私の場合はあまり得意ではないのですが、相手の会社の地図から、食べ物情報を検索して「あの店はおいしいですよね」と雑談するのもよい方法です。ええ、やる過ぎると胡散臭くみられるので、注意が必要ですが。

会話中に相手の情報を利用する

もうひとつの掌握術として、リアルタイムに会話をしているときに、相手の情報を使って相手の警戒心を下げるという方法もあります。ホット・リーディングと呼ばれますが、これも単なる会話術にひとつですね。

その場で知った相手の情報を活用するだけでなく、「相手に自分が何かを知っているように思わせる」という手法があります。これが冒頭に書いた、某K議員の話であって、

  • 何か言葉を使っているが「空疎」な言葉しか吐かなくて馬鹿なやつ
  • 何かグローバルな言葉を使って「意味深」な頭の切れるやつ

という感想が同居します。これ、同じ言葉を同じシチュエーションで使っても、受け取る側で二面的に取られるということです。そして注意したいのは、どちらも会話を発している本人とは関係ないところで起こる現象です。

image

さんざん、マスコミでの情報の切り取り問題が起こっているので、発言者から発せられた「発話A」が、それぞれの受け取り方で異なることが分かると思います。これは意図的な切り取りがなくても発生します。例えば、同じ会議室で、発言者が「発話A」を発したとしても、聞いている人が別であれば、別の発話を受け取ります(これ、音波的には同じもなのか?という問題もあるけど、まあ、音波であっても違いますよね)。

ただし、発話Aを受け取った人は、微妙に異なる「発話A’」と「発話A’’」を受け取りますが、この差異はあまり大きくありません。マスコミやツイッターなどの意図的な切り取りは別なのですが、同じ場所で同じ発言を聞いていれば、多少は差異はあるけれども、ほぼ同じものを着ている。あとから「発話A’」と「発話A’’」を比較しても「発話A」を再現できる程度に正確に聞き取れているでしょう。

しかし、これを理解するための「解釈」の段階になるとことなります。それぞれの「知識B」と「知識C」が大きく異なるため、理解するための「解釈 A’+B」と「解釈 A’’+C 」は異なる可能性が高いのです。これが同じ発言を聞いても「空疎」と「意味深」が同居する理由です。

まあ時には、「空疎」だけど「意味深」という形で同居する解釈もできるので、それは頭の中で「知識B」と「知識C」を切り替えて2つの解釈を割り出す方法です。

これを発言側から見れば、相手の知識Bと知識Cに向かって「解釈が異なる」ことを利用します。つまり、相手に「知識B」があると仮定したうえで、漠然とした発話Aを発します。知識Cの人にとっては訳がわからないのですが、あらかじ知識Bの人は「受け答え」をします。この受け答えを以って、相手が「知識B」をもっていることを発言者は知ることができるのです。この問答は、試験官と面接者の関係に似ています。異なるのは、発言者Aは、あらかじめ「知識B」の全体をしらなくても、それとなく知識Bが回答させられるように、発言Aを「漠然と」言うということです。そして、発言者Aは、まんまと知識Bの概要を得ることができます。

一見、ややこしいように見えますが、よく親が子供に対して「今日、何かあった?」という聞くよりも、「今日の国語のテストはどうだった?」とカマを掛けるのと同じです。国語のテストがなければ、子供は「国語のテストなんかないよ、何言ってんの」と言うでしょうが、ちょうど国語のテストがあれば、隠していたテストの結果を出してくるでしょう。親の側では、国語のテストがあってかどうかを知らずに、国語のテストの結果を得られます。

こんな感じなのが、ホット・リーディングの会話テクニックなのですが、このあたり先天的に(というか家系的に?)無意識でやっている人たちもいるので、対抗手段を講じるのは必要でしょう。私的には無意識でやっているのは進化論のひとつだと思うのですが、その話はまた別の機会に。

カテゴリー: 雑談 | 掌握術のコールド・リーディングの話を少し はコメントを受け付けていません