For Your ISHIO Blog

データ分析や機械学習やスクラムや組織とか、色々つぶやくブログです。

学習済みEmbeddingを利用する時の前処理ゴールデンルール

Word2vecやfastText、Gloveなど、Word Embeddingの方法は広く普及してきており、外部から学習済みのEmbeddingデータをインポートし、そのベクトルを手元のデータセットに適用し利用するケースも増えています。

学習済みEmbeddingを効果的に利用するためには、一般的な自然言語の前処理とは異なるアプローチが必要らしいです。次のKernelでは、ゴールデンルールとして紹介されていますので、このブログで触れたいと思います。

How to: Preprocessing when using embeddings | Kaggle

目次

そもそもEmbeddingとは

こちらをご覧ください。

ishitonton.hatenablog.com

2つのゴールデンルール

次の2点が前処理の方針です。

  1. 学習済みEmbeddingを利用する際には、ステミングやストップワードの除去等の標準的な前処理ステップを利用しない。
  2. 自データセットのvocabularyをできるだけ、Embedding側に近づけるように処理を行っていく。

ここでの注意点としては、利用する学習済みEmbedding毎に、Embedding作成までのプロセス(前処理や除外ルール)は異なる点です。つまり、このEmbeddingに近づけるための作業は画一的な手順ではなく、利用するEmbeddingと対話をしながら、ある程度探索的なデータ分析プロセスを挟むことになります。

利用するデータセット

用意するのは、次の2つです。

  1. 学習済みEmbeddingデータを適用するデータセット
  2. 学習済みEmbeddingデータ

前者には、Kernel同様KaggleのQuora Insincere Questions Classificationコンペのデータセット(trainデータ)を利用します。

Quora Insincere Questions Classification | Kaggle

後者には、GoogleNewsをもとに作成されたWord2vecのEmbeddingを利用します。次のリンクからダウンロード可能です(約2GB)。

GoogleNews-vectors-negative300 | Kaggle

適用先のデータセット

Quoraは実名制のQ&Aサイトで、データセットには質問のテキストデータが含まれています。

text.head()
0    How did Quebec nationalists see their province...
1    Do you have an adopted dog, how would you enco...
2    Why does velocity affect time? Does velocity a...
3    How did Otto von Guericke used the Magdeburg h...
4    Can I convert montra helicon D to a mountain b...
Name: question_text, dtype: object

データセットのVocabularyを作成

テキストデータからVocabularyの辞書を作成していきます。

def build_vocab(sentences, verbose =  True):
    vocab = {}
    for sentence in sentences:
        for word in sentence:
            try:
                vocab[word] += 1
            except KeyError:
                vocab[word] = 1
    return vocab

sentences = text.apply(lambda x: x.split()).values
vocab = build_vocab(sentences)
print(vocab)
{'How': 261930,
 'did': 33489,
 'Quebec': 97,
 'nationalists': 91,
 'see': 9003,
 'their': 34810,
...

学習済みEmbeddingの読み込み

gensimを利用して、Word2Vecの学習済みEmbeddingを読み込みます。

from gensim.models import KeyedVectors

news_path = 'GoogleNews-vectors-negative300.bin'
embeddings_index = KeyedVectors.load_word2vec_format(news_path, binary=True)

試しにjapanという単語をみてみます。

embeddings_index["japan"]
array([-3.22265625e-01,  2.30712891e-02,  1.77734375e-01,  3.35937500e-01,
       -2.75390625e-01, -3.01513672e-02, -2.11914062e-01, -2.98828125e-01,
        3.76953125e-01, -1.13281250e-01, -6.54296875e-02, -3.53515625e-01,
       ...
       -6.95312500e-01,  2.50000000e-01,  7.66601562e-02,  2.02148438e-01],
      dtype=float32)
print(embeddings_index["japan"])
300

このEmbeddingは、300次元からなるベクトル表現であることがわかります。

vocabと外部Embeddingの単語の重複チェック

Out of Vocabulary(OoV)はすなわち知らない単語のことを指します。データセットと外部の学習済みEmbeddingには、存在する単語に差異があります。外部Embedding(Google News)には存在しないが、データセットのVocabularyには存在する単語がOoVです。これを利用することで、前処理を改善することが可能です。

以下は、vocabとembeddingとの間の共通部分およびOoVをチェックする関数です。

import operator 
from tqdm import tqdm

def check_coverage(vocab, embeddings_index):
    a = {}
    oov = {}
    k = 0
    i = 0
    for word in tqdm(vocab):
        try:
            a[word] = embeddings_index[word]
            k += vocab[word]
        except:

            oov[word] = vocab[word]
            i += vocab[word]
            pass

    print('Found embeddings for {:.2%} of vocab'.format(len(a) / len(vocab)))
    print('Found embeddings for  {:.2%} of all text'.format(k / (k + i)))
    sorted_x = sorted(oov.items(), key=operator.itemgetter(1))[::-1]

    return sorted_x

実行します。

oov = check_coverage(vocab, embeddings_index)
Found embeddings for 24.31% of vocab
Found embeddings for  78.75% of all text

出力結果からは、Quoraのテキストデータから得られた単語の24.31%しか、外部Embeddingデータに含まれていないことがわかります。これでは、外部のEmbeddingを利用して、テキストデータに内包される情報を効果的に表現することができません。データクレンジングを通じて、できるだけこの割合を高めていきます。(=OoVを減らしていく。)

OoVの出力し、改善の糸口を探る

OoVを出力してみます。

oov[:20]
[('to', 403183),
 ('a', 402682),
 ('of', 330825),
 ('and', 251973),
 ('India?', 16384),
 ('it?', 12900),
 ('do?', 8753),
 ('life?', 7753),
 ('you?', 6295),
 ('me?', 6202),
 ('them?', 6140),
 ('time?', 5716),
 ('world?', 5386),
 ('people?', 4971),
 ('why?', 4943),
 ('Quora?', 4655),
 ('10', 4591),
 ('like?', 4487),
 ('for?', 4450),
 ('work?', 4206)]

サンプル出力からいくつかのことがわかります。

  • 語尾に?がついたVocabがEmbeddingには存在していない。?とか記号分割の処理をいい感じにすればOoVを減らせる。
  • atoofandGoogle newsのEmbeddingには存在しない。学習時に削除している??

得られた仮説をもとに、OoVを減らせるかトライしてみます。

前処理1(記号の処理をいい感じにする)

記号は削除すべきか・それとも残すべきかは、場合によります。ゴールデンルールに従えば、利用する外部Embeddingの単語として存在する場合には残せばよいし、存在しない場合は削除した方がよいです。データセットのVocabをできるだけ外部Embedddingの単語に近づけていきます。

今回のデータで?&をについて確認してみます。次の結果からは、?についてはVocabの単語から削除し、&については外部Embeddingに存在するので残しておくべきということになります。これらは利用する外部Embeddingデータによって前処理は異なるため、判断は変わってきます。

'?' in embeddings_index
False
'&' in embeddings_index
True

そんなんで、クレンジングしていきます。&は語彙として残しますが、他は削除します。

def clean_text(x):
    x = str(x)
    for punct in "/-'":
        x = x.replace(punct, ' ')
    for punct in '&':
        x = x.replace(punct, f' {punct} ')
    for punct in '?!.,"#$%\'()*+-/:;<=>@[\\]^_`{|}~' + '“”’':
        x = x.replace(punct, '')
    return x

text_clean = text.progress_apply(lambda x: clean_text(x))
sentences = text_clean.apply(lambda x: x.split())
vocab = build_vocab(sentences)
oov = check_coverage(vocab, embeddings_index)
Found embeddings for 57.38% of vocab
Found embeddings for  89.99% of all text

Quoraのテキストデータから得られた単語の57.38%が、外部Embeddingデータにも含まれるようになりました。前回の24.31%から大きく増加しました! さらに、再度OoVをチェックしてみます。

oov[:20]
[('to', 406298),
 ('a', 403852),
 ('of', 332964),
 ('and', 254081),
 ('2017', 8781),
 ('2018', 7373),
 ('10', 6642),
 ('12', 3694),
 ('20', 2942),
 ('100', 2883),
 ('15', 2762),
 ('12th', 2551),
 ('11', 2356),
 ('30', 2163),
 ('18', 2066),
 ('50', 1993),
 ('16', 1589),
 ('14', 1533),
 ('17', 1505),
 ('13', 1390)]

語尾に?がついた単語については先ほどの前処理によってなくなりましたが、新たな仮説が導かれます。

  • OoVに数字がたくさんある。Google news側で、数字に対するなにかしらの前処理が行われているのでは?

前処理2(数字の処理をいい感じにする)

今回も、データセットのVocabをできるだけ外部Embedddingの単語に近づけていきます。そのためにEmbedding側でどのように数字が処理されているかを探索的に探っていきます。 結論としては、利用したGoogle newsのEmbeddingでは、数字は#に置き換えられているようです。10であれば##99.99であれば##.##といった具合です。

データセット側も同様の処理を行います。

import re

def clean_numbers(x):
    x = re.sub('[0-9]{5,}', '#####', x)
    x = re.sub('[0-9]{4}', '####', x)
    x = re.sub('[0-9]{3}', '###', x)
    x = re.sub('[0-9]{2}', '##', x)
    return x

text_clean2 = text_clean.progress_apply(lambda x: clean_numbers(x))
sentences = text_clean2.progress_apply(lambda x: x.split())
vocab = build_vocab(sentences)
oov = check_coverage(vocab, embeddings_index)
Found embeddings for 60.41% of vocab
Found embeddings for  90.75% of all text

さらに、60.41%と改善しました!

こんな感じで、前処理をやっていきます。

そのほか前処理していること

この他にも、OoVをもとにEmbeddingに近づけるためのアイデアを探っていきます。割愛しますが、Kernekでは以下のような処理も行っています。

  • QuoraのQ6Aのテキストデータには、ソーシャルメディアならではの人間が間違いやすいスペルミスが存在している(おそらくGoogle news側では少ない)。これをいい感じにしてやる。
  • OoVに多い「a」、「to」、「and」、「of」という単語を削除する。Google newsのEmbeddingを学習するときには明らかにこれらの単語をダウンサンプリングしている。

最後に

なんか間違ってたり、よりよいアイデアあれば教えてください。

1on1始めるぞー!のためのチェックシート

ゴールデンウィーク明けから、1on1をメンター側で始めることになりそうです。すでに組織に1on1は導入されていて、これまで私は部下の立場でマネージャーと週30分程度行っていました。

今後は立場を変え、「後輩(部下ではない)」との1on1を行っていく(たぶん)ですが、間違った運用を続けていると、組織と個人を破壊するので、過去に読んだ「ヤフーの1on1―――部下を成長させるコミュニケーションの技法」を読み直しました。

自分の考え含め、仕事中にカンニングするために、ブログ上でチェックシートという形で整理しておきます。

www.diamond.co.jp

1. 1on1は部下のために行う面談であることを忘れない。

1on1は、個人の経験学習を促すことが、一番の実施する意義。とはいえ、30分の対話が終わったときに、部下が「話してよかった」と思えれば、まず成功。業務についての相談の場になってもよい。例えば、なかなか上司が忙しくて話す時間が取れない等、それが部下にとって有意義な場であるならば。

2. 定期的に実施できているか

忙しいからといって、1on1を先延ばしにしてはならない。とはいえ、上司のカラダは1つなので、信頼関係が高まってきた部下は「2週間に一度」にするなど、粒度をつけて工夫するとよい。

3. 1on1内での対話の内容は、原則他人に話さない。

できるだけ安心してしゃべってもらおう。もしかしたらプライベートでの悩みがあるかもしれない。部下が良いコンディションで仕事に集中するためには、プライベートが安定していることも重要。

4. 部下に十分に話してもらえたか。

1on1は部下の行動や経験学習を深めることが目的。自分の経験を思い出し、言葉にして深い内省を促すために、部下側にたくさん話してもらおう。

5. アクティブリスニングの態度がとれているか

アクティブリスニングは、すなわち傾聴。部下が話しやすい雰囲気を作ってあげる。そのための安心感を与える動作を取る。信頼関係を構築するところから始める。

6. 部下の話を最後まで聞いているか。

部下に最後まで話をさせず、途中で遮って質問をしてはならない。部下本人が思い出し、学び行動することが重要。また、質問攻めにすることは、上司側の関心や興味に基づく質問であり、対話の内容は部下が本当に話したいことからずれていく。

7. 上司が先に自分の考えを言っていないか。

部下の言葉を先取りして、自分の考えていることを話し始めてしまっていないか。これでは部下の学びは深くならない。また、上司と異なる見立てを持っているとしたら、部下はそれを表明しづらくなる。

8. 1on1を評価のための面談にしていないか。

良い悪いの判断は避け、部下の想いや考えを深めるための問いかけをすべき。特に第三者が行うコーチングとは異なり、上司と部下の関係では、本音で話せないこともでてくる。より一層の安心できる・話しやすい雰囲気を醸成し、信頼関係を築く必要がある。

9. 否定は常にNGではないが、上手に否定しよう。

部下は上司の指示待ち人間になりかねない。上司依存になると、部下は考えなくなり、学びが深まらない。ただし、期待を持っている限り、言うべきことはしっかり言うことも大事。

10. 部下の次の行動まで、促すことができているか。

「いつまでにやろうか」「自分に手伝えることはあるか」など、部下の具体的な行動宣言まで支援できると善き。

11. 今日は何から話そうか。

テーマは部下側に決めてもらおう。それでも信頼関係ができていない最初は、話すネタが出てこないかもしれない。そのために、上司側もいくつかネタは持ち合わせておこう。

12. 1on1自体のプロセスも振り返ろうぜ。

1on1は結局のところ、個人と個人のコミュニケーションなので、書籍で読んだようにうまくいかないだろうし、人によってリアクションは違うだろうし試行錯誤が続くと思われる。1on1自体やそのプロセス自体も振り返りを行い改善していき、自身の態度などを改善していく必要があると思います。


現職場では、スクラムフレームワークで業務を行っているため、チームの振り返りは「スクラムイベント」、個人の振り返りは「1on1」という仕切りになるかと。ITの領域は進化のスピードが速いため、個人と組織が継続的に振り返り成長していくことがより求められるため、定期的・短期的に振り返りを促せる1on1の意義は大きいと思います。

直感・感覚値で作ってたData Visualizationから卒業する(したい)

データドリブンな組織を作るとか何とか叫びながら、あれ私データ可視化するとき、直感や感覚値だけで適当に色使いやらなんやら作ってるやん?と、ふと思ったのが勉強のモチベーションです。

『The Big Book of Dashboards』という書籍を読んでいます。グラフやダッシュボードを作りデータ可視化を行う上で、データを扱う人間が気を付けるべきことはたくさんあります。それは人間の脳の働きや色覚が異なる人への配慮、色の使い方やデータタイプなど様々です。こういった(恐らくデザイナーさんが普通に知っている)可視化テクニックを体系的に教えてくれる良書であると思います。 デザインや色の使い方を直感や感覚値で選んでいた私はとても参考になっているので、いくつか勉強になった観点を共有します

The Big Book of Dashboards [Book]

Anscombe's Quartet

「そもそもなぜデータの可視化をするのか」という疑問に対しては、アンスコムの数値例(Anscombe's Quartet)に説得力があります。統計学者のフランク・アンスコムさんが1973年に頑張って作ったらしい。実は、4つのグラフのXとYの平均・分散、XとYの相関係数も回帰直線も全て同じになります。実際にプロットしてみると、表や統計量だけでは把握できない情報が存在していて、視覚化により発見できることが理解できます。

f:id:ishitonton:20190405194457p:plain
The Big Book od Dashboards: FIGURE1.1

Preattentive Attributes

Preattentive Attributesは、日本語では前注意的処理とか言います。他のことに注意を払ったり、意識的にデータを理解しようとする前に、無意識に人間の脳がミリ秒単位でする処理のことを指します。この人間の脳の認識処理をうまく活用すると、情報をより効果的に理解させたり、相手の注意を引き付けたりすることができます。

例えば、次の図の中から「数字の9の数を数えてください」という質問に対して回答は簡単だと思います。ただし少し時間がかかると思います。この図に対して、Preattentive Attributesの処理を活かすように少しだけ手を加えると、質問に対する回答がずっと早くなります。

f:id:ishitonton:20190406151532p:plain
The Big Book od Dashboards: FIGURE1.3

次の図の場合はどうでしょうか。おそらく意識的に数字の9を探そうを試みる前に、赤字の数字9に注目したと思います。

f:id:ishitonton:20190406151634p:plain
The Big Book od Dashboards: FIGURE1.4

1つの色を視覚化に使用することは、1つのカテゴリを際立たせるために非常に効果的です。複数色を使う場合でも、カテゴリが少なければ十分識別に有効です。8~10個のカテゴリーがある場合は、色が多すぎて1つを他のカテゴリと識別することは難しくなります。おそらく感覚的には認識されていることだと思います。

上で出てきた色とサイズ以外にも、Preattentive Attributesに有効な特徴はたくさんあります。これらを効果的に利用することで、相手に効果的に情報を伝えたり、組織の意思決定を早くしたりできると考えます。

f:id:ishitonton:20190405201516p:plain
The Big Book od Dashboards: FIGURE1.10

How to Choose Color

「色」の使い方はデータの可視化において最も重要である一方、誤った使い方をされる要素の1つです。色は意図的に利用されるべきです。たとえば、読み手の注意を引きつけたり、データの一部や異なるカテゴリの間の区別を強調したりすることです。

次の図では、色の主要な使い方が説明されています。Sequential(連続)Diverging(発散)Categorical(カテゴリー)Highlight(強調)Alert(警告)です。

f:id:ishitonton:20190406154853p:plain
The Big Book od Dashboards: P15

Sequential Colorは、1種類の色に対して、色の明るさを変更し、グラデーションで表現します。

Diverging Colorは、中間に分岐ポイントを設定し、その中間点からそれぞれ2色のグラデーションを利用して表現します。例えば、ポジネガの可視化などにおいて、ニュートラルをグレーとし、そこからポジティブな値は青のグラデーション。ネガティブな値は赤のグラデーションで表現したりします(ポジ/ネガにどの色を使うかも重要です。西洋文化では、左記に挙げた色使いが一般的で、色だけでポジネガの印象を与えます)。他には、気温の可視化などでは、寒いときは青、暑いときは赤を利用したりしますね。

Categorical Colorは、異なるカテゴリ間で表現を区別するために色を分けて利用します。

Highlight Colorは、読み手に何か情報を際立たせる必要がある時に利用します。ただし、警告や警報以外の用途になります。この色の使い方には様々な方法があります。その一例を以下に示します。

  • 特定のデータポイントのハイライト

  • 表内のテキストのハイライト

  • 折れ線グラフ上の特定のラインの強調表示

  • 棒グラフ内の特定の棒を強調表示

最後のAlert Colorは、読み手に警告を与えるものであり、すぐに注意を惹けるような、明るいアラーミングカラーを利用します。

Color Vision Deficiency

Color Vision Deficiency(CVD)は、日本語だと色覚異常色盲などと訳されます(※専門家でないので誤っていたらご指摘ください)。CVDをもつ人は、色は見えるが大多数の人と見え方が異なっていたり、特定の色を区別できない。本書籍だと女性で0.4%、男性で8%ほど、程度は違えどCVDであると記載されています(※色彩検定のHPには異なる数字が記載されている)。 大企業に勤めていて、大勢の人が可視化したダッシュボードを見る場合や、可視化した情報を一般公開する場合には、無視することはできません。色の見え方は多様であることを理解し、多様な人間が苦なく正確に情報を理解するためには、CVDの人がどのように色を区別しているかの知識を持つ必要があります。

私自身もこれから勉強を始める身ですが、CVDにも様々なタイプがあり一概に全員が同じ傾向にあるとは言えないようです。例えば、protanopia(=red color blindness)Deuteranopia(=green color blindness)Tritanopia(=blue color blindness)などのタイプがあります。

一般的には赤と緑の間の区別に問題を抱えると記載されています。赤と緑を一緒に利用しないことがベストな可視化方法であり、つまり一般的に、信号機色の同時利用を避けるべきです。

下記の図は、左が信号機の色を利用したグラフで、右がCVD(Protanopia)がどのように見えているかをシミュレーションしているものです。信号機のカラーパレットは多くのソフトウェアで普及しており、今日のビジネスで一般的に使用されているため、議論の種の1つです。

f:id:ishitonton:20190406162441p:plain
The Big Book od Dashboards: FIGURE1.24

解決策として、本書ではColor-blind-Friendlyなカラーパレットの知識が手に入ります。一般的な解決方法としては、緑の代わりに青、赤の代わりにオレンジを利用することです。下記の図は、Color-blind-Friendlyな色を利用した場合のCVDの見え方です。

f:id:ishitonton:20190406163845p:plain
The Big Book od Dashboards: FIGURE1.25

まとめ

『The Big Book of Dashboards』には、より細かく、様々なシナリオにおける可視化のテクニックや注意すべき知識が述べられています。今まで感覚でなんとなくやっていたことが体系的な知識として獲得できると思いますので、大変お勧めです。データを扱う人間であれば知っていて損はないと思います。

とりあえず、私自身は、色彩とかCVDに関する知識を身に付けたいモチベが高まっているので、そこらへんの資格をとる勉強をしようと思います。

以上です。

Hadoop / Spark Conference 2019 参加メモ

3月14日(木)にHadoop / Spark Conference 2019が開催されました。このイベントの参加メモになります。

hadoop.apache.jp

目次

同イベントは毎年開催されているわけではなく、近年は開催されていなかったらしい。そんなわけで「Hadoopはオワコンなんだね」と巷では認識されることもあるが、ちゃんと進化してますぜ!ということをこのイベントではアピールしたいらしい。(※旧MapReduceは確かに下火ですが、HDFSはバリバリ活躍中ですよね。)

Hadoop/SParkの初心者の方は以下の勉強会資料をご参考ください。 speakerdeck.com

プログラム

黄色線が引かれた講演を、私自身は聴いてきました。いくつか本ブログでも共有したいと思います。

f:id:ishitonton:20190315211623p:plain
プログラム

1. Hadoopの現在と未来:鯵坂 明さん、Arpit Agarwalさん

Hadoopの利用状況」に関する事前アンケート結果

※あくまで参加者のアンケート回答であり、正しい現状を示しているとは限らないので注意してください。

  • Hadoop利用者の1/4くらいはHadoop 3系を既に利用。2系から3系へと検証/導入が進んでいる。
  • オンプレミス環境での利用者が60%くらい。オンプレ優勢もクラウドでの利用ユーザが拡大している。
  • クラスタ数は~10台と小規模なクラスタ構成が45%程度と多い。

Hadoop 3系がリリースされたのは、確か2017年の12月くらいだったと思うので、この1年ちょっとで徐々に浸透し始めているということだと思います。

f:id:ishitonton:20190315213322p:plain

並列分散処理の取り巻く動向

現在の並列分散処理の取り巻く動向としては、下記4つが挙げられており、この動向を受けて、Hadoopエコシステムも進化を続けている模様。

  1. クラウドサービスでの利用が増加
  2. データ量/計算量の増加
    • スケーラビリティの限界突破が進んでいる。
      • HDFS/YARN Router-based Federationクラスタを束ねることで、マスタの負荷を軽減(クラスタを束ねる機能?)
      • OZONE:オブジェクトストレージ機能の開発。
      • HDFS Erasure Coding:ディスク節約。(データローカリティがなくなるが、あまり問題にならなくなってきている。)
  3. 機械学習、深層学習の浸透
    • Submarineというサブプロジェクトが進んでいる。これは、YARNの最新機能をフル活用して、TensorflowやPytorchなどの深層学習フレームワークHadoop上で分散実行させる。
    • GPU isolation、Docker on Yarn、Container DNS support
  4. コンテナ技術の発展

個人的には、TensorflowやPytorch等のカバーを目指している点に注目。

オブジェクトストレージ機能『OZONE』の紹介

  • Ozoneは、HDFS上にオブジェクトストアを実装し、(⁠Amazon S3やAzure Storageのような)オブジェクトストレージとして利用可能にする技術。HDFSの良い部分はそのままに、HDFS併用可能かつ移行可能な技術。
  • 「多数のオブジェクトを格納したい」、というHDFSが苦手とする領域をカバーする目的で開発が進んでいる。
  • 現在はまだアルファ版。今後ベータ版も出す予定。Hadoop/Sparkのエコシステムはそのまま利用可能。

www.slideshare.net

2. The upcoming Spark 3.0: What’s Next:猿田 浩輔さん、Xiao Liさん

Sparkに関するこれまでの振り返りと今後の展望について共有がなされました。

振り返り

2018年の12月末にはSpark2.4がリリースされている。Sparkは、Unified Data Processing Engineとして着実に進化。バッチ処理、ETLでの活用が依然として多いが、新たに「IoTやアナリティクス領域」でのデータ活用を取り込めている。Spark2.0以降では、これらのデータ活用に即した機能追加も行われた(ex:Structured Streaming/Pythonからの利用における利便性向上/PandasUDFなどの拡充)。詳しくは下記資料にまとめられています。

medium.com

一方で、現在の課題としては「AI領域の需要取り込み」が挙げられます。昨今は機械学習Deep Learningがトレンドとなっているが、この領域の活用を取り込めていない現状があるとのこと。

Spark3.0の展望について

CIOへの調査報告によると、AI分野への投資が増加しているが、成功例は少ない。Unified Analyticsが成功のカギと言っている。79%のCIOがUnified analytics Platformとして、データサイエンスとデータエンジニアリングの統合を評価しており、AI領域においても、AIとデータの統合的なアプローチが期待されている。これを受けた下記のような展望。

  1. Project Tungsten

    • メモリの利用効率改善やモダンなCPU機能の活用によりCPUネックの解消を行うプロジェクト。
    • 分散実行されるDeep LearningのジョブをSparkのStageとして埋め込むために、ギャングスケジューリング機能を追加する。これにより分散学習のワークフローが簡素化される。
  2. MLflowの導入

    • 機械学習のライフサイクル(前処理×モデル評価×デプロイ)は手作業が多くて統一性がない。これを統合化する取組み。
      • パラメータやメトリクス等のトラッキング
      • 管理(依存ライブラリ管理、バージョン間のトラックなど)
      • モデルのパッケージング
  3. Data Source API 2.0
  4. クエリ実行時の再最適化
    • クエリが完了した後の統計情報をもとに、実行計画を再最適化させる

github.com

software.intel.com

3. Cloud-Nativeなデータ分析基盤におけるPrestoの活用:廣瀬 智史(SmartNews, Inc.)

既に資料は公開されています。

speakerdeck.com

2014年当時は、Amazon S3上のデータをMapReduce処理してMongoDBに蓄積していた。課題としては、データを気軽に分析できる環境ではなかったこと。新しい集計処理が必要になる度にMapReduce処理を追加する必要があったし、新たな可視化ニーズの度にアプリケーションの修正が必要になっていたとのこと。

そこで、「Amazon S3 + Presto + Hive」の構成に変更。ETL/バッチ処理はHive(Hive metastoreのデータを参照)、リアルタイムデータ集計はPrestoを利用。これにより、ストレージとコンピューティングリソースを分離することができ、またSQLを書けば、誰でもデータ分析できるようになった。

また、利用用途ごとに要求が異なるため、クラスタを使い分けて利用している(例えば、広告配信はシビアな要求が求められるが、ニュース配信はそこまでではない)。これにより依存性を局所化しているが、その結果データが分散する状況にもなる。そこで複数のデータソースに対するリクエストを可能とする「Presto」をインタフェースとして利用し、この問題を解決している。 また、EMRではなくEC2上にPrestoクラスタを構築することで、デフォルトのPrestoには存在しないコネクターや、独自のファンクションの追加を行っている。Prestoは開発が盛んなので、最新版を試せる環境にしておきたいとのこと。

4. DataFrameとDatasetの内部をのぞいてみる:石崎 一明(日本アイ・ビー・エム

資料公開されています。個人的にとても面白かったです!!

www.slideshare.net

Sparkで実装する上で、RDDやDataFrameやDatasetなどの選択に迫られる。DataFrameはSQL由来なのでループ処理の記述が難しいが、一方DatasetはScala由来なので簡単に記述できる。ただし、同じ処理でもDatasetはDataFarmeと比較して処理が非常に遅い、という二者択一状態。機械学習アルゴリズムを記述する場合、ループ処理が書けないと結構大変なので、Datasetの処理性能改善を加えていっている、という話。Spark2.2以降でだいぶ改善されている模様。 Sparkの仕組みとして、DataFrameやDatasetは様々な最適化(Catalyst)の末、最終的にJavaのコードを生成する。PythonとかScalaのまま実行されるわけではない。それぞれ最適化の仕方が異なるので、処理性能に違いが生じる。 DatasetとRDDでは、現状は性能差があるため、SparkのMLアルゴリズムではほとんどRDDへの変換後に実行されているのが実情(?)。本来はRDDへの変換にオーバーヘッドコストがかかるため本当はやりたくない!でも現状はまだまだRDDがメインストリームということなのだろうか。

5. スキーマレスカラムナフォーマット「Yosegi」で実現するスキーマの柔軟性と処理性能を両立したログ収集システム:井島 洸二さん

資料公開されています。

www.slideshare.net

ヤフーで日々発生する多種多様なサービスのログは、リアルタイムに収集しHDFSに格納している。データを利用するデータサイエンス部門が試行錯誤を繰り返すために、ログの仕様変更(つまりスキーマの変更)が日々行われる(らしい)。

スキーマ定義には2つの方法がある。

  1. Schema on Read:利用時にスキーマを定義する
    • 収集時に制約が少ない/保存時の効率化が難しい
  2. Schema on write:保存時にスキーマを定義する
    • 収集時に制約が多い/保存時の効率化が容易

ヤフーでは、Schema on Readを採用。理由は多種多様なサービスからログが生成されるため、スキーマ定義のコストが大きいため。一般的には、JSONファイルなどが利用される。

一方で、カラムナフォーマットについても検討する必要がある。カラムナフォーマットは、データベースの分析用途に利用されるファイルフォーマットの1つ。大量データを扱う際に効率的に圧縮してストレージコストを下げたり、計算時に必要なデータだけを取り出して計算コストを小さくできる設計がされている。代表的なフォーマットにはORCやParquetがある。カラムナフォーマットへの変換には、事前のスキーマ定義が必要になる。

このように、多様なスキーマにはJSON、膨大なログ量にはカラムナフォーマットが選択肢としてあるが、スキーマの柔軟性と処理性能はトレードオフの関係にある。そこで、スキーマレスカラムナフォーマット「Yosegi」を開発したという話。スキーマの柔軟性と高い処理性能を両立しつつ、スキーマ管理が不要なログ収集システムを実現しているようである。YosegiはGithubでも公開されている。

github.com

5. Apache Kafkaって本当に大丈夫?~実際にいじめてみたのでお伝えします~:土橋 昌さん

正直、知見があふれまくってたので。資料公開をお待ちしています。この発表では、Kafkaの障害における様々な検証をしてくれています。

Kafkaは、データハブとして、ストリーム処理のパイプラインとして、そしてスケーラブルなメッセージングキューとして利用されるメッセージングシステムです。Consumer、Broker、Producerで構成され、さらにZookeeperを利用してHA構成を取りますが、それぞれのコンポーネントが故障した時に、Kafkaの挙動はどうなるのかを実際に各コンポーネントに障害を起こして検証しています。バージョンの違いでKafkaの構成は異なってくるため、一概にこの検証がそのまま役に立つわけではないと思いますが、検証結果や検証項目の考え方は非常に勉強になるものでした。

故障検証のサマリーとしては、公式ドキュメントに記載されたアーキテクチャから想像される挙動とおおむね合致するが、実際の挙動のうちZookeeperのアンサンブル故障と、データファイル(ログファイル)の異常については特に注意したほうが良いよ!という内容でした。

f:id:ishitonton:20190317212939p:plain f:id:ishitonton:20190317213007p:plain

ShakeDownを食らったMicrosoft Malwareコンペを振り返る

KaggleのMicrosoft Malware Predictionが終了しました。参加した皆さん大変お疲れ様でした。 これまでもつまみ食いはしつつも、今回初めてKaggleコンペに本格的に参加しました。少し期待していたのですが、Publicでソロ銅圏(150位)からPrivateで840位と大幅なShake Downを食らい悲しいし恥ずかしい。 一方で、Kaggleコンペに参加したことで多くの学び・教訓を得ることができました。失敗や経験を次につなげるためにも、本コンペを通じて学んだことを振り返っておきたいと思います。

技術的な学び

今回のコンペの特徴は下記であったと考えます。

  1. 大規模なデータ
  2. 訓練データとテストデータの分布が異なる
  3. (結果的に)テストのPublicデータとPrivateデータの分布が異なる

こういった特徴の中で出会った学びについて書いていきます。

メモリ載らない問題

大規模データであることから、私の環境ではDataFrameがメモリ上に載らない事案が発生し、メモリ節約の必要性が出てきました。そこら辺に関しては、自身もブログに記したほか、えちさんのブログで知ったreduce_mem_usage()関数でデータ型を最適化する等により対処をすることができました。

ishitonton.hatenablog.com

amalog.hateblo.jp

仮説検証サイクル遅くなる問題

Kaggleに限らず、いかに仮説検証を効率的に高速に回せるかが非常に重要だと思います。 今回のコンペが大規模データセットであることから、仮説検証サイクルが遅くなることに遭遇しました。より高速にサイクルを回すために、Feather形式での特徴量管理やデータの入出力する等のアイデアをもらい試しました。

amalog.hateblo.jp

訓練データとテストデータの分布違う問題

訓練/テストデータの分布が違う点に関しては、ディスカッションにも出ていましたが、私はAdversarial Varidationを試しました。訓練データとテストデータを判別する95%くらいの精度の2値判別モデルを構築。そのモデルを訓練データを対象に推論し、テストデータのProbavility Scoreを生成しました。テストデータの確度が高いと判別された訓練データを検証データとして、モデルの学習を行いました。

ただし、結果的に大幅なShakeDownを食らったことをみると、Adversarial Varidationのプロセスに何かしら問題があったか、テストデータの中でもPrivate/Publicデータの分布が想像以上に異なりPublicに過学習していたのか。いずれにしても自分の勉強不足以外のナニモノでもないですが、上位者の解法が出てきたらヒントを得たいと思います。 なお、Adversarial Varidationやそのほかvalidationの重要性については、u++さんのブログで勉強させていただきました。

upura.hatenablog.com

upura.hatenablog.com

特徴量生成について

今回自分は3つのモデルを組み合わせて最終的なsubmissionを生成していました。Non Tree Based Modelが1つとTree based Modelが2つです。これらのモデルのタイプに応じて、特徴量生成のケアや前処理方法は異なるため、改めて整理することが出来ました。前処理についてはCourseraのKaggleコースで勉強し、その内容の一部をアウトプットしました。

ishitonton.hatenablog.com

www.coursera.org

特徴量選択について

特徴量選択についてはかなり勉強不足で、今回の敗因の大きなウェイトを占めている気がします。 u++さんがブログに記載してくれたコルモゴロフ-スミルノフ検定を利用した特徴量選択とかを試したりしたが、私のモデルではモデル説明力が失われたように見え、残念ながら有意義な仮説検証に至りませんでした。

今後は『機械学習のための特徴量エンジニアリング』読んで勉強したいと思います。Adversarial ValidationでFeature Importanceがものすごく高い特徴量が何個かあったのだが、それ抜いたらスコア上がっただろうか。

upura.hatenablog.com

技術面以外の自身の内省

どこで満足するか

今回、自分は締切り1週間前の段階でソロ銀の状態にいました。その段階でかなり満足している自分がいたことを認識しています。その結果ラスト一週間でのsubmissionはかなり惰性的なものであり、全く進捗なく締め切りを迎えました。

一方で、トップ層では日本のKagglerの皆さんが最後までさらにスコアを挙げようと邁進していたことを横目で見ており、自身の精神面での未熟さを痛感しました。 どこで自身が満足するかは、Kaggleに限らず人生のあらゆる局面で自身に課せられる問いであり、仕事においてもプライベートにおいてもKaggleにおいても、この未熟さを改善したいと感じた次第です

学び多し犠牲もあり

KaggleのKernelやDiscussionを理解することで、多くの学びを得ることができました。結果よりこの学びの方が、自分の仕事にもポジティブな影響を与えてくれるかもしれない。 一方で、自分の性格上Kaggleを頑張ると他の様々な学びの機会を犠牲にしていることも理解しました。感覚的には、一時期ビットコインを購入して一攫千金を狙ったことがあるが、夜中も推移が気になり寝れなかった感覚に似ている。時に自身のライフサイクルを逸脱し、知的好奇心が一極集中。

その傾向を認識した上で、今後も参加したい!!

最後に

改めてDiscussionを見てみると、同じく大幅なShakeDownを食らっているolivierさんが、Conglatulationsというスレッドを立て上位者を祝福している。素晴らしい。自分も、自分がダメでも周りを称え、コミュニティに貢献できるスキルとマインドと懐の広さを持ちたいと思う次第です。

f:id:ishitonton:20190314191403p:plain
https://www.kaggle.com/c/microsoft-malware-prediction/discussion/83990

以上です。

モデリングのための特徴量の前処理について整理した

久しぶりのデータ分析関連の記事を書きたく、モデリングを行う上での特徴データの前処理について整理しました。本投稿は、下記courseraのKaggleコースの受講とその周辺情報のインプットを整理したものです。より詳細かつ正確な内容については受講してください。

www.coursera.org

目次

前処理の分類

データの前処理には様々な技法が存在するが、自身が利用する「予測モデルのタイプ」×「データ型」により、その処理や特徴量生成方法は大きく異なると認識している。

この文脈における教師あり学習の「予測モデルのタイプ」は、大きく次の2つに大別される。

  1. Tree Based Model
  2. Non Tree Based Model

Tree Based Modelは決定木やランダムフォレスト、AdaBoost等を、Non Tree Based Modelは線形モデルやKNN、Neural Network等を指している。

また、データセット上には、下記のような様々なデータ型が存在する。これらをモデルが識別可能な形式に処理する必要がある。

  1. Numeric(数値データ)
  2. Categorical(カテゴリカルデータ)
  3. Ordinal(順序付きデータ)
  4. Datetime(日付、時間)
  5. Coordinates(座標)

また、本投稿では割愛するが、データセット上には一般的に欠損値が存在する。欠損値もモデルによって処理方法が異なるために注意する必要があるし、そもそもデータセットには、分析者の意図しない/認識しえない範疇で、既に欠損処理された値が埋め込まれている可能性がある。これらを可視化し明らかにし、モデルに合わせてエンコーディングする必要性もある。

以降では、具体的な各データ型における前処理方法について、整理していく。

Numeric(数値)データ

Numericデータにおいて注意すべき1つに、Scaling(スケーリング)がある。Scalingとは、「特徴量の取りうる値の範囲(スケール)を変えること」をさす。例えば、体重と身長、価格と数量では、単位と値の範囲が異なる。特徴量間で極端に異なるスケールのデータセットのままでは、うまく学習できない可能性があり、スケールを揃える必要がある。一般的にTree Based ModelモデルではScalingに依存しないが、Non Tree Based Modelの場合には予測に失敗するか悪影響を及ぼす。

Scalingの影響に関して、Non Tree based Modelに含まれるKNNを利用した例を1つ挙げる。2つの数値データを特徴量としたデータセットにおいて、「オレンジのデータがAとBのどちらと同じグループに含まれるか」のクラス分類を考えてみる。データ間の距離(類似性)をユークリッド距離で計算する場合、左の図ではBとの距離が近くなるために、Bと同じグループに分類される。次に特徴量Xを100倍にしたとする。その結果オレンジのデータはAとの距離が近くなり、Aと同じグループに分類されるだろう。これは相対的に特徴量Xの影響力を肥大化させ、特徴量Yを無視することに繋がる。

f:id:ishitonton:20190223101652p:plain
KNN(Non Tree Based Model)でのクラス分類

逆に、特徴量Xにゼロを掛け合わせたらどうなるか。上記の例ではKNNは特徴量Xを無視することになる。以上はKNNの例だが、線形モデルでもNeural Networkでも勾配降下ベースの最適化に依存するモデルについては、適切なScalingがなされていない場合には、予測結果に悪い影響を与える可能性がある。

特徴量のScalingの方法はいくつか存在する。

  1. Min Max Scalar
  2. Standard Scalar
  3. Outliers(外れ値)への対処
  4. rank transformation
  5. log transformation/square transformation
1. Min Max Scalar

最も直感的かつ簡単なScalingの方法。全ての特徴量の値を同じスケールに変換することである。全ての値から最小値を引き、MinとMaxの差で割る。その結果、値は0から1となる。 デメリットは、0から1の範囲に値を収めるため、標準偏差が小さくなり、外れ値の影響が抑制されること。

SklearnのMinMaxScalerでは、次の変換により行われる。

X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))
X_scaled = X_std * (max - min) + min

なお、sklearnのドキュメント内の説明では、This transformation is often used as an alternative to zero mean, unit variance scaling.と記載があり、次に挙げるStandard Scalarの代替手段として利用されるのだろうか。

sklearn.preprocessing.MinMaxScaler — scikit-learn 0.20.2 documentation

2. Standard Scalar

この変換処理では、平均0、分散1の標準化された分布を得ることができる。標準化(standardization)と同義。まず、平均値を引くことで0前後の値とする。次に、値を標準偏差で除算して、結果の分布が平均0、標準偏差1の標準となるようにする変換方法である。代表的なパッケージとしてはsklearn.preprocessing.StandardScalerがある。

ここでも外れ値には要注意。Standard Scalerでは、平均値と標準偏差を計算する際に外れ値が影響を及ぼし、特徴量のrangeが狭まります。特に、各特徴量の外れ値の大きさが異なるため、各特徴量の変換データの広がりは大きく異なる可能性が出てくる。このように、外れ値が存在する場合にバランスの取れたScalingが保証できない

下記記事も参考にしました。

python - Difference between Standard scaler and MinMaxScaler - Stack Overflow

Standard Scaler v Min Max Scaler in Machine Learning - All Things Software, Data Science and Technology

Feature Scalingはなぜ必要? - Qiita

3. Outliers(外れ値)への対処

Min Max ScalarやStandard Scalarにおいても、外れ値の影響について述べたが、特に線形モデルでは、外れ値の有無が予測精度に大きく影響を与える。これらに対処するために、下限と上限を決め、2つの選択された値の間で特徴量を切り取る方法などがとられる。Kaggleコース内では、特徴量の分布の中から1%~99%のデータを切り取る方法が提案されている。

Scipyのwinsorizationモジュールを利用すると、データから切り取ったデータを返してくれる。

scipy.stats.mstats.winsorize — SciPy v0.14.0 Reference Guide

4. rank transformation

特徴量内の各値の間隔が等しくなるように、数値の順序を保って数字を振り直す方法。例えば、外れ値が存在する場合には、外れ値を他の値に近づける効果があるためMin Max Scalerよりも有効な手段となる。チキチキ外れ値の処理をやっている時間がない場合には有益。

ただし、テストデータへの適用時には注意が必要。事前にTrainデータとTestデータを連結してrank transformationを行うか、もしくが特徴量とランク値のmapping情報をストアしておく必要がある。

rank transformationには、scipyにはrankdataモジュールが提供されている。値が等しいときに、どのようにランクを割り当てるか、いくつかオプションが用意されている。

>>> from scipy.stats import rankdata
>>> rankdata([0, 2, 3, 2])
array([ 1. ,  2.5,  4. ,  2.5])
>>> rankdata([0, 2, 3, 2], method='min')
array([ 1.,  2.,  4.,  2.])
>>> rankdata([0, 2, 3, 2], method='max')
array([ 1.,  3.,  4.,  3.])
>>> rankdata([0, 2, 3, 2], method='dense')
array([ 1.,  2.,  3.,  2.])
>>> rankdata([0, 2, 3, 2], method='ordinal')
array([ 1.,  2.,  4.,  3.])

scipy.stats.rankdata — SciPy v0.16.1 Reference Guide

5. log transformation/square root transformation

多くのモデルは、正規分布を仮定していることが多いので、対数変換により正規分布に近似させる。データを正規分布に従わせる以外にも、外れ値が含まれるデータの分散を小さくするためにも使われる。すなわち、対数変換により極端に大きすぎる外れ値を平均値に近づける。これに伴い、ゼロに近い値をもう少し区別しやすくなる。特徴量の平方根を取る方法も同様の効果が見込める可能性がある。Non Tree Based Modelの中でも、特にNeural Networkで有効。

なお、下記のブログでは、場合によっては分散が増大するケースがあることも書かれている。 yolo-kiyoshi.com

Categorical / Ordinalデータ

Categoricalデータとは、統計用語集によると、質的データと同義で、名義尺度や順序尺度のデータをさす。Ordinal(順序付き)データは、Order Categoricalデータとも呼ばれ、Categoricalデータに含まれる。 Categoricalデータは、性別(男性/女性)や出身都道府県(北海道/青森県岩手県...)、チケットのクラス(エコノミークラス/ビジネスクラス/ファーストクラス)などが該当する。ここでチケットのクラスは、一般的に大小には意味があるが、間隔には意味がないデータであり、Ordinalデータに含まれるだろう。すなわち、チケットのクラスがNumericデータである場合、「エコノミー(1)とビジネス(2)」の差異と「ビジネス(2)とファースト(3)」の差異は等しいと解釈される。Ordinalデータでは、どちらの差異が大きいかはわからない。

Categoricalデータの一般的なエンコード方法は下記のとおりです。

  1. Label Encoding
  2. Frequency Encoding
  3. One-Hot Encoding

上記以外にも、最近ではTarget Encodingなどの手法もKaggleではよく利用されている。

1. Label Encoding

Ordinal featureの最もシンプルなエンコード方法であり、この特徴量のユニークな値を異なる数値にマッピングする方法である。Ordinalデータに限らず、Label EncodingはKaggleのCompetitionでのベースモデルとして、とりあえずCategoricalデータを全てLabel EncodingしているKernelをよく目にする。それほど、最も簡単な方法の1つである。Label EncodingはTree Based Modelでうまく作用するが、逆にNon Tree Based Modelでは効果的ではない

Label Encodingのラベル方法には、次の2通りがある。

  1. alphabetical order
  2. sorted order

alphabetical orderは、SklearnのLabel Encoderモジュールのデフォルトである。すなわち、アルファベットや数字の順序に準拠し、ラベルを振り直す。

>>> from sklearn import preprocessing
>>> le = preprocessing.LabelEncoder()
>>> le.fit([1, 2, 2, 6])
LabelEncoder()
>>> le.classes_
array([1, 2, 6])
>>> le.transform([1, 1, 2, 6]) 
array([0, 0, 1, 2]...)

>>> le = preprocessing.LabelEncoder()
>>> le.fit(["paris", "paris", "tokyo", "amsterdam"])
LabelEncoder()
>>> list(le.classes_)
['amsterdam', 'paris', 'tokyo']
>>> le.transform(["tokyo", "tokyo", "paris"]) 
array([2, 2, 1]...)

sorted orderはpandasのfactorizedモジュールで実装される。値が出現する順序でラベル付けを行う。 既にデータが何かしら意味ある方法でソートされている場合に有効となる。

>>> import pandas as pd
>>> labels, uniques = pd.factorize(['b', 'b', 'a', 'c', 'b'])
>>> labels
array([0, 0, 1, 2, 0])
2. Frequency Encoding

カテゴリーが出現する頻度にデータを置き換えるエンコード方法であり、Tree Based Modelで有効。カテゴリーの頻度がTargetデータとの間に相関がある場合には、線形モデルにおいても効果がある。

注意すべき点としては、仮に複数のカテゴリーで同じ頻度を持つ場合、それらの値を持つデータを区別をすることができないため問題になる可能性がある。この場合の対処として、下記サイトにはwill need to change it to ranked frequency encodingと記載されている。当初、ranked frequency encodingとはよくわからなかったが、恐らくFrequency Encodingとは別に、Label Encodingの特徴量も用意すれば、Tree Based Modelであれば分割可能だということだと思う。

### FREQUENCY ENCODING

# size of each category
encoding = titanic.groupby('Embarked').size()
# get frequency of each category
encoding = encoding/len(titanic)
titanic['enc'] = titanic.Embarked.map(encoding)

# if categories have same frequency it can be an issue
# will need to change it to ranked frequency encoding
from scipy.stats import rankdata

4. Feature Preprocessing & Generation — Data Science 0.1 documentation

3. One-Hot Encoding

One Hot Encodingについては、カテゴリー変数をアルゴリズムが学習しやすいように0と1で表現する方法。エンコード方法には、sklearnのOneHotEncoderモジュールやPandasのget_dummiesメソッド等がある。

One-Hot Encodingは既に最大値1、最小値0にスケーリングされており、Non Tree Based Modelに適用する場合に有効。One-Hot Encodingは、カテゴリー数だけバイナリデータが特徴量として生成される。これは1つの特徴量を効率的に分類しようとするTree Based Modelでの分類を困難にする

次のブログで、Tree Based ModelでOne-Hot-Encodingを実行したプロセスの図が描かれているが、直感的に効率が悪いことが確認できると思う。

f:id:ishitonton:20190224173803p:plain
Visiting: Categorical Features and Encoding in Decision Trees

Visiting: Categorical Features and Encoding in Decision Trees

Categoricalデータにユニーク値が多く含まれている場合には注意が必要である。One-hot Encodingによって、ほとんどゼロの値を取る大量の特徴量が生成される。これらのデータを効率的に利用するために、Sparse Matrixが有用。RAM上に、すべてをStoreせずに、Non-Zeroの要素だけを保存し、メモリを節約できる。目安としては、カテゴリー内の全ての値の半分以上がゼロであるときに有用。XGBoost、LightGBM、sklearnなど、一般的なライブラリのほとんどでSparse Matrixは利用可能。

Lasso on dense and sparse data — scikit-learn 0.20.2 documentation

Sparse matrices (scipy.sparse) — SciPy v1.2.1 Reference Guide

Sparse Matrixを用いたLightGBMの例

LightGBM. Baseline Model Using Sparse Matrix | Kaggle

Datatimeデータ

Datetimeデータの特徴量生成方法には、大きく2つの方法がある。

  1. 期間内のある瞬間の情報
  2. 特定のイベントからの経過時間
1. 期間内のある瞬間の情報

ある期間(1カ月/1年)における週、秒、分、時、日といったデータを追加することができる。これらは、データ内の繰り返しのパターンを捉えるのに有効。例えば、毎月20日は給料日である場合、その繰り返しの情報は、支払いや売上の予測に有効かもしれない。

2. 特定のイベントからの経過時間

ある瞬間からの経過時間に関する情報である。その「ある瞬間」とは、固定の場合と変動の場合がある。前者の例でいえば、「2019年1月1日から経過した日数」が特徴量となる。後者の場合、「日曜からの経過日数」や「前回のセールからの経過日数」などレコードに依存する情報となる。

また、複数のdatetimeデータを保持してている場合には、datetimeデータ同士の差分情報を特徴量として生成することも有効な場合がある。

Coordinatesデータ

座標データは、これまで挑戦したことがないので簡易的な記述とさせていただくが、特徴量生成方法には次の2つが一般的。

  1. 距離の計算
  2. 統計データの利用
1. 距離の計算

仮に地図上に何か重要な地点が存在する場合に、その重要地点との距離を計算し特徴量とする方法である。例えば、もし建物の位置に関する追加データがある場合には、そこから最も近い店舗の距離を計算し特徴量として追加できる。 追加データがない場合にも、様々な工夫により、特徴を生成することが可能である。以下に例を挙げる。

  • 対象のエリアをさらにサブエリアに分割(クラスタリングやグリッド線での分割)し、各サブエリア内で最も高価な建物を代表点と定める。そして代表点までの距離を計算し特徴量とする。
  • サブエリアの中心地点からの距離を計算する。
2. 統計データの利用

オブジェクト周辺エリアの統計データを利用することも有効である。例えば、そのエリアの平均家賃の計算など。

おわりに

もし間違っている箇所があればご指摘下さい。長くなってしまったが、欠損値についてもいつか整理したい。

チームの暗黙の了解をWorking Agreementとして定めた話

自分では当たり前と思っていたけど、隣のメンバーは知らなかった・違う認識を持っていた。仕事をしていてそんな経験はありませんか。

私は、個々人が創造性と情熱をもって、自律的に働ける組織こそが、最大限のパフォーマンスを発揮できると考えています。そのための環境作りの1つとして、我々が取り組んでいるWorking Agreementについて書きたいと思います。

Working Agreementとは

Working Agreementとネットで検索すると、おそらく色々な記事が出てくるかと思いますが、私は次のように定義しています。

共に働く上での非公式の合意事項

例えば、クライアントとの取引や各従業員の雇用等の関係性については、契約書があり文書で明文化されており、私は「公式」的な合意事項のくくりに含んでいます。

一方で、組織に属しチームとして共に働く(=生活する)上中で、特に書面で合意したわけでもないし、雇用契約条項に書かれているわけではないけど、いつの間にか「暗黙の了解」として皆が従っている様々な決まりごとが出てきます。 例えば、、(今考えている)

  • 週に1回、チームの誰かがルンバを回す
  • 喫煙者は、毎回ファブリーズをする
  • 生ごみはこっちのゴミ箱に捨てずにあっちのゴミ箱に捨てる
  • 帰宅時は、メンバーに一声かけよう。
  • 空調の調整方法について
  • とかとか。

こういったものを我々は「非公式の合意事項」と考えており、どちらかというと仕事の内容ではなく職場環境や生活する上での合意事項を集めて合意した文書がWorking Agreementです。

Working Agreementを決めるべき理由がいくつかあります。

  • チームメンバーが入れ替わるリスク
  • 新メンバーのスムーズなジョイン
  • メンバー間、お客様との不必要な衝突や仲たがいを避ける
  • 直接言いにくいこともある
  • セキュリティリスク

暗黙の了解事項は、個人の頭の中に知識として蓄えられているため、チームメンバーの離脱等、入れ替わりがあった際に、チームとして知識を消失するリスクが発生します。また、新しいメンバーがチームにジョインした際に、スムーズにチームに参加できるメリットがあります。メンバー各人が考えている「当たり前」が違うと、それは時として、メンバー間の仲たがいが発生するリスクにつながりますし、セキュリティリスクにつながることもあります。

どのように作り運用するか。

Working Agreemnetはどのように作成すべきでしょうか。私たちのチームでは次のようなプロセスで作成し、現在も運用しています。

  • 最初にチーム全員で、「暗黙の了解」となっている非公式な合意事項を洗い出します。
  • 集約した項目の中には、Working Agreementに含むべきではない項目が出てきます。例えば上述のような契約事項は「公式的」なものですから、Working Agreementには含めない、という考え方を私たちは取っています。これらをメンバー全員の合意のもと精査する。
  • 集約した項目の中には、各メンバーによって認識が違うものが必ず出てきます。これらをメンバー全員で1項目ずつ擦り合わせを行っていきます。
  • 作成したWroking Agreementのテキストは、プロジェクト管理ツールのWiki等に展開し、誰もがいつでも確認できるようにします。

新しいメンバーが入ってきたときは、まずチームの働く上での合意事項としてWorking Agreementを読んでもらいます。また、働いている中で、暗黙の了解は増えていきますし変わっていきます。Working Agreementは働く中で柔軟に追加・修正していくべきものと考えていますが、個人的に編集するのではなく、MTG等のメンバーが集う場で合意を取って修正していきます。

また、Working Agreementを破った場合、決してその人を非難するべきではありません。誰だって失念することはありますし、間違いを犯すこともあります。罪人の様に扱うのではなく、こういったタイミングを会話の契機として、チーム内のコミュニケーションや関係性を向上させていくことだと考えています。

現在我々のチームでは、100個近くの項目が存在します。是非皆さんも試してみてください。