yuya4's note

備忘録です。好きにアウトプットします。

Reciprocal Recommender Systems(相互推薦システム)の紹介

はじめに

この記事は、情報検索・検索エンジン Advent Calendar 2019の12日目のものです。初日から素晴らしい記事ばかり登場するので毎日胃が痛かったです 楽しませていただいております。

今年の9月にコペンハーゲンで開催された推薦システムについてのカンファレンスである RecSys 2019 に参加したのですが,そこで発表 (Neve 2019) を聞いて強く興味を持った Reciprocal Recommender Systems(相互推薦システム)について紹介することにします。

この記事は RecSys2019 の内容について紹介し合う以下の勉強会で私が発表した以下の資料をベースにサーベイしなおしてまとめたものです。

connpass.com

speakerdeck.com

Reciprocal Recommender System(相互推薦システム)とは

一般的に RSs(Recommender Systems; 推薦システム) とは,Amazon などの EC サービスのように,アイテム(商品)をユーザに一方的に推薦するようなシステムのことを指します。 一方で,TinderPairs などのオンラインデーティングサービスであったり,LinkedInWantedly などのビジネスSNS(広義の求人サービス)のように,サービス内のユーザを互いに推薦するシステムを RRSs(Reciprocal Recommender Systems; 相互推薦システム) と言います。

オンラインデーティングサービスと求人サービスでは問題設定が異なっていると感じるかもしれませんが,前者は(基本的に1)男性ユーザに対して女性ユーザを,女性ユーザに対して男性ユーザを相互に推薦するという構造であり,後者は個人ユーザ(いわゆる求職者)に対して企業ユーザ(いわゆるリクルータあるいは企業)を,企業ユーザに対して個人ユーザを相互に推薦するという構造であり,サービス内のユーザを互いに推薦しているという点において問題設定は近しいです。

従来の RSs では,基本的にユーザからアイテムへの嗜好(評価)のみに基づいて推薦が行われます。一方でRRSでは、ユーザどうしの相互の嗜好に基づいて推薦が行われます。ここが従来の RSs と RRSs の一番の違いです。

初めて RRSs が従来の RSs と明確に区別され,その性質について詳細に議論されたのは (Pizzato 2010) のようですが2,従来の RSs に比べて RRSs についてはまだまだ十分に研究が行われていません。

従来の推薦システム(RSs)と相互推薦システム(RRSs)の比較

従来の RSs に対して RRSs には,人気ユーザを不人気なユーザに推薦してしまった(もしくはその逆)際の影響や,受動的な(自分からはアクションしない)ユーザに対して受動的なユーザを推薦した際の影響など,追加で考慮すべき RRSs に特有な様々な問題が存在します。従来の RSs と RRSs の性質の違いについて「ユーザのプロフィールや好みについての情報」,「サービス内におけるユーザの役割」,「推薦システムの性能評価」という3つの観点における比較が (Pizzato 2012) にまとめられているので簡単に紹介します。

ユーザのプロフィールや好みについての情報

f:id:yu-ya4:20191211182745p:plain
Table 2 from (Pizzato 2012)

ユーザが明示的に提供するデータ

従来の RSs では通常,明示的なユーザのプロフィールは必須でなく,わざわざ自身の好みのアイテムについての詳細な情報をサービスに提供したがるユーザは少数です。さらには,ユーザは自分自身が一体何を必要としているのか,欲しているのかを分かっていないこともあります。そのため,ユーザが明示的に提供する自身のプロフィールや好みについての情報だけで十分な推薦を行うことは難しいです。また,情報の提供をユーザに強いることもサービスとして望ましくありません。

一方で RRSs においては,ユーザは積極的に自身のプロフィールや好みのユーザの情報を詳細に提供してくれる傾向にあります。ただ,ユーザは自身をより魅力的に見せるために,無自覚な場合も含めて,正しくない情報を提供してしまうことがあるのでその点を留意する必要があります。自身の好みについても,無自覚な場合も含めて,本当の好みを提供しているとは限りません(性格重視って書くけど実は顔と年収しか見ていない的な?)。

ユーザが明示的に提供するプロフィールや好みについての情報と,ユーザの本当の好みの間にギャップがあることを理解した上でシステムを設計するのは重要です。サービスを利用することで暗黙的に得られるユーザの好みについての情報を利用すれば,ある程度ユーザの本当の好みについて推定することが可能となります。そうすることで,ユーザにプロフィール情報の訂正を促したり,ユーザが自身では気づいていない本当の好みについて気づかせてあげたりといったことが可能となります。

行動履歴に基づく暗黙的な嗜好データ

サービス内でのユーザの行動履歴に基づいて得られる暗黙的な情報という点では,従来の RSs では良いサービスならばロイヤルユーザが何度も利用してくれるのでたくさんのデータが集められます。対照的に RRSs ではサービス内で結婚や転職などの目的が果たされるとユーザはほぼ永久にサービスに戻ってきません。ユーザの行動履歴を利用する場合はこの性質も考慮した設計にする必要があります。

サービス内におけるユーザの役割

f:id:yu-ya4:20191211182946p:plain
Table 3 from (Pizzato 2012)

「推薦の適切さ」の決定

従来の RSs において適切なアイテムが推薦されたかどうかというのはユーザの判断のみによって決定されていました。つまり,ユーザが推薦されたアイテムを購入すると決めたらその推薦は適切ですし,購入しないと決めたのならその推薦は適切でなかったということになります。一方で,RRSs においては適切なユーザが推薦されたかどうかというのは,推薦を受けたユーザ(subject)と推薦されたユーザ(object)の両方の判断によって決定されます。

また,RRSs を利用するユーザはこの事実を認識しており,サービス内でのユーザの行動にも影響を及ぼしています。たとえば,ものすごく好みのユーザが推薦されたとしても,そのユーザにとっては自分は好みではなく断られてしまうのではないかと恐れて推薦を受け入れないという行動に出ることがあります。

好意の「送り手」と「受け手」

従来の RSs においてはユーザが能動的にアイテムを探し,気に入ったものがあれば購入などのポジティブなアクション/好意をアイテムに対して行います。アイテムからユーザに対して好意を伝えたりすることはできません。つまり,ユーザは常に好意の送り手でありアイテムは常に受け手となります。しかし,RRSs ではユーザは状況に応じて送り手にも受け手にもなります。あるユーザが他のユーザの推薦を受けっとた際には,推薦されたユーザが自身のことを気に入ってくれるかということも考慮しつつ,そのユーザに興味があると伝えるかどうかを送り手として決定します。一方で,あるユーザから好意/興味があると伝えられたユーザは受け手となり,送り手のユーザは自分に興味があるということは既に分かっているため,単純に自分の好みだけに基づいてそのユーザに興味があると伝えるかどうか決定できます。

推薦システムの性能評価

f:id:yu-ya4:20191211183010p:plain
Table 4 from (Pizzato 2012)

性能指標

従来の RSs において推薦が適切であるかどうかは推薦に対するユーザの反応のみに着目した正解率で評価することが多いです。一方で,RRSs においては3つの観点で正解率を考えることができます。まず最初に,他のユーザの推薦を受け取り好意の送り手となるユーザに着目すると,推薦されたユーザの中にどれだけ好意を送ることにしたユーザがいたかという指標が考えられます。次に,送り手から好意を伝えられた受け手のユーザに着目すると,受け取った送り手の好意に対してどれだけの割合で好意を伝え返したかという指標を考えることができます。最後に,最終的に推薦された中からどれくらいの割合でユーザ間のマッチングが成立したかという指標も考えられます。

性能への期待値

推薦の精度の必要性,ユーザからの期待値も従来の RSs と RRSs では異なります。前者ではある程度精度が悪くとも(もちろん悪い体験には変わりないが)ユーザはアイテムを購入しないという判断をするだけです。また,たくさんの様々な良いアイテムを推薦してもらいたいと考えているので,多少良くないものでも受け入れてしまう(購入してしまう)こともあります。一方後者では,好意の送り手にとっては魅力的だが受け手にとって送り手が魅力的でないというような推薦が多くなってしまうと,送り手は何度も自分の好意が送り手に断られるというサービスとしてかなり悪い体験をしてしまうことになります。また,サービスの性質上ユーザは少数の(あるいはたった1人の)本当に自分に合ったユーザを探しています。そういう状況において精度の低い推薦をしてしまうことは比較的ユーザにとって受け入れがたいことです。

推薦されるコンテンツの偏り

従来の RSs においては,同じアイテムがたくさんのユーザに推薦されるということに何の問題もありません(在庫の問題とかはあるかもしれませんが)。一方で,RRSs において1人のユーザをたくさんのユーザに推薦してしまうと,そのユーザに送られる好意の数が増えすぎてユーザのキャパシティを超えてしまいます。その結果として,断られる好意の数が多くなってしまいます。逆に,あるアイテム/ユーザが全く推薦されないということを考えると,従来の RSs において本当にそのアイテムが良くないものなのであればそれがどのユーザに対しても全く推薦されないというのはサービスとしては良いことです(そのアイテムの販売者からしたら違うかもしれないが)。一方で,RRSs の場合を考えると,自分から積極的に好意を伝える送り手の役割をこなせるユーザが他のユーザに推薦されないことはサービスとして大きな問題はありませんが,あまり自分から好意を伝えられない受け身なユーザは他のユーザに推薦されないと永遠にマッチングという目的を果てせないことになります。また,受け身なユーザを受け身なユーザにだけ推薦しても両者ともに自分からは好意を送らないために問題となってしまいます。

セレンディピティ

セレンディピティについて,ユーザがあまり明示的に自分の好みを示さない従来の RSs においては受け入れられやすく,寧ろ目新しいアイテムに出会いたいというユーザはたくさんいます。一方で,ユーザが自分の好みをある程度明示的に提供している RRSs において,提供された情報とまったく異なるユーザを推薦してしまうことは悪い体験となりやすい。そのため,なぜユーザが明示的に提供している好みの情報と異なるユーザを推薦しているのかをユーザに理解してもらえるようなインタフェースが求められることになります。

システム構成

Reciprocal Recommender Systems の構成を抽象化すると以下のように表されます。

f:id:yu-ya4:20191212171609p:plain:w400

User A と User B の2群が存在するとします。まず,User A 群に所属する各ユーザから User B 群に所属する各ユーザへの一方向の嗜好を表現する User A to User B Preference Score をなんらかの手段で計算します。同時に,逆向きの嗜好を表現する User B to User A Preference Score も計算します。 次に,それら2つの Preference Score をなんらかの手段(Aggregation Function)で集約することで,双方向のマッチ度を表現する1つの Reciprocal Preference Score へと変換します。この Reciprocal Recommender Score に基づいて,ユーザごとに推薦を行います。

従来の RSs の場合だと,ユーザからアイテムへの一方向の Preference Score のみを計算して推薦を行いますが,RRSs では逆方向の Preference Score も計算して,最終的に推薦に使うスコアは双方向のスコアを考慮しているというのが大きな違いです。かなり単純な仕組みですが,実際のデータで検証すると双方向の嗜好を考慮した Reciprocal Preference Score を利用した推薦システムの方が良い性能が出ているそうです。

RRSs を実現する手法

最後に,実際に RRSs を実現する手法としてこれまで提案されてきたものをいくつか紹介します。

RECON, a content-based filtering algorithm for reciprocal recommendation

RECON: a reciprocal recommender for online dating.(Pizzato 2010) で提案された手法です。その名の通り,コンテンツベースのアルゴリズムであり,各ユーザの嗜好データと各ユーザのプロフィール情報の一致度合いから Preference Score を算出します。

あるユーザについて,過去に好意を送ったユーザ群と受け取った好意に対して好意を返したユーザ群から,体格や年齢,学歴などの属性の要素を抽出することで,ユーザごとの嗜好を表現するデータを作成します。次に,その嗜好を表現するデータとそれぞれのユーザのプロフィール情報のマッチ度を算出することで,あるユーザからその他のユーザへの Preference Score を算出します。

Aggregation Function としては調和平均を採用しています。

Reciprocal Collaborative Filtering (RCF), a collaborative filtering based algorithm

Reciprocal Reciprocal recommendation System for Online Dating.(Xia 2015) で提案された手法です。こちらもその名の通り,協調フィルタリングベースのアルゴリズムです。「同じユーザから好意を受け取ったか」「同じユーザに対して好意を送ったか」などの複数の観点で過去の行動履歴からユーザ間の類似度を算出し,あるユーザと似ている上位 k 件のユーザの嗜好データをもとに,Preference Score を算出します (k近傍)。

こちらも Aggregation Function としては調和平均を採用しています。

Latent Factor Reciprocal Recommender (LFRR)

RecSys2019 にて私が実際に発表を聞いて RRSs に興味を持つきっかけとなった Latent Factor Models and Aggregation Operators for Collaborative Filtering in Reciprocal Recommender Systems (Neve 2019) で提案されている手法です。

従来の RSs では数々の研究がなされてきて実績のある Latent Factor Model(潜在因子モデル)を利用しようとのことで, Matrix Factorization を適用しています。データの特性から学習には SGD(Stochastic Gradient Descent; 確率的勾配降下法)を選択しています。

f:id:yu-ya4:20191211185406p:plain:w300
Figure 1 from (Neve 2019)

また, Aggregation Function にはこれまで調和平均ばかりが採用されていましたが,この研究では Aggregation Function の比較実験が行われました。

実験の結果,精度としてはこれまでの手法とほぼ変わらないかそれ以上で,計算量は大幅に改善されたため実際のサービス運用を考えた場合十分有用なものであるという結論でした。

おわりに

この記事では,私が最近関心を持っている Reciprocal Recommender Systems(相互推薦システム)についての紹介を行いました。 記事を読んでいて感じたかもしれませんが,RRSs 特有の様々な問題に対して現在提案されている手法は比較的ナイーブなものが多いです。 実は,私は現在 RRSs に当てはまるサービスの開発に携わっているのですが,企業でサービスを改善するエンジニアをしていてもまだまだ学術的にも価値のあることができるのではないかと可能性を感じてワクワクしています。

あまり RRSs の研究が盛んでない背景には,生の公開されているデータセットが少ないことが1つの要因としてあるのではないかと思っています。 私の知る限り,オープンなデータセットは RecSys Challenge 2017(http://www.recsyschallenge.com/2017/) で題材とされた,ヨーロッパで展開されているビジネス SNS である XING のものくらいではないでしょうか3。 RRSs に当てはまるサービスのデータはその性質上,非常にセンシティブなものが多いですしオープンにするには様々な障壁があるのですが,適切な形で研究が進められ,パートーナー探しにおいてもシゴト探しにおいてもより良いマッチングが実現できる世界になっていけばいいのになと個人的に思っています。

推薦システムについてもっといろいろとディスカッションしたいなどと思っていただいた方は, 毎週木曜日に社内有志で行っている以下の勉強会とかに参加していただけると嬉しいです。 Twitter などでご連絡いただけると嬉しいです!

github.com

Refs

  • (Pizzato 2010) Luiz Pizzato, Tomek Rej, Thomas Chung, Irena Koprinska, and Judy Kay. 2010. RECON: a reciprocal recommender for online dating. Proceedings of the fourth ACM conference on Recommender systems P. 207-214.
  • (Pizzato 2012) Luiz Pizzato, Tomasz Rej, Joshua Akehurst, Irena Koprinska, Kalina Yacef, and Judy Kay. 2012. Recommending people to people: the nature of reciprocal recommenders with a case study in online dating. User Model User-Adap Inter (2013) 23: 447.
  • (Xia 2015) Peng Xia, Benyuan Liu, Yizhou Sun, and Cindy Chen. 2015. Reciprocal Reciprocal recommendation System for Online Dating. Proceedings of the 2015 IEEE/ACM International Conference on Advances in Social Networks Analysis and Mining P. 234-241. 

  • (Neve 2019) J Neve, I Palomares.2019. Latent Factor Models and Aggregation Operators for Collaborative Filtering in Reciprocal Recommender Systems Proceedings of the 13th ACM Conference on Recommender Systems, 219-227.

  1. 性別に関する問題は難しいと認識していますが,ここでは問題を簡単にするため,サービス内のすべてのユーザが男性ユーザと女性ユーザに分かれていて相互に推薦されるという枠組みで捉えさせてください。

  2. 違ったら教えてください。m( )m

  3. 他に知っていたら教えてほしいです。

2019年3月現在利用しているメモアプリ

最近,論文を読むために iPad Pro + Apple Pencil を導入したのと, そろそろメインの MacBook Pro を買い換えるので, この機会に使っているメモアプリ(って言葉が正しいかはわからない)を見直そうと思っていろいろ調べたのでそのメモを残します。

tl;dr

以下の 3 つのアプリケーションを利用することにしました。 ちなみに今回は 個人での利用 のみを想定しているので,チームでの共有などのプライオリティは高く設定していません。 ()内は使用するデバイスです。

もともとの環境

利用しているアプリケーションもその用途もバラバラでした。笑

今回最終的に利用することにした Evernote(無料版) と Boostnote はもともと利用していたのですが, 個人で利用するメモアプリとしてはその他にも Kobito (2017年12月27日にユーザサポート終了)やNotion (かじっただけですが),iOS 標準のメモアプリをその時の気分で使いわけており,どこに何を記録しているの分からなくなってしまっている状態でした。 また,iPhoneMac の画像の共有のためにはSlack の自分のアカウントへのDM(?)や適当な友人への Line を利用したりもしていました。。。

さすがにごちゃごちゃしていて良くないなというのと,せっかく新しいデバイスが増えるのでこの機にいろいろと見直したという次第です。

メモアプリに求めたこと

私がメモアプリに求めた要件は以下の 4 つです。

  • すべてのデバイス間でシームレスに共有できること。
  • 文章をプレーンな状態で残せること。
    • マークダウンを変換してくれる場合は,プレビュー機能(画面)が別でついてくること。
  • フォルダ分け or タグ付けなどである程度構造化できること。
  • iPad Pro + Apple Pencil を最大限活かせること。笑

こいつらを満たしつつ,できるだけ少ないアプリケーション数で簡潔させたい。

すべてのデバイス間でシームレスに共有できること。

メインで利用する MacBook ProiPad Pro,iPhone の 3 つのデバイスはメモを共有したい。 少なくとも,テキストメモを共有できることは必須だと感じています。

文章をプレーンな状態で残せること。

最近のメモアプリは中途半端にマークダウンに対応してくれるものが多いおかげで, 逆に管理がしにくいと感じていました。 その瞬間の見た目はいいのですが,テキストを他の場所にコピペすると崩れるみたいなことが多発してストレスがすごかった。。。 ですので,テキストは基本的にプレーンな状態で保存できて,かつ,マークダウンを変換する機能がある場合は別の画面でプレビューができるって状態がベストだと思っていました。

フォルダ分け or タグ付けなどである程度構造化できること。

けっこういろんなコンテキストでメモを残すので, ある程度の構造化は必要です。

iPad Pro + Apple Pencil を最大限活かせること。

せっかく買ったのでいい感じにしたい。笑 これはかねてからいいと聞いていた GoodNote を使うと決め手いました。

PDF を取り込んで,直接 PDF にApple Pencil で書きこんだり,PDF の途中にノートを差し込んでメモしたりできます。 フォルダなどでファイルの管理もきちんとできますし,読んだ論文などは今後こいつで管理していくつもりです。

採用したもの

Evernote

まず,「すべてのデバイス間でシームレスに共有できること。」に関しては,課金してプレミアムプランにアップグレードすることで解決されます。次に「文章をプレーンな状態で残せること。」は,設定からオートフォーマットを無効にすれば達成できます。「フォルダ分け or タグ付けなどである程度構造化できること。」に関しては,ノートブックという形でフォルダ分けもできますし,タグもつけられるので検索には向いています。

そして他のアプリと比べて頭一つ抜けたのは,カメラ機能とレコーダ機能です。 カメラ機能では,紙たやホワイトボード上の文書を撮影する際に,いい感じで文書の部分を判定して切り抜いたものをノートとして保存してくれます。 レコーダ機能はさくっと起動させて,録音音声をノートとして保存することができます。

また,Google アドレスでログインできるのと,デスクトップアプリもモバイルアプリも,Web アプリケーションも存在するので,かなり汎用性が高いのも良い点だと思いました。

Boostnote

テキストメモを共有するという目的だけですと Evernote だけでも充分なのですが, コードスニペットをいい感じに残しておいたりしたい。 そういう意味では,Boostnote はかなりベンリなアプリだと思います。シンタックスハイライトがデフォルトでいい感じに設定されているし,ローカルで動いて爆速。 あと,Boostnote はマークダウンプレビューがいい感じにできるのでストレスフリーにマークダウンのメモが残せます。

現在はモバイルアプリがインストールできないので,デスクトップで使うしかできないのですが, コードスニペットの管理だけなら問題ないと感じました。 また,PC 間での共有(というよりもバックアップ)でしたら,Dropbox と連携することで可能ですので, そうすることにしました。

普段 GitHub の Issue 等にそこそこの分量のコメントなりを投下する前には, こいつで下書きしてから書き込んでいます。

というわけで,テキストだけのメモや画像,音声の共有とは別に, コードスニペットの管理という意味で Boostnote を採用することにしました。 コードスニペットを他のメモと一緒に管理するのもイケてないなと思っていましたので。

GoodNote

これはかねてからいいと聞いていた GoodNote を使うと決めていました。

PDF を取り込んで,直接 PDF にApple Pencil で書きこんだり,PDF の途中にノートを差し込んでメモしたりできます。 フォルダなどでファイルの管理もきちんとできますし,読んだ論文などは今後こいつで管理していくつもりです。

採用しなかったもの

Apple 標準メモ

今回いろんなアプリケーションを見ていてかなり優秀なんだと思いました。 Apple のデバイスでしたら「すべてのデバイス間でシームレスに共有できること。」はクリアできますし, 「文章をプレーンな状態で残せること。」も,箇条書き以外は達成できてるはず(箇条書きも設定で無効化できるのかな?)。「フォルダ分け or タグ付けなどである程度構造化できること。」も,フォルダを作成できるのでクリアできています。

ただ,Apple 製品でしか使えないというのは若干汎用性にかけるかなと思ったのと,検索機能が貧弱だなと思いました。 また,前述の採用した Evernote に比べると,もうひと押し使える機能が欲しいなと思ってしまいました。

Notion

最近界隈で盛り上がってきてますね。 私も軽くは使っていたのですが,使いこなせばとてもベンリだと思いました。 私が今回メモアプリに求めている要件も余裕で満たしています。 しかし,いかんせん機能が豊富過ぎて,さくっとメモ用途で使うという意味では使いにくいなと思いました。

拡張性も高く,そのうち本格的に導入できればとも思うのですが,少々導入するのに学習コストもかかりそうですので,今はいったん見送ることにしました。

Inkdrop

こちらも最近盛り上がっていますね! ほとんど Boostnote と遜色ない機能を持っていると思っています。 Inkdrop が Boostnote より際立って優れているのは,モバイルアプリがきちんと実装されていることですかね。

ただ,Boostnote は特定の開発コミュニティで開発が進められている+OSS化されているのに対して,Inkdrop は個人で開発していらっしゃるので若干バグ対応であったり今後の改善スピードが不安ってのと,こちらは有料アプリですので,同じ機能を求めるのなら Boostnote かなと思って今回は利用を見送りました。

モバイルアプリがあるのは魅力的なのですが,今回はコードスニペットの管理に使いたいため基本的に Mac でだけ動けばいいってのと,何故か今はインストールできなくなっちゃっていますが,実は Boostnote のモバイルアプリも存在しているので,強く Inkdrop に変えたいというモチベーションは出てこなかったです。

OneNote

こいつもいろいろできちゃうのですが,Notion と同じく機能が豊富過ぎてさくっと使うには使いづらいかなと思いました。あと,Apple 標準メモ は Apple 製品だけでしか使えないから汎用性がどうとかいいつつも,やっぱり Apple が好きなので宗教じ(ry

まとめ

今回,利用するメモアプリを見直すということで,以下のような要件でサーベイを行いました。

  • すべてのデバイス間でシームレスに共有できること。
  • 文章をプレーンな状態で残せること。
    • マークダウンを変換してくれる場合は,プレビュー機能(画面)が別でついてくること。
  • フォルダ分け or タグ付けなどである程度構造化できること。
  • iPad Pro + Apple Pencil を最大限活かせること。

その結果,以下のアプリケーションを採用することにしました。

文章中でも触れたように,様々な便利なメモアプリが開発され続けているので, 私の中でのベストプラクティスも半年後にはどうなっているのか分かりませんが, とりあえず今使うならこの布陣だなぁと思って挙げさせていただきました。 参考になれば幸いです。

【JavaScript】【jquery】jquery.validate.jsの基本的な使い方

 フォームへの入力チェック(バリデーション)を行ってくれる、jQueryプラグインの【jquery.validate.js】を利用したのでまとめておきます。

今回フォームはこんな感じです。
f:id:yu-ya4:20150702162648p:plain
date_select.html

<html>
<head>
<title>validate</title>
<meta charset="utf-8">
</head>
<body>
  <h2>validate</h2>
  <form class="form-signin">
    <table class="usertable">
        <tr>
            <th>名前</th>
            <td><input name="myname" type="text" value="" /></td>
        </tr>
        <tr>
            <th>電話番号</th>
            <td><input name="num" type="text" value="" /></td>
        </tr>
        <tr>
            <th>メアド</th>
            <td><input name="address"type="text" value="" /></td>
        </tr>
        <tr>
            <th>性別</th>
            <td>
                <input name="gender" type="radio" value="男性" /> 男姓  
                <input name="gender" type="radio" value="女性" /> 女姓
            </td>
        </tr>
    </table>
    <button id="button" class="btn btn-large btn-primary" type="submit">登録</button>
  </form>

<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/jquery.validate.min.js"></script>
<script type="text/javascript" src="js/val.js"></script>
</body>
</html>


jquery.validate.jsはこちらのリンクからダウンロードしてください。
jQuery Validation Plugin | Form validation with jQuery

ダウンロードしたzipファイルを解凍したら、jquery.validate.min.jsを自分のjsファイルにつっこんで準備完了です。(jquery.jsも一緒に設定してください)

jquery.validate.jsでは、inputのname属性ごとにエラーメッセージ、エラーチェックのルールを定義できます。また、デフォで用意されているルール以外にも自分で独自のバリデートルールを定義することも可能です。

とりあえずJavaScriptのコードはこんな感じになりました。

val.js

(function(){
  //標準エラーメッセージの変更
  $.extend($.validator.messages, {
    email: '*正しいメールアドレスの形式で入力して下さい',
    required: '*入力必須です',

    phone: "*正しい電話番号の形式で入力してください"
  });

 //追加ルールの定義
  var methods = {
    phone: function(value, element){
      return this.optional(element) || /^\d{11}$|^\d{3}-\d{4}-\d{4}$/.test(value);
    }
  };

  //メソッドの追加
  $.each(methods, function(key) {
    $.validator.addMethod(key, this);
  });

  //入力項目の検証ルール定義
  var rules = {
    myname: {required: true},
    num: "phone",
    address: {required: true, email: true},
    gender:  {required: true}
  };

  //入力項目ごとのエラーメッセージ定義
  var messages = {
    myname: {
      required: "*名前を入力してください"
    },
    address: {
      required: "*メアドを入力してください"
    },
    gender: {
      required: "*性別を選択してください"
    }
  };

  $(function(){
    $('#testform').validate({
      rules: rules,
      messages: messages,

      //エラーメッセージ出力箇所調整
      errorPlacement: function(error, element){
        if (element.is(':radio')) {
          error.appendTo(element.parent());
        }else {
          error.insertAfter(element);
        }
      }
    });
  });

})();


1ブロックずつ解説していきますね。



まず1ブロック目では、標準で定義されているエラーメッセージを変更してあげています。もちろん変更なしでもvalidate自体は問題なく機能します。

 //標準エラーメッセージの変更
  $.extend($.validator.messages, {
    email: '*正しいメールアドレスの形式で入力して下さい',
    required: '*入力必須です',

    phone: "*正しい電話番号の形式で入力してください"
  });

バリデートルール : "表示させたいエラーメッセージ"
って感じで好きにつけてあげてください。


続いて2ブロック目では追加ルールを定義しています。

var methods = {
    phone: function(value, element){
      return this.optional(element) || /^\d{11}$|^\d{3}-\d{4}-\d{4}$/.test(value);
    }
  };

今回は'phone'というルールを新たに定義してあげました。正規表現で表してやればよいみたいです。この'phone'は11桁の数字または000-0000-000のように3桁-4桁-3桁とハイフンで数字が繋げられているものならエラーを出さないというルールです。

そして3ブロック目のaddMethod()で定義した追加ルールを登録しています。

4ブロック目と5ブロック目ではそれぞれ、適応する検証ルールとエラーメッセージをinputのname属性ごとに設定しています。

//入力項目の検証ルール定義
  var rules = {
    myname: {required: true},
    num: "phone",
    address: {required: true, email: true},
    gender:  {required: true}
  };

  //入力項目ごとのエラーメッセージ定義
  var messages = {
    myname: {
      required: "*名前を入力してください"
    },
    address: {
      required: "*メアドを入力してください"
    },
    gender: {
      required: "*性別を選択してください"
    }[f:id:matsumura-kobetsu:20150611175118p:plain]
  };

ルール定義では基本的に、name : {rule: true} という感じでokです。
たとえば myname: {required: true} は、name="myname"であるinputに対してrequired(入力必須)ルールの適用を行う、という具合です。
"phone"というのは先ほど定義した検証ルールですね。
エラーメッセージ定義では、name : {rule: "エラーメッセージ"} という感じです。


これで設定が終わりましたので、最後にフォームに対して(idで指定しています)先ほど設定してあげたrulesとmessagesを適用してバリデートを実行しています。

$(function(){
    $('#testform').validate({
      rules: rules,
      messages: messages
    });
  });

実際にバリデイトを行うとこんな感じで怒ってくれます。すみません。

f:id:yu-ya4:20150702162644p:plain

何が素晴らしいって、入力するたびにエラーチェックを行ってくれるのと、submitしようとした際もエラーチェックを行ってくれるところですね。便利。

ちなみにerrorPlacementってのは、エラーメッセージを表示する箇所を設定してあげてます。

以上で簡単なjquery.validate.jsの使い方は終了です。
もうちょい書きたいことがあったりなかったりするのでまた続編を書くかもしれません。書かないかもしれません。

この記事がどなたかのお役に立てれば幸せです。

【JavaScript】【jquery】セレクトボックスでのうるう年計算

簡単な入力フォームを作ってJavaScriptの勉強をしているのですが、
生年月日を入力する際にいい感じでうるう年も考慮してくれるものがなかったので
いろいろなサイトやらを参考にしながら作りました。

フォームはこんな感じです。
f:id:yu-ya4:20150702162652p:plain
date_select.html

<html>
<head>
<title>日付選択</title>
<meta charset="utf-8">
</head>
<body>
<form class="form">
    <select id="year">
        <option value="">--西暦--</option>
    </select>
    <select id="month">
        <option value="">-月-</option>
    </select>
    <select id="day">
        <option value="">-日-</option>
    </select>
</form>

<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/date_select.js"></script>
</body>
</html>

javascriptはこんな感じです。
date_select.js

(function(){
  //日付範囲決定
  function calcDays(){
    $('#day').empty();
    var y = $('#year').val();
    var m = $('#month'). val();

    if (m == "" || y == "") { //年か月が選択されていない時は31日まで表示
      var last = 31;
    } else if (m == 2 && ((y % 400 == 0) || ((y % 4 == 0) && (y % 100 != 0)))) {
      var last = 29; //うるう年判定
    } else {
      var last = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)[m-1];
    }

    $('#day').append('<option value="">日</option>');
    for (var i = 1; i <= last; i++) {
      if (d == i) { //日がすでに選択されている場合はその値が選択された状態で表示
        $('#day').append('<option value="' + i + '" selected>' + i + '</option>');
      } else {
        $('#day').append('<option value="' + i + '">' + i + '</option>');
      }
    }
  }

  var d = 0;
  $(function(){
    //1900年~2015年まで表示
    for (var i = 2015; i >= 1900; i--) {
      $('#year').append('<option value="' + i + '">' + i + '</option>');
    }
    //1月~12月まで表示
    for (var i = 1; i <= 12; i++) {
      $('#month').append('<option value="' + i + '">' + i + '</option>');
    }
    //1日~31日まで表示
    for (var i = 1; i <= 31; i++) {
      $('#day').append('<option value="' + i + '">' + i + '</option>');
    }

    $('#day').change(function(){
      d = $(this).val();
    });
    //年か月が変わるごとに日数を計算
    $('#year').change(calcDays);
    $('#month').change(calcDays);
  });
})();

まあ、単純にうるう年の計算方法をそのまま実装しただけですね。

  1. 西暦年が4で割り切れる
  2. ただし、西暦年が100では割り切れてはいけない
  3. ただし、西暦年が400で割り切れるのはok

西暦年か月が選びなおされる都度日付を計算するようにしています。
また、日付がすでに選択されていた場合はその値を保持しておき、
年や月を選び直して再度日付計算が行われても日付を選びなおさないでいいように実装しています。

こんな簡単なことなのにとても時間がかかってしまいました・・・。
jquery使ったのも初めてですので多めに見てやってください。

次回はvalidateについて書こうかな...

記事中へのソースコードの埋め込み

さて、ブログを始めてみたわけですがどうやって記事中にソースコードを埋め込むのかなーって思って調べてみたのでまとめてみました。

と言っても簡単で、ソースコードを'>||'と'||<'という記号で挟めばいいだけのようでした。

ただ、一つ注意点ですが、これははてな記法というらしく、

f:id:yu-ya4:20150702160715p:plain

こんな風に設定の編集モードをはてな記法モードに変更してやる必要があります。

例えば、記号で挟まなかったら

#include

int main(void){

printf("hello, world!");

return 0;

}

という風に表されるところ、'>||'と'||<'で挟んでやれば...

#include <stdio.h>

int main(void){

    printf("hello, world!"); 

    return 0;

}

こんな風に、入力コードをいい感じに表してくれます。枠で囲んでくれるのいいですね。

また、記号で挟む際に、'>|lang_type|' '||<' のlang_typeにプログラミング言語の種類を入れてやると、
(この例では lang_type = c)

#include <stdio.h>

int main(void){

    printf("hello, world!"); 

    return 0;

}

こんな風に色分けして表示してくれるようです。

他にもいろんな言語に対応しているようで、詳しくは以下のリンクから対応しているファイルタイプをご確認下さい。

ソースコードを色付けして記述する(シンタックス・ハイライト) - はてなダイアリーのヘルプ

とりあえずこんな感じでかっこよくコードを貼付ける方法は分かりましたので、これからは貼付けるだけのコードを書けるように精進して参ります。

他にもはてな記法には便利なものがたくさんあるようですので少しずつ使えるようになればいいなと思います。

以上、初投稿でした。