console.blog(self);

技術、読んだ本、いろいろ。

Cloud Natural Language APIを使ってみた、というか自然言語処理について調べてみた

12/24に書いているけど、Goodpatch Advent Calendar 2017の3日目の記事です!いろいろあるよね!

Cloud Natural Language APIはこれ。

最近ハードに英語を勉強していたら、品詞とかに詳しくなった。英語の主な品詞はこんな感じ。

  • 名詞
  • 代名詞
  • 動詞
  • 形容詞
  • 副詞
  • 前置詞
  • 接続詞
  • 間投詞

こちらが分かりやすかった。以下の語尾の部分などは記事からの引用。

名詞によくある語尾

  • -tion: information(情報)
  • -sion: decision (意思決定)
  • -ity: identity (アイデンティティ)
  • -ty: beauty (美しさ)
  • -th: health (健康)
  • -ment: supplement (サプリメント)
  • -ness: kindness (やさしさ)
  • -ance: announce (アナウンス)
  • -ence: entrance (入り口)
  • -cy: policy (ポリシー)
  • -er: employer (雇用主)
  • -or: doctor (博士)
  • -ee: employee (被雇用者)

動詞によくある語尾

  • -en: broaden (広げる)
  • -fy: notify (知らせる)
  • -ize: prioritize (優先する)
  • en(語頭): enpower (力を与える)

形容詞によくある語尾

  • -able/-ible: possible(可能な), accessible(アクセス可能な)
  • -al: financial(財務の)
  • -ant: brilliant(素晴らしい)
  • -ent: independent(独立した)
  • -ar: similar(似た)
  • -ed: limited(限定的な)
  • -ful: successful(成功した)
  • -ic/-ical: basic(基本的な), economical(経済的な)
  • -ive: massive(巨大な), active(活動的な)
  • -less: useless(使えない), helpless(希望のない)
  • -ory: contributory(一因となる)
  • -ous: enormous(巨大な)
  • -y: busy(忙しい)

副詞によくある語尾

副詞は、形容詞の語尾に-lyをつけるだけ

  • financial+”-ly”=financially (財務に)

ただ名詞に ly がついていると形容詞になる。

  • costly 形容詞

Cloud Natural Language API

こんなの人間が判断するのだるいので。

構文解析

トークンと文の抽出、品詞(PoS)の特定、各文の係り受け解析ツリーの作成が可能です。

エンティティ認識

エンティティとラベル(人、組織、場所、イベント、商品、メディアなど)を特定できます。

感情分析

テキストのブロック内で示されている全体的な感情を読み取ることができます。

コンテンツの分類

事前定義された 700 以上のカテゴリでドキュメントを分類できます。

多言語

さまざまな言語のテキストを簡単に分析できます。英語、スペイン語、日本語、中国語(簡体字および繁体字)、フランス語、ドイツ語、イタリア語、韓国語、ポルトガル語に対応しています。

自然言語処理

そもそも、自然言語処理とは。

自然言語処理(しぜんげんごしょり、英語: natural language processing、略称:NLP)は、人間が日常的に使っている自然言語をコンピュータに処理させる一連の技術であり、人工知能言語学の一分野である。

自然言語処理 - Wikipedia

形態素解析

文を形態素に分割する。

形態素解析(けいたいそかいせき、Morphological Analysis)とは、文法的な情報の注記の無い自然言語のテキストデータ(文)から、対象言語の文法や、辞書と呼ばれる単語の品詞等の情報にもとづき、形態素(Morpheme, おおまかにいえば、言語で意味を持つ最小単位)の列に分割し、それぞれの形態素の品詞等を判別する作業である。

形態素解析 - Wikipedia

形態素とは。

形態素(けいたいそ、英: morpheme)とは、言語学の用語で、意味をもつ表現要素の最小単位。ある言語においてそれ以上分解したら意味をなさなくなるところまで分割して抽出された、音素のまとまりの1つ1つを指す。形態素の一般的な性質や、形態素間の結びつきなどを明らかにする言語学の領域は、形態論と呼ばれる。

形態素 - Wikipedia

日本語はいろいろ大変。

わかち書き(わかちがき)とは、文章において語の区切りに空白を挟んで記述することである。分かち書き・別ち書きとも表記する。

わかち書き - Wikipedia

日本語形態素解析の裏側を覗く!MeCab はどのように形態素解析しているか - クックパッド開発者ブログ

構文解析

形態素間の関連を分析する。

構文解析(こうぶんかいせき、syntactic analysis あるいは parse)とは、文章、具体的にはマークアップなどの注記の入っていないベタの文字列を、自然言語であれば形態素に切分け、さらにその間の関連(修飾-被修飾など)といったような、統語論的(構文論的)な関係を図式化するなどして明確にする(解析する)手続きである。

構文解析 - Wikipedia

語義の曖昧性解消

いろんな意味があるので、それを解消する。

語義の曖昧性解消(ごぎのあいまいせいかいしょう、英語: Word-sense disambiguation)とは自然言語処理において、文中のある単語に出会ったとき、その単語がどの語義をあらわしているのかを判断する過程のこと。語義識別、語義判別、語義確定などともいう。

語義の曖昧性解消 - Wikipedia

やばい。「のめり込みそうである」って語義が来年の広辞苑の改訂で追加される。

①身に危険が迫るさま。あぶない。 「 - ・いぞ,逃げろ」 ②不都合が予想される。 「この成績では-・いな」 ③若者言葉で,すごい。自身の心情が,ひどく揺さぶられている様子についていう。 「この曲,-・いよ」 〔若者言葉では「格好良い」を意味する肯定的な文脈から,「困った」を意味する否定的文脈まで,広く感動詞的に用いられる〕

やばいとは - 日本語表現辞典 Weblio辞書

照応解析

「あれ」とかが何を示すのか推定する。

照応解析(しょうおうかいせき、英: reference resolution)とは、照応詞(代名詞や指示詞など)の指示対象を推定したり、省略された名詞句(ゼロ代名詞)を補完する処理のこと。照応は文と文の間にまたがった構造なので、照応解析は談話解析の一種である。

照応解析 - Wikipedia

Universal Dependencies

形態論と依存関係ツリー

形態論とは、単語の内部構造と、単語の形成および変更の仕組みについて研究したものです。形態論は、1 つの単語の構成要素(語幹、語素、接頭辞、接尾辞など)がどのように配置または変更されて、さまざまな意味を持つようになるかに注目しています。Natural Language API は、提供された単語について、形態素解析を利用して文法情報を推測します。

形態論は構文とは別のものであることに注意してください(相互に影響し合うことはあります)。たとえば、英語の未来形は「I will get my umbrella」のように、動詞の前に単語「will」を付加することで表現されます。一方、形態論的には「will」も「get」も単語自体は変化していないので、単語自体が未来形を示しているわけではなく、未来形は構文規則で示されています。ただし、言語によっては単語を直接変更して未来形動詞とするものもあります(数多くあります)。

https://cloud.google.com/natural-language/docs/morphology?hl=ja

Universal Dependencies

Universal Dependencies (UD) is a framework for cross-linguistically consistent grammatical annotation and an open community effort with over 200 contributors producing more than 100 treebanks in over 60 languages.

http://universaldependencies.org/

つかってみた

構文解析してみた。

This is really a good pen.

f:id:sadah:20171224111918p:plain

APIたたくだけだとこんな感じ。

sentences:<text:<content:"This is really a good pen." > >

tokens:<
  text:<content:"This" >
  part_of_speech:<tag:DET number:SINGULAR >
  dependency_edge:<head_token_index:1 label:NSUBJ >
  lemma:"This"
> 

tokens:<
  text:<content:"is" begin_offset:5 > 
  part_of_speech:<tag:VERB mood:INDICATIVE number:SINGULAR person:THIRD tense:PRESENT >
  dependency_edge:<head_token_index:1 label:ROOT > 
  lemma:"be"
> 

tokens:<
  text:<content:"really" begin_offset:8 > 
  part_of_speech:<tag:ADV > 
  dependency_edge:<head_token_index:1 label:ADVMOD > 
  lemma:"really"
> 

tokens:<
  text:<content:"a" begin_offset:15 > 
  part_of_speech:<tag:DET > 
  dependency_edge:<head_token_index:5 label:DET > 
  lemma:"a"
> 

tokens:<
  text:<content:"good" begin_offset:17 >
  part_of_speech:<tag:ADJ >
  dependency_edge:<head_token_index:5 label:AMOD >
  lemma:"good"
> 

tokens:<
  text:<content:"pen" begin_offset:22 > 
  part_of_speech:<tag:NOUN number:SINGULAR > 
  dependency_edge:<head_token_index:1 label:ATTR > 
  lemma:"pen"
> 

tokens:<
  text:<content:"." begin_offset:25 > 
  part_of_speech:<tag:PUNCT > 
  dependency_edge:<head_token_index:1 label:P > 
  lemma:"."
>

document_sentiment:<> language:"en" 

そのままだとさっぱりわからないので、頑張って日本語にした。

package main

import (
    language "cloud.google.com/go/language/apiv1"
    "fmt"
    "golang.org/x/net/context"
    languagepb "google.golang.org/genproto/googleapis/cloud/language/v1"
    "log"
    "strings"
)

func main() {
    ctx := context.Background()

    // Creates a client.
    client, err := language.NewClient(ctx)
    if err != nil {
        log.Fatalf("Failed to create client: %v", err)
    }

    // Sets the text to analyze.
    text := "This is really a good pen."
    //text := "At the end of the ball, Kennedy spoke to thank Sinatra on the festivities and his support of the Democratic Party throughout his life and the 1960 campaign, adding 'The happy relationship between the arts and politics which has characterized our long history I think reached culmination tonight.'"
    annotateTextResponse, _ := analyzeSyntax(ctx, client, text)
    sentences := annotateTextResponse.Sentences
    tokens := annotateTextResponse.Tokens

    for _, sentence := range sentences {
        fmt.Printf("%v\n\n", sentence)
    }

    for _, token := range tokens {
        fmt.Printf("%v\n", token.Text)
        fmt.Printf("%v\n", replacePartOfSpeech(fmt.Sprintf("%v", token.PartOfSpeech)))
        fmt.Printf("%v\n", token.DependencyEdge)
        fmt.Printf("\n")
    }
}

func analyzeSyntax(ctx context.Context, client *language.Client, text string) (*languagepb.AnnotateTextResponse, error) {
    return client.AnnotateText(ctx, &languagepb.AnnotateTextRequest{
        Document: &languagepb.Document{
            Source: &languagepb.Document_Content{
                Content: text,
            },
            Type: languagepb.Document_PLAIN_TEXT,
        },
        Features: &languagepb.AnnotateTextRequest_Features{
            ExtractSyntax: true,
        },
        EncodingType: languagepb.EncodingType_UTF8,
    })
}

// https://cloud.google.com/natural-language/docs/reference/rest/v1beta2/Token?hl=ja#Tag
func replacePartOfSpeech(str string) string {
    oldnewTag := []string{
        "NOUN", "名詞(一般名詞 or 固有名詞)",
        "VERB", "動詞",
        "ADJ", "形容詞",
        "ADV", "副詞",
        "PRON", "代名詞",
        "CONJ", "接続詞",
        "DET", "限定詞",
        "ADP", "接置詞",
        "UNKNOWN", "不明",
        "NUM", "数詞",
        "PRT", "接辞",
        "AFFIX", "接辞?",
        "PUNCT", "句読点",
        "X", "その他",
    }
    oldnewCase := []string{
        "CASE_UNKNOWN", "格不明",
        "ACCUSATIVE", "対格(直接目的語)",
        "ADVERBIAL", "副詞(形容詞の副詞形)",
        "COMPLEMENTIVE", "補語",
        "DATIVE", "与格(間接目的語または直接目的語)",
        "GENITIVE", "属格(所有格)",
        "INSTRUMENTAL", "具格(名詞が行為の手段であるかどうか)",
        "LOCATIVE", "処格(場所を推測する単語の使用)",
        "NOMINATIVE", "主格(動詞の主語)",
        "OBLIQUE", "限定的用法(動詞または前置詞に対する目的語)",
        "PARTITIVE", "部分詞",
        "PREPOSITIONAL", "前置詞の目的語",
        "REFLEXIVE_CASE", "再帰格",
        "RELATIVE_CASE", "動詞または形容詞と名詞を結びつける関係詞節の補部",
        "VOCATIVE", "呼格(相手に呼びかけるときに使用する名詞)",
    }
    oldnewPerson := []string{
        "PERSON_UNKNOWN", "人称不明",
        "FIRST", "一人称",
        "SECOND", "二人称",
        "THIRD", "三人称",
        "REFLEXIVE_PERSON", "再帰代名詞",
    }
    oldnewNumber := []string{
        "NUMBER_UNKNOWN", "数不明",
        "SINGULAR", "単数",
        "PLURAL", "複数",
        "DUAL", "2数",
    }
    oldnewTense := []string{
        "TENSE_UNKNOWN", "時制不明",
        "CONDITIONAL_TENSE", "条件法",
        "FUTURE", "未来形",
        "PAST", "過去形",
        "PRESENT", "現在形",
        "IMPERFECT", "過去進行形",
        "PLUPERFECT", "過去完了形",
    }
    oldnewAspect := []string{
        "ASPECT_UNKNOWN", "相不明",
        "PERFECTIVE", "完了相",
        "IMPERFECTIVE", "未完了相",
        "PROGRESSIVE", "進行相",
    }
    oldnewMood := []string{
        "MOOD_UNKNOWN", "法不明",
        "CONDITIONAL_MOOD", "条件法",
        "IMPERATIVE", "命令法",
        "INDICATIVE", "現実法",
        "INTERROGATIVE", "疑問法",
        "JUSSIVE", "命令法",
        "SUBJUNCTIVE", "接続法",
    }
    oldnewProper := []string{
        "PROPER_UNKNOWN", "PROPER不明",
        "PROPER", "固有名詞の一部",
        "NOT_PROPER", "固有名詞の一部ではない",
    }
    oldnew := append(oldnewTag, oldnewCase...)
    oldnew = append(oldnew, oldnewPerson...)
    oldnew = append(oldnew, oldnewNumber...)
    oldnew = append(oldnew, oldnewTense...)
    oldnew = append(oldnew, oldnewAspect...)
    oldnew = append(oldnew, oldnewMood...)
    oldnew = append(oldnew, oldnewProper...)
    r := strings.NewReplacer(oldnew...)
    return r.Replace(str)
}

こんな出力になる。

text:<content:"This is really a good pen." > 

content:"This" 
tag:限定詞 number:単数 
head_token_index:1 label:NSUBJ 

content:"is" begin_offset:5 
tag:動詞 mood:現実法 number:単数 person:三人称 tense:現在形 
head_token_index:1 label:ROOT 

content:"really" begin_offset:8 
tag:副詞 
head_token_index:1 label:ADVMOD 

content:"a" begin_offset:15 
tag:限定詞 
head_token_index:5 label:DET 

content:"good" begin_offset:17 
tag:形容詞 
head_token_index:5 label:AMOD 

content:"pen" begin_offset:22 
tag:名詞(一般名詞 or 固有名詞) number:単数 
head_token_index:1 label:ATTR 

content:"." begin_offset:25 
tag:句読点 
head_token_index:1 label:P 

f:id:sadah:20171224111949p:plain

nsubjとかを調べてみると、こんな感じのことが書いてあった。むずい。

nsubj: nominal subject:

nsubjは節の構文的な主語である名詞節を示す。この関係のガバナーは常に動詞とは限らない。もし動詞が継動詞(copular verb)である場合、その節のルート(根)はその継動詞の補語になる。

attr: attribute:

be動詞やseem、appear、becomeなどのようにイコールの関係で結ぶ動詞(これを継詞、連結詞などと呼ぶ)に対して、それの補語。 たとえば   "What is that?"   attr (is, What)

advmod: adverbial modifier:

ある語に対するadvmodは、(節でない)RBかADVPで、その語の意味を修飾する。 たとえば   "Genetically modied food"   advmod(modied, genetically)   "less often"   advmod(often, less)

det: determiner: determiner

はNPのヘッドとそれのdeterminerとの関係を示す。たとえば   "The man is here"   det(man, the)

amod: adjectival modifier:

NPに対する形容的な句で、NPの意味を修飾する。たとえば   "Sam eats red meat"   amod(meat, red)

punct: punctuation:

punctは、節の句読点のうち、もしその句読点がtyped dependencyの中で保持されているなら、それを表す。但しデフォルトでは、句読点では出力に保持されていない。   "Go home!"   punct(Go, !)


まとめ

自然言語処理言語学は違う。真面目に言語学に取り組むよりは、英語勉強したほうが楽。

参考文献

Cloud Natural Language API

Universal Dependencies

形態素解析 / 言語学

その他

36歳になった

35歳になった直後から、想像もしていなかったことが次々と起きて、けっこう大変だった。とはいえなんとか乗り越えた。

51%のメリットと49%のデメリットがあるような判断を、立て続けにしなくてはならなかった。どちらを選んでも同じくらい大変だったりするけど、最善だと思う決断を行っていかなくてはならなかった。どちらを選んでもデメリットがあるしストレスフルだけど、それでもできるかぎり考えて、ひとつひとつをちゃんと選んできた。でも判断は手段であって目的ではない。成果をださなくてはいけない。

そんな環境に身を置いて、学ぶことがたくさんあった。ただ去年やりたかったことがあまりできず、図らずも35歳は守りの1年になってしまった。レイモンド・チャンドラーのプレイバックの一節が印象的(多くの人にとって印象的だろうけど)で、よく思い出す。

If I wasn’t hard, I wouldn’t be alive. If I couldn’t ever be gentle, I wouldn’t deserve to be alive.

Playback - Raymond Chandler

36歳はもっと攻めていきたい。とはいえ、また瀬戸内行ってゆっくりしたいな、とも思う。ちゃんとバランスとりながら、よい選択をしていきたい。

エンジニアの評価制度について

Goodpatch Advent Calendar 2016 25日目の記事です。

「エンジニア向け評価制度」とは、技術やスキルなどの側面を評価するための制度という意味合い。いまエンジニア向けの評価制度を作っていて、いろいろな会社のエンジニア向け評価制度について調べてみた。

大別すると、こんな感じ。

  • そもそも評価制度がない
  • エンジニア向け評価制度がない
  • エンジニア向け評価制度がある

そもそも評価制度がない

時雨堂やソニックガーデンには評価制度がない。

こういった考え方は、たしかになーと思う。

良い悪いを短期的に見ないからです。短期的に評価すると、短期的な視線で仕事をしちゃうじゃないですか? 一番イヤなのは、チームで助け合って働くのが大事なのに、“自分の評価を考えると、この人を助けている場合じゃない”となってしまうこと。そうなるとチームワークが崩壊します。だから短期的な評価はやめました。

スペシャリストな人が多くて、社員を増やす予定がなければ、こういったやり方がよさそう。ある程度以上の規模になると、評価制度を導入するメリットもありそう。

エンジニア向け評価制度がない

エンジニア向け評価制度がない会社もたくさんあると思うけど、明示的に持たない会社ってけっこう珍しい気がする。

― そんな理想の像がある中で、エンジニアの評価軸はどのように定めてらっしゃるんですか。

特別、エンジニアだけの評価軸って明文化されてないんですよ。エンジニアも、デザイナーも、皆「いい人をつくる」という経営理念で評価されます。エンジニアである前に、スタートトゥデイのメンバーだから、いい人をつくれると判断された人がステップアップしていくんです。

エンジニア向け評価制度がある

いろんな会社で導入されていて、参考になる。特にVoyageとペパボはいろいろな情報が公開されている。

Voyage

VOYAGE GROUPのエンジニア評価あれこれ。

こういった軸の話しとか、とても参考になる。

  1. サービスや事業を理解しているか(そもそもサービスや事業への理解が浅いと見当違いのものを作ってしまう)
  2. プロジェクトの要件や制約条件を理解しているか(プロジェクトには要件や制約条件がつきもの。これを明確に定義して作ることも欠かせない)
  3. 可用性(24時間365日動くシステムを作るために単一障害点をなくしているか,障害が起こったときに復旧・検知しやすいようになっているか)
  4. 性能(きちんと性能が出る設計か,どこかで詰まるような設計になっていないか)
  5. セキュリティ(セキュリティは堅牢か,昨今サービス提供する上では欠かせない指標)
  6. 変更容易性(作ったものは1回出して終わりではない,フィードバックを受けてどんどん改善していけるよう変更容易な設計・実装になっているか)
  7. テスト容易性(プロジェクトの制約によっては品質に時間をかけるのが難しいことも。テストが簡単にでき,プロデューサー含め専門職以外も実施しやすいよう配慮されているか)

第6回 VOYAGE GROUP執行役員CTO小賀昌法氏に訊く(後編)―クリエイティブ職向けに考え抜かれた育成・評価の仕組み:Webクリエイティブ職の学び場研究|gihyo.jp … 技術評論社

ペパボ

ペパボのエンジニア評価あれこれ。評価者側、被評価者側のエントリがあって参考になる。

こういう傾向もすごく参考になる

評価全体を見渡してみると、評価の高い人には、以下の傾向が見られます。(一人がすべてを満たしている、というわけではないです。)

  • 開発手法、開発フローに対するきちんとした理解と実践
  • 開発もインフラもできるオールラウンドな能力
  • 常に新しい技術情報を追いかけ、それを仕事にも取り込み活かしている
  • 現状これでやれてるから、とそこに留まらずに常に改善していこうとしている
  • 一部の技術ではずば抜けていて、社内で他にできる人が少ない、あるいはいない
  • いかに自動化して楽をするか、ということを常に考え実践している
  • アウトプットがすごい

Paperboy's engineer evaluation system - Gosuke Miyashita

クックパッド

その他

いまやっていること

いろいろ調べたことをまとめて評価制度の叩き台を作って、社内の全エンジニアと評価制度について1 on 1形式でヒアリングをさせてもらっている。実際にヒアリングしてみると、本当にいろいろな考え方の人がいて興味深い。多様性はあると感じた。制度設計は難しいけど。

まとめてみると、細かいところは違えど以下の観点で仕組みを作っている気がした。

  • 自社のエンジニアとして意識してほしいこと
  • 事業的な視点
  • 技術的な視点

事業的な視点と技術的な視点という分け方をしている企業が多いような印象だった。これと自社の企業理念や行動規範とのバランスが、企業ごとにちょっとずつ違う。このバランスの取り方が、大事なんだろうなと、感じている。

流行りにのるわけではないけど、評価の軸をSystem of RecordとSystem of Engagementの視点で分けつつ、バイモーダルを意識した形で選択できるように分類したらどうかな、と思っている。キーワードをそのまま使うわけではないけど、分類するための視点としてはよいと感じた。これは自分で思いついたわけではなく、ヒアリングの過程でアイディアをもらった。

WEB+DB Pressにもnaoyaさんが記事を書いていた。

WEB+DB PRESS Vol.96

評価制度の内容以外で共通しているのは、そのプロセスにしっかりと時間を掛けていることだった。評価面談の前、評価面談、その後のフィードバック面談が、しっかりと設計されていた。評価制度の内容ではなく、大切なのはどうやって相互に納得感を醸成するのかだと思う。

そこを前提として、どんなバランスがよいのか考えている。ヒアリングをしていくことで、評価制度について興味を持ってくれる人が増えたし、よい意見ももらえた。

CTOになって、ちょうど1年になる。ピーターの法則をかなり意識する。エンジニアが気持ちよく働けるような制度をしっかりと考えて、よいものを作りたい。頑張らなくては。