2021年6月30日水曜日

やっぱりPythonは気持ち悪い?

Googleのサーチコンソール,たまに覗くとときどき面白い気付きがある.私の名前やブログのタイトルである「飯尾研究室」で飛んでくる人たちの多くは,学生なんじゃないかと想像している.

まあ,それはそれとして,「オンラインと対面の併用」というトピックが人気である.これは,おそらく同業者諸氏であろう.「こうするといいよ!」というような情報提供をしていないので心苦しいところではあるが,皆さんお悩みの様子が伺える.オンライン講義に関する本を来月か再来月あたりに出版する予定なので,そちらも参考にしてください(と,さりげなく宣伝).

さて,今回ピックアップしたいのは,「Python 気持ち悪い」「Python 気持ち 悪い」というキーワードである(図).


「Pythonの三項演算子は気持ち悪い」という記事を以前に書いた.皆さんの検索にその記事ががヒットしているのだろう(それ以外にはあまりPythonが気持ち悪いという記事は書いていないので).

ここからは推測だが,Pythonの三項演算子が気持ち悪いと思って検索している人たちは少数派なのではないか.おそらくは,インデントでスコープを定義するそのことが「気持ち悪い」と思っているのではなかろうかと考える.そんなわけで,同志が多数いるようだということを(勝手に)確信して,安心した次第である.

2021年6月29日火曜日

可視化は楽しい

Google Fusion Tables(以下,GFT)のサービスが終了して久しいが,しばらくぶりにGoogle My Maps(以下,GMM)にアクセスしてみたら,どうも多少はGFTのコードがマージされたのか,GFTでできていたことがある程度はGMMでもできるようになっていた.

てなわけで,八王子市と進めている共同研究の件,とあるデータを頂いたのでさっそくマップしてみた.

色使いなど細かな調整ができないのが残念だが,やろうとしていることはそれなりにできる.これならデータ分析事例として学生に学ばせるのもちょうどいいサイズでもある.これからは,GMMを授業で紹介して使わせてみるかな.

さて,こんな画面を見てニヤニヤしているデータ分析オタクを,データサイエンティストと呼んでよいかどうか,それはまた別の問題か.

2021年6月28日月曜日

オンライン作文指導の可能性

長引くパンデミック対策も,だいぶ慣れてきたというか疲れてきたというか(どっちだよ!)もうどうしたもんかなという印象ではあるが,オンラインでもいろいろと工夫すれば学習効果を高めることはできるということが分かってきた.いま我々は,英作文の学習指導に関して,オンラインで効果がどれだけあったか,また,より効果的な指導方法は何かを確認する研究を進めている.

まだ分析中なのではっきりした結論を示すことはできないが,意義深い結果が見えてきているので,その一部を紹介したい.

次の図を見ていただきたい.これは,我々が開発して運用しているDialogbookというコミュニケーションツールを用いて実施した英語によるコミュニケーションの変化をみたものである.

具体的には,初回から3回分(A)と,最後までの3回分(B)のやりとりを対象として,データを分析したものだ.1回あたりのやり取りに含まれる語彙数(異なり単語数)を,1文あたりに正規化して比較したものである.1回・1学生を単位として,ヒストグラムを作成した.

青がA,緑がBである.見て明らかだとは思うが,メッセージのやりとりに含まれる語彙数が増えていることがわかるだろう.統計的に差があるかどうかを検定したところ,1%水準で有意差が示された.オンライン指導でもそれなりに学習効果はあったといえる.

現在,課題の提出状況とDialogbookによるコミュニケーションの比較など,本件に関しては多角的な考察を進めている.その結果は論文としてまとめて発表する予定である.

2021年6月26日土曜日

Neo4jとProlog

Neo4jをご存知だろうか.Neo4jとは,グラフデータベースと呼ばれる種類のデータベースで,データベースに格納される要素,および,要素と要素の関係を,それぞれグラフ理論でいうところのノードとエッジ(アーク)で表現できるというものである.

宣言型プログラミング言語としてのデータベース操作言語

2017年にSocioInfoというイベントでNeo4jに関する勉強会をした.ただし,そこは天邪鬼な私のこと,たんに勉強するだけじゃつまらない.Neo4jで定義されるデータって,それPrologでできるよと.そんな発表をしたのだ.

まあ,この発想は飯尾オリジナルというわけではない.宣言型プログラミングという大きな括りを考えたとき,その代表的事例がPrologであることは間違いないが,SQL,データベース操作の言語も宣言型プログラミング言語の範疇に入れられることがある.SQLを宣言型として扱ってよいなら,Neo4jだって同じようにできるよねえ.という単純な話.

その具体例

ではその実例をみてみよう.Neo4jのデモ,チュートリアルで挙げられている事例は「映画データベース」である.

データ定義のスクリプト(Cypherスクリプト)を読んでみる.

まず,映画(Movie)エントリとして,TheMatrix を作る(CREATE文).続いて人物(Person)として,キアヌやらキャリーやら,どんどん作っていこう.

ひと通り関係者のエントリができたら,関係をまとめて作る.いわく,「(Keanu)-[:ACTED_IN {...}]->(TheMatrix)」などを作っていく.すなわち,「キアヌ・リーブズはマトリックスに出演した」,「アンディ・ワショウスキーはマトリックスを監督した」などの情報を,関係として表現してデータベースに入れていくわけである.

あとは,ひたすらデータを定義していくというスクリプトである.これを,original.cypher というファイル名で保存する.

さて,このスクリプトをNeo4jのシステムに喰わせて「わーいグラフをぐりぐり動かせるぅ」とやるのも一興,ではあるが,天邪鬼氏はひと味違う.いきなり,次のワンライナーで,movie.pl なるPrologプログラムに変換してしまうのだ.

Prologプログラムへ変換

変換の実際は次のとおりである.

このワンライナーの詳細は省略する.※1の時点でスクリプトがどうなっているかというと,次のようになっている.

これは分かりやすいだろう.「(人物)→[関係]→(映画)」というように,関係性の一覧が出来上がっている.

Prologプログラムに変換するには,もうひと手間かける必要がある.この関係,「関係(人物,映画).」と表現を変換すれば,Prologでいうところの述語である.小文字で始めなければいけないなどの細かな文法に注意しつつ,機械的に変換した結果が movie.pl に記録される.

Prologによる探索

次のスライドで「昨日の問題」となっているのは,Neo4jの勉強会でその話題が出たからである.具体的には「TheMatrixを作ったディレクターが作成した映画は何があるか?」を検索せよという問題である.

これは,Neo4jの match コマンドを用いて調べることができる.そして,それはPrologでは「?-」から始まる文法で表現できる.

「?- directed(X, m_TheMatrix), directed(X, Y).」という問合せを行えば,Xにはマトリックスのディレクター,すなわち,p_AndyWとp_LanaWが単一化される.その後,directed(X, Y).の述語においてその両者を順にXに単一化したときに,Yに何があてはまるか?という話になるわけだ.

「write(Y), nl, fail.」はちょっとしたテクニックで,Yを出力して改行し,強制的にfailさせてバックトラック,次の解を探しにいくというプログラムとなる.

2021年6月25日金曜日

Ruby on Railsにおける多対多モデルの実装

学生が作らんとしているアプリ,入門書ではなかなか触れられていない際どいところに触れてきよったので,補講をした.以下はその記録から要点を抜粋したものである.

やりたいこと

学生たちは自分たちが授業評価をするアプリを作りたいそうだ.みんなのキャンパス学内版,みたいなものか.それでデータ構造を考えている.一人の学生は複数の授業を履修する.ひとつの授業は複数の学生が履修する.したがって,学生テーブルと授業テーブルを作ると,それは多対多の関係ということになる.

ER図はこんな感じ.

モデルの作成

さて,では必要なモデルを作っていこう.まず,学生モデル(Student)を次の操作で作る.

$ bin/rails g model student name:string sid:string

Running via Spring preloader in process 8711

      invoke  active_record

      create    db/migrate/20210625063116_create_students.rb

      create    app/models/student.rb

      invoke    test_unit

      create      test/models/student_test.rb

      create      test/fixtures/students.yml

$ bin/rails db:migrate

== 20210625063116 CreateStudents: migrating ===================================

-- create_table(:students)

   -> 0.0083s

== 20210625063116 CreateStudents: migrated (0.0085s) ==========================


$ 

次に,授業モデル(Lesson)も次の操作で作る.

$ bin/rails g model lesson name:string teacher:string room:string

Running via Spring preloader in process 8788

      invoke  active_record

      create    db/migrate/20210625063223_create_lessons.rb

      create    app/models/lesson.rb

      invoke    test_unit

      create      test/models/lesson_test.rb

      create      test/fixtures/lessons.yml

$ bin/rails db:migrate

== 20210625063223 CreateLessons: migrating ====================================

-- create_table(:lessons)

   -> 0.0052s

== 20210625063223 CreateLessons: migrated (0.0053s) ===========================


$ 

多対多の関係なので,間を取り持つ学生-授業モデル(StudentLesson)を作る.

これがなぜ必要になるのか,なかなか分かりにくいのだが,順繰りに解き明かしていくことにする.とりあえずは,次の操作で学生テーブルと授業テーブルを参照するモデルである StudentLesson を作る.

$ bin/rails g model student_lesson student:references lesson:references

Running via Spring preloader in process 8906

      invoke  active_record

      create    db/migrate/20210625063559_create_student_lessons.rb

      create    app/models/student_lesson.rb

      invoke    test_unit

      create      test/models/student_lesson_test.rb

      create      test/fixtures/student_lessons.yml

$ bin/rails db:migrate

== 20210625063559 CreateStudentLessons: migrating =============================

-- create_table(:student_lessons)

   -> 0.0133s

== 20210625063559 CreateStudentLessons: migrated (0.0133s) ====================


$

モデルクラスの修正

app/models/student_lesson.rb を見てみると,次のようになっている.

class StudentLesson < ApplicationRecord

  belongs_to :student

  belongs_to :lesson

end

学生と授業の間を取り持つクラスはそれぞれに belongs_to しているので,これはそのままこのとおりにしておけばよい.

app/models/student.rb はどうか.ここには,student_lessons を介してlessonsを持つよということを追記する.具体的には次に示す has_many 句の2行を追加する.

class Student < ApplicationRecord

  has_many :student_lessons

  has_many :lessons, through: :student_lessons

end

app/models/lesson.rb にも同様の修正を加える.

class Lesson < ApplicationRecord

  has_many :student_lessons

  has_many :studentsthrough:student_lessons

end


多対多関係の記述,その効果

このようにしておくと,次の操作が可能になる.ActiveRecord の威力を感じられたい.

まず,Studentをひとつ,作る.これを変数 s に入れる.

$ bin/rails c

Running via Spring preloader in process 9093

Loading development environment (Rails 6.1.4)

irb(main):001:0> s = Student.create(name: 'Jun IIO'sid: '21G0123456J')

  TRANSACTION (0.1ms)  BEGIN

  Student Create (5.7ms)  INSERT INTO "students" ("name", "sid", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["name", "Jun IIO"], ["sid", "21G0123456J"], ["created_at", "2021-06-25 06:44:17.699274"], ["updated_at", "2021-06-25 06:44:17.699274"]]

  TRANSACTION (6.1ms)  COMMIT

=> 

#<Student:0x00000001071e0d18

...

次に,Lessonもひとつ,作っておこう.これは変数 l に入れておく.

irb(main):002:0> l = Lesson.create(name: 'Programming I'teacher: 'Taro YAMADA'room: '301')

  TRANSACTION (0.1ms)  BEGIN

  Lesson Create (2.1ms)  INSERT INTO "lessons" ("name", "teacher", "room", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["name", "Programming I"], ["teacher", "Taro YAMADA"], ["room", "301"], ["created_at", "2021-06-25 06:44:56.034435"], ["updated_at", "2021-06-25 06:44:56.034435"]]

  TRANSACTION (0.3ms)  COMMIT

=> 

#<Lesson:0x0000000107228050

...

このようにしておくと,s.lessons << l という操作で,s に l を関連付けることができる(sに紐づけられた lessons に l を追加するという操作である).学生 s が授業 l を受講している状態を表していると解釈することができる.この操作で,StudentLesson のエントリが1つ作られていることがおわかりだろうか?(「StudentLesson Create」とログが出ている)

irb(main):003:0> s.lessons << l

  TRANSACTION (0.2ms)  BEGIN

  StudentLesson Create (6.0ms)  INSERT INTO "student_lessons" ("student_id", "lesson_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["student_id", 1], ["lesson_id", 1], ["created_at", "2021-06-25 06:45:31.907370"], ["updated_at", "2021-06-25 06:45:31.907370"]]

  TRANSACTION (0.3ms)  COMMIT

  Lesson Load (0.3ms)  SELECT "lessons".* FROM "lessons" INNER JOIN "student_lessons" ON "lessons"."id" = "student_lessons"."lesson_id" WHERE "student_lessons"."student_id" = $1  [["student_id", 1]]

=> 

[#<Lesson:0x0000000107228050

  id: 1,

  name: "Programming I",

  teacher: "Taro YAMADA",

  room: "301",

  created_at: Fri, 25 Jun 2021 06:44:56.034435000 UTC +00:00,

  updated_at: Fri, 25 Jun 2021 06:44:56.034435000 UTC +00:00>]

わざわざ中間的な関連を示す中間テーブルを用意した威力は,次の操作で確認することができる.すなわち,今の操作「だけ」で授業に参加する学生の一覧も取ることができるようになるということである.

l.students を表示させてみよう.これは,授業 l を受講している学生の一覧を取得する,という操作である.これまで,授業 l に関しては何の操作もしていない.しかし,次のように受講者の一覧(といってもまだ1人だけだが)を自動的に得ることを,確認できるだろう.

irb(main):005:0> l.students

  Student Load (0.4ms)  SELECT "students".* FROM "students" INNER JOIN "student_lessons" ON "students"."id" = "student_lessons"."student_id" WHERE "student_lessons"."lesson_id" = $1  [["lesson_id", 1]]

=> 

[#<Student:0x000000010702c850

  id: 1,

  name: "Jun IIO",

  sid: "21G0123456J",

  created_at: Fri, 25 Jun 2021 06:44:17.699274000 UTC +00:00,

  updated_at: Fri, 25 Jun 2021 06:44:17.699274000 UTC +00:00>]

irb(main):006:0>

リアルキャンパスのセレンディピティ

昨日,対面で行われる打合せに参加する必要があって,久しぶりに本学多摩キャンパスまで出かけた.何ヶ月ぶりかではあったが,以前と比べると,少し賑わいを取り戻しているかな?という印象で,学生の姿もちらほら.いつぞやのゴーストタウンのようなキャンパスという有り様ではなかった.

そんなことを考えながら歩いていたら,文学部のある先生とすれ違った.私はイヤホンでラジオを聴いていたのだが,声をかけていただいて気が付いた.少しばかり,立ち話をする.お互いの近況など伝え合い,いろいろ大変ですねと労りあった.

そしてふと気付いたのだ.オンライン生活にはこれがない.もちろん,こういう交流を避けるためにもテレワーク,ということなのだろう.疫学的にそれは正しいのかもしれない.しかし,人間はコミュニケーションする生き物なのである.こういうちょっとしたコミュニケーション,これをセレンディピティというのも烏滸がましい気もするが,こういった出来事が人生の彩りではなかろうか.こういうコミュニケーションあってこそ,日頃のストレスが緩和されるといったら言い過ぎだろうか.

学生と比べると,なんやかんやと理由を付けて入構できる教員ですらこれなので,より制限を課されている学生のストレスは相当なものだろう.学生も人間であるからには,この問題を避けて逃げるわけにはいかない.やはり,我々も学生の教育という職務を担っている以上,真正面からきちんと向かい合うべき問題である.

2021年6月20日日曜日

ちゃんと教えてよ(オンライン学会の罠)

昨年の11月にACHI2020という国際会議に参加した,といっても,オンライン会議であり,発表のビデオを投稿しておしまいという参加した感の薄いものであった.まったく何のための国際会議なんだかわからない,それで良いのか?という感想を持った.

その後,「あんたの予稿はわりと良かったから extended version を journal にインバイトしたげるやで?」という連絡を受け,かなり改訂と追記を加えて投稿した.その結果はまだ届いていないが,今日,ふとしたことから,当該の予稿がBest Paper Awardを受賞していたことを知った.半年後に知るってどういうこと?

「えー?ちゃんと教えてよぅ」というのが正直な気持ちである.とくに優秀でもない平凡なワタクシが論文賞をもらえる機会なんて滅多にないのに…….Awardを頂けたのはたいへんありがたいが,なんだか肩すかしを喰った気分.これがリアルな会議だったら,閉会式で「それではBest Paper Awardを発表します!」パチパチパチ,なんていうプロセスを経て,パンパカパーンと表彰されるのだ.そういったセレモニー,いっさい省略.つまんないの.

っていうかそもそも教えてくれないってどういうことよ?


2021年6月17日木曜日

Webexよお前もか

新しい MacBook Pro に Zoom を Homebrew でインストールしたら,初期設定がすっ飛ばされたせいか画面共有などができないという状況にぶち当たったので皆さんご注意を,という記事を,先日,投稿した.今回はその続きである.

Zoom だけでなく Webex もしばしば利用するので,Webex も次の手順でインストールした.

$ brew install --cask webex

さて,使ってみたところ,先日の Zoom と同じような状況が!


今回はホストではなくたんなる参加者だったが,いつも参加者にも画面共有の権限は与えられている会議なので,会議の設定上の問題であるとは考えにくい.この無効ボタンのところへマウスカーソルを持っていくと,ご丁寧に「システム環境設定を確認せよ」とのインストラクションが出てきた.

先日の Zoom と同じ状況である.

もう手順はわかっているので怖いことは何もない.言われるがままにシステム環境設定を調整して事なきを得た.経験って大事ですね.

2021年6月15日火曜日

ジェスチャーの話

郵便局にレターパックライト370を買いにいった.ところが,固有名詞が咄嗟に出てこない.窓口のお姉さんに向かって「あれください,アレ.……,あの,青いやつ……」とジタバタ.

みっともないことこのうえないのだが,それでも通じるから,人と人との対話ってすごい.


ノンバーバルコミュニケーションの情報量

さて,あの……あの……とアタフタしていたときに,手では必死でA4サイズ程度の四角形を空中に描いていた.レターパックのイメージである.

このジェスチャーでの情報伝達も含めて,無事に「レターパックを買いたい」という意図が伝わり,さらに「青いやつ」という意思疎通から,安いほう(レターパックには安いほうと高いほうの2種類あり,高いほうは赤いのだ),所望のそれを手にすることができた.もう,ノンバーバルコミュニケーション万歳,というしかない.

まあ,この例はかなり極端な例ではあろうが,オンライン講義やオンライン会議などで情報伝達のバンド幅が狭められている状況では,なかなか非言語的情報を伝えられないところがもどかしいところではある.

「ろくろ」とは

ジェスチャーの話で思い出すのは,「ベンチャー企業やITの業界人はインタビュー記事で必ず『ろくろ』を回している」という話である.10年ほど前に話題になっていただろうか.

ご存知ない方のために簡単に説明すると,新進気鋭の業界人やベンチャー社長たちは,インタビュー記事などに写る写真で,必ずといってよいほど「ろくろを回しているようなポーズ」をとっている,というものだ.ろくろを回しているようなポーズとは,両手を前に出して,空中で陶芸作品をこねているようなポーズのこと.誰かが言い出して,一時期,とても話題になった.いまでも,「ろくろを回す」と「IT業界」といったキーワードの組み合わせでネットを検索すると,話題になっていた当時に記された多数の記事を読むことができる.

「IT社長はなぜ『ろくろ』を回すのか」など,理由を推測するような記事も多数みつかるが,ざっと目を通してみると,やれ不安だからだとか,カッコつけてるからだとか,まったくもってテキトーなことばかり並べていて,どれも的外れ.真実をひとつも言い当てていない記事ばかりで困ったものである.

ろくろの正体

ではここで,ろくろの正体を私が明らかにしてしんぜよう.ずばり,彼らのろくろは「エアオブジェクトである」と断言する.

動画で検証してみるとよい.多くの人は,空中にモノを想定するときに,この所作をする.より具体的には「ここにAがあって,Bがあって,Cがある」などと説明するときに,両手でモノの輪郭を表現するような操作をするのだ.上記のABCの例だと,両手で3つの何かを空中に並べるはずである.

それを写真という瞬間で切り取ると,ろくろになる.幽霊の正体見たり,枯れ尾花.解説しちゃうと,実につまんない話でしかない(ろくろ社長に憧れていた皆さんには,ゴメンなさい).


だいぶ若いときの写真で恐縮だが,私もずいぶん大きなろくろ回してた.たしか,このときは段ボール箱程度の物体を空中に描いていたはず.経験者は語る.

2021年6月14日月曜日

Bootstrap5のRails6への導入方法

「最短距離でしっかり身に付く!Webアプリケーション開発の教科書 〜Ruby on Railsで作る本格Webアプリ〜」ではRailsにBootstrapを導入する手順を説明している.執筆当時,Bootstrapのバージョンは4だったのだが,いつの間にかバージョンアップしていて,書籍で説明している手順ではうまく適用できなくなっている.

そこで,ここではその補足として,現時点(2021年6月)でのBootstrap導入方法について説明する.

Bootstrap5の導入

まず,端末から次の操作をしよう.

$ yarn add bootstrap

$ yarn add @popperjs/core

次に,app/views/layouts/application.html.erb のヘッダー部を,次のように修正する.具体的には,stylesheet_pack_tag の行(赤字部分)を追加する.

<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>

<%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>

<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>

app/javascript/stylesheets/application.scss を,次の手順で用意しよう.

$ mkdir app/javascript/stylesheets

$ echo '@import "bootstrap";' > app/javascript/stylesheets/application.scss

app/javascript/stylesheets/application.scss には,以下の内容が書き込まれているはずだ.

@import "bootstrap";

さらに,app/javascript/packs/application.js に次を追記する.

import "bootstrap"

import "../stylesheets/application"

書き込む場所は,import "channels" と Rails.start() の間でよい.

テスト

rails new した後に,上記手順でBootstrapを導入したとする.テストのために,コントローラとビューを1つ作る.

$ bin/rails g controller home index

app/views/home/index.html.erb に,以下の内容を追記しよう.

<button type="button" class="btn btn-primary">Primary</button>

<button type="button" class="btn btn-secondary">Secondary</button>

<button type="button" class="btn btn-success">Success</button>

<button type="button" class="btn btn-danger">Danger</button>

<button type="button" class="btn btn-warning">Warning</button>

<button type="button" class="btn btn-info">Info</button>

<button type="button" class="btn btn-light">Light</button>

<button type="button" class="btn btn-dark">Dark</button>

追記する場所はどこでも構わないが,まあ,末尾でよい.

$ bin/rails s

サーバを起動して,ブラウザで,http://localhost:3000/home/index をアクセスしてみよう.正しく設定できていれば,次のような画面になるはずだ.Bootstrap化されていることを確認できるだろう.