06 : 言語処理100本ノックでPythonのお勉強

第一章 : 06 集合

"paraparaparadise"と"paragraph"に含まれる文字bi-gramの集合を,それぞれ, XとYとして求め,XとYの和集合,積集合,差集合を求めよ.さらに,'se'というbi-gramがXおよびYに含まれるかどうかを調べよ.

集合はPythonだとset()関数を使うことで作成することができます。

プログラムは以下のようになります。n_gram()関数は05で作成したプログラムを使います。

l = 'paraparaparadise'
l2 = 'paragraph'

X = set(n_gram(l, 2))
Y = set(n_gram(l2, 2))

# 和集合
OR = X | Y
print(OR)

# 積集合
AND = X & Y
print(AND)

# 差集合
SUB = X - Y
print(SUB)

# 'se'が含まれているか
result = 'se' in X
print(result)
result = 'se' in Y
print(result)

05 : 言語処理100本ノックでPythonのお勉強

第一章 : 05のお題 n-gram

与えられたシーケンス(文字列やリストなど)からn-gramを作る関数を作成せよ.この関数を用い,"I am an NLPer"という文から単語bi-gram,文字bi-gramを得よ.

そもそもn-gramとは何ぞや。bi-gramとは何ぞや。wikipediaを調べると以下のようなものらしい。

「N文字インデックス法」「Nグラム法」などともいう。検索対象を単語単位ではなく文字単位で分解し、後続の N-1 文字を含めた状態で出現頻度を求める方法。Nの値が1なら「ユニグラム(英: uni-gram)」、2なら「バイグラム(英: bi-gram)」、3なら「トライグラム(英: tri-gram)」と呼ばれる。

例えば、「こんにちは」という文字列をbi-gramで分割すると、「こん」、「んに」、「にち」、「ちは」という文字列に分けられる。tri-gramで分割すると、「こんに」、「んにち」、「にちは」という文字列にわけられる。n-gramは検索などに使われる技術のよう。

プログラムは以下のようになります。

def n_gram(target, n):
    result = []
    for i in range(0, len(target) -n + 1):
        result.append(target[i:i+n])
    return result

l = "I am an NLPer"
words = l.split(" ")

# bi-gram
result = n_gram(words, 2)
print(result)

# tri-gram
result = n_gram(words, 3)
print(result)

04 : 言語処理100本ノックでPythonのお勉強

第一章 : 04のお題 元素記号

"Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."という文を単語に分解し,1, 5, 6, 7, 8, 9, 15, 16, 19番目の単語は先頭の1文字,それ以外の単語は先頭に2文字を取り出し,取り出した文字列から単語の位置(先頭から何番目の単語か)への連想配列(辞書型もしくはマップ型)を作成せよ.

プログラムはこんな感じです。

first_w_list = [1, 5, 6, 7, 8, 9, 15, 16, 19]
target = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."
results = {}

words = target.split(" ")

for (num, word) in enumerate(words, 1):
    if num in first_w_list:
        results[word[0:1]] = num
    else:
        results[word[0:2]] = num

print(results)

最初に先頭の1文字だけ取り出す単語の番号のリスト、文全体の文字列、結果を入れる辞書を作成します。

次に文全体を文字列から単語のリストに変換します。

そして、enumerate()関数を使って単語のリストを回し、numがfirst_w_listに入ってる場合は、単語の1文字目をスライスして辞書のキーに入れ、辞書の値にその番号を入れます。入っていない場合は単語の2文字目までをスライスし、辞書のキーに入れ、辞書の値にその番号を入れます。

enumerate()関数を使うと、リストの値だけでなく、インデックス番号も取得することができます。for(num, word) in enumerate(words, 1)と書くと、wordsリストに入っている要素のインデックスをnumに返し、値をwordに返すことができます。enumerate()関数の第2引数(今回の場合は1)は最初のインデックス番号をいくつにするか指定するために使います。

03 : 言語処理100本ノックでPythonのお勉強

第一章 : 03のお題 円周率

"Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."という文を単語に分解し,各単語の(アルファベットの)文字数を先頭から出現順に並べたリストを作成せよ.

l = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."
words = l.split(" ")
result = []

for word in words:
    count = 0
    for char in word:
        if char.isalpha():
        count += 1
    result.append(count)

print(result)

まず、split関数で文を単語のリストに分ける。 次に結果を入れるための空のリストを用意する そして、単語のリストをfor文で回し、その中で単語の中にあるアルファベットをis.alpha()関数で調べ、アルファベットであれば、 countを1増やす。最後に結果のリストにアルファベットの数の要素をappend()関数で追加する。

00,01,02 : 言語処理100本ノックでPythonのお勉強

言語処理100本ノックというPython自然言語処理を学ぶのに最適なウェブページがあるので、やってみる。こちらが2015年版の問題週。今回は00から03までやってみます。

環境

macOS Sierra 10.12.2 python3.5.2 (pyenv)

00. 文字列の逆順

"stressed"という文字列を逆順にする。 Pythonでは、スライスという機能があり、この機能を使うと簡単に逆に出来る。 スライス機能はコロンで区切って、3つの値を入力して処理させることができる。 例えば、"helloworld"[0:-1:2]と書くと、0文字目から末尾の1つ手前まで一文字おきにを切り取ることが出来て、"hllol"を取り出すことが出来る。-1は逆順を表す。

# knock1_00.py
l = "stressed"
re_l = l[::-1]
print(re_l)

01.パタトクカシーー

「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して、連結し文字列にする。 これもスライス機能を使う。

# knock_01.py
l = "パタトクカシーー"
l2 = l[::2]
print(l2)

# 2,4,6,8文字目を取り出す場合はこうする。
l3 = l[1::2]
print(l3)

02.「パトカー」+「タクシー」=「パタトクカシーー」

「パトカー」と「タクシー」という文字列を先頭から交互に連結して、「パタトクカシーー」という文字列をつくる。

# knock_03.py
l = []
l2 = 'パトカー'
l3 = 'タクシー'
for i in range(len(l2)):
    l.append(l2[i])
    l.append(l3[i])
l = ''.join(l)

# 他の方法1 - zip関数を使う。こっちの方が随分簡潔。
result = ''
for (a, b) in zip(l2, l3):
    result  += a + b
print(result)  
    

深センを見てきた - 2016年8月 -

2016年8/15日に行われたニコ技深セン観察会に参加してきました。 僕はファブラボ鎌倉というモノづくり施設の運営をしていて、 今回そのファブラボの国際会議であるFAB12にも参加していたため、 1週間ほど深センに滞在していましたが、スケジュールの関係でこちらのツアーは1日だけの参加となりました。 深センの情報は、本ツアーの主催者であるチームラボ高須さんが書いた、ツアーの参加者が書いたブログを見て事前に予習しておくといいです。

f:id:mio_kt:20160823064725j:plain

1. 深センに滞在する

SIMカード

深センに滞在する際に快適に過ごすために必要なことを少し書いておきます。 まずインターネットですが、アマゾンで香港用のSIMカードを買っておきましょう。 僕は買い忘れて深センに着いてから、回展中心駅のシェラトンホテルで現地のSIMを買って、 iPhone6S(SIMフリー)に入れてVPNを通して使い始めたのですが、VPN(HMAとTunnelBear)が不安定なのか更新中のグルグルマーク が消えず、ページを読み込まなくなることが多々ありました。ちなみに深センのSIMでは、普通に接続すると、 Facebook, Twitter, Line, Googleあたりが見れません。日本で買い忘れた方は仕方ないので買いましょう。

f:id:mio_kt:20160823064730j:plain [シェラトンで変えるSIMカード]

アプリケーション

知らない土地でGoogleMapが使えないのは痛いです。Appleの地図は使えますが、位置が不正確で全く使えません。 仕方がないので、連絡はWeChat、地図はBaiduMapを使いました。WeChatは現地の人とも連絡取れるし、 内部の連絡もこちらを使うので入れるのは必須です。BaiduMapは中国語しか選べませんが、地図は正確で使いやすいです。

ホテル

AgodaでColour Inn Shenzhen というホテルを予約して泊まりました。こちら安くて比較的綺麗なのでおすすめです。一泊3,500円くらい。 超大きい家電街、華強北までも電車、徒歩含めて20分くらいでいけます。

電車

電車は行き先を指定してコイン(RFID入)を購入し、Suicaみたいにタッチして入場して、出るときはタッチしてコインを戻します。 またSuicaのようなチャージできるカードも購入できるので、今後も深センに行くなら持っておくと便利です。 毎回コインを買うのに並ぶのが面倒くさいので。カードは100元で購入し、20元がデポジット、80元が使用できます。 一度に乗るのに必要な料金は2.7元くらいです。

f:id:mio_kt:20160823064733j:plain [中国版Suica]

2. Seeed Studio 組立工場

基板を少量ロットで生産してくれるサービス、FusionPCBで有名なSeeed Studioの組立工場を見学に行きました。

f:id:mio_kt:20160823064652j:plain [Seeed Studio 組立工場]

とても綺麗な工場で、工員の作業環境も良く、快適に仕事ができそうです。Seeedのウェブサイトを見ればわかりますが、現在SeeedはPCBの製造だけでなく、部品実装からレーザー加工、3Dプリントのようなサービスも受けてくれるようで、少量生産で作りたいMakerにとって無くてはならないインフラとなってきています。 僕はPCB製造しか頼んだことないですが、他のサービスも試してみようと思いました。

f:id:mio_kt:20160823064701j:plain [レーザー加工機]

f:id:mio_kt:20160823064657j:plain [通電試験用の治具]

f:id:mio_kt:20160823064705j:plain [デスクワーカー達の作業風景]

一通り、工場の中を案内してくれた後、Seeedが行なっているビジネスについてプレゼンをしてくれました。 Seeedは世界のMakerの人たちに向けてサービスを行なっていて、現在は国内に関してはあまり見てないようです。 依頼してくるMakerの数はアメリカ、ヨーロッパが中心ですが、日本も増えてきていて、今は20%は日本からの依頼とのこと。 世界中のMakerに向けてサービスを行なっているので、英語が堪能なスタッフがいることは当然で、カスタマサポートなどにも 力を入れていて、他の中国の工場とは一線を画してると思います。受けた印象としては、SaasやPaasといったソフトウェアのクラウドサービス のハードウェア板という感じがして、細かい指示を出さなくても、よしなにハードウェアを作ってくれる工場のクラウドサービスを目指している気がしました。

3. PCB工場

SeeedにPCBを発注すると、SeeedがPCBをすべてつくるわけではなく、さまざまな工場と連携して製造しています。 こちらはSeeedからの発注を受けているPCB工場で、日本の企業から直接発注を受けることもあるそうです。 僕はPCB工場を見学するの初めてなので、比較はできませんが、こちらの工場では手作業の部分が数多くあり、昔ながらの工場という印象を受けました。

f:id:mio_kt:20160823064709j:plain [基板のチェック]

f:id:mio_kt:20160823064714j:plain [通電チェック風景]

f:id:mio_kt:20160823064718j:plain [基板を切り抜く作業風景]

4. ロボットベンチャー

PCB工場をあとにして僕らはNXROBOというロボットをつくっているスタートアップを見に行きました。 NXROBOは家庭用のロボットを作っていて、デザインは部屋に溶け込むようにソファとかと似た布で覆われています。 現在Kickstarterのキャンペーンを行なっています。かなりお手頃な価格で手に入るので気になりますね。 一家に一台ロボットが来る日は近いなと感じました。ただ結構大きいので、現状では日本の狭いマンションとかには 厳しいかな。もう少し小型化したバージョンもぜひ開発してほしい。

5. おわりに

深セン面白い!現在深センは、日本の高度経済成長期のようなバブル(体験してませんが)の雰囲気もあり、 玉石混交の面白ガジェットが街に溢れかえり、人々はいきいきとしています。 深センで知り合ったArduinoなどのマイコンボードを販売していいる会社の社長は、18才で起業して、まだ26才の若さです。 彼はマイコンボードなどを売っていますが、ファブラボやMakerについては、あまり知らないようで、興味津々にいろいろと聞いてきます。 また、Seeedのような国際的なインフラになりつつある会社があり、Haxのようなハードウェアスタートアップを支援するエコシステムも存在します。 この生態系の中に日本のMakerも入っていくことで、面白い化学反応が起こるように思います。一度見ただけでは、わからない部分もあるので、 10月に行われるMakerFaire Shenzhenにも参加してみようと思います。

SwiftでCorebluetoothを使ってKonashiのLEDをチカチカさせる

iPhone6Sを買ったしSwiftでいろいろと遊んでます。
今回は以前買ったKonashi v2をKonashiSDKを使わないでCorebluetoothでLチカさせてみました。 こちらの本"iOSxBLE Core Bluetoothプログラミング"で学びながら作ってます。

開発環境
開発環境 : XCode7.2
使用機器 : iPhone6S, iOS9.2
Konashi : Konashi v2(koshian)

アプリケーションが実行する処理の流れ

  1. アプリに配置したスキャンボタンを押して、周辺のペリフェラル(Konashiとか)を検索。
  2. ペリフェラルを発見したら接続。
  3. ペリフェラルと接続できたら、ペリフェラルが提供するサービスを検索。
  4. 提供しているサービスを見つけたら、サービスに含まれるキャラクタリスティックを検索。
  5. 目的のキャラクタリスティックを発見したら、そのキャラクタリスティックをプロパティに保持しておく。
  6. アプリに配置したスイッチボタンでキャラクタリスティックの値を書き換える。
  7. キャラクタリスティックの値が変更されるとLEDが点灯/消灯します。
//
//  ViewController.swift
//  Corebluetooth LED Blinking Example
//
//  Created by miokato on 1/20/16.
//  Copyright © 2016 miok. All rights reserved.
//

import UIKit
import CoreBluetooth

class ViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {

    var isScanning: Bool = false
    var isBlink: Bool = false
    var centralManager: CBCentralManager!
    var peripheral: CBPeripheral!
    var settingCharacteristic: CBCharacteristic!
    var outputCharacteristic: CBCharacteristic!
        
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.centralManager = CBCentralManager(delegate: self, queue: nil)
    }
    
    // ===============================================================================
    // MARK: Actions
    
    // スキャン
    @IBAction func scanBtnTapped(sender: UIButton) {
        if !isScanning {
            isScanning = true
            self.centralManager.scanForPeripheralsWithServices(nil, options: nil)
            sender.setTitle("Stop Scan", forState: UIControlState.Normal)
        }
        else {
            isScanning = false
            self.centralManager.stopScan()
            sender.setTitle("Start Scan", forState: UIControlState.Normal)
        }
    }

    
    // LEDスイッチ
    @IBAction func writeValue(sender: UIButton) {
        if self.settingCharacteristic == nil || self.outputCharacteristic == nil {
            print("konashi is not ready!")
            return
        }
        var value: CUnsignedChar
        
        if !isBlink {
            isBlink = true
            sender.setTitle("Turn Off", forState: UIControlState.Normal)
            // LED2を光らせる
            value = 0x01 << 1
            
        }
        else {
            isBlink = false
            sender.setTitle("Turn On", forState: UIControlState.Normal)
            // LED2を消す
            value = 0x00 << 1
        }
        let data: NSData = NSData(bytes: &value, length: 1)
        
        
        self.peripheral.writeValue(data,
            forCharacteristic: self.settingCharacteristic,
            type: CBCharacteristicWriteType.WithoutResponse)
        
        self.peripheral.writeValue(data,
            forCharacteristic: self.outputCharacteristic,
            type: CBCharacteristicWriteType.WithoutResponse)
    }
    
    // ===============================================================================
    // MARK: CBCentral Manager Delegate
    
    // セントラルマネージャの状態変化があると呼ばれる
    func centralManagerDidUpdateState(central: CBCentralManager) {
        print("state: \(central.state)")
    }
    
    // ペリフェラルが見つかると呼ばれる
    func centralManager(central: CBCentralManager,
        didDiscoverPeripheral peripheral: CBPeripheral,
        advertisementData: [String : AnyObject],
        RSSI: NSNumber)
    {
        print("発見したBLEデバイス: \(peripheral)\n")
        
        if peripheral.name?.hasPrefix("konashi") == true {
            self.peripheral = peripheral
            // 接続開始
            self.centralManager.connectPeripheral(self.peripheral, options: nil)
        }

    }
    
    // ペリフェラルに接続したら呼ばれる
    func centralManager(central: CBCentralManager,
        didConnectPeripheral peripheral: CBPeripheral)
    {
        print("接続成功")
        
        // サービス検索結果を受け取るデリゲートをセット
        peripheral.delegate = self
        // サービス検索開始
        peripheral.discoverServices(nil)
    }
    
    // ペリフェラルへの接続が失敗すると呼ばれる
    func centralManager(central: CBCentralManager,
        didFailToConnectPeripheral peripheral: CBPeripheral,
        error: NSError?)
    {
        print("接続失敗...")
    }
    
    // ===============================================================================
    // MARK: CBPeripheralDelegate
    
    // サービス発見したら呼ばれる
    func peripheral(peripheral: CBPeripheral, didDiscoverServices error: NSError?) {

        if error != nil {
            print("エラー: \(error)")
            return
        }
        
        if peripheral.services?.count <= 0 {
            print("no services")
            return
        }
        
        let services = peripheral.services!
        print("\(services.count)個のサービスを発見しました。\n\(services)\n")
        
        for service in services {
            peripheral.discoverCharacteristics(nil , forService: service)
        }

    }
    
    // キャラクタリスティックを取得したら呼ばれる
    func peripheral(peripheral: CBPeripheral,
        didDiscoverCharacteristicsForService service: CBService,
        error: NSError?)
    {
        if error != nil {
            print("エラー: \(error)")
            return
        }
        
        if service.characteristics?.count <= 0 {
            print("no characteristics")
            return
        }
        
        let characteristics = service.characteristics!
        print("\(characteristics.count)個のキャラクタリスティックを発見しました。\n\(characteristics)\n")
        
        for characteristic in characteristics {

            if characteristic.UUID.isEqual(CBUUID(string: "229B3000-03FB-40DA-98A7-B0DEF65C2D4B")) {
                self.settingCharacteristic = characteristic
                print("KONASHI_PIO_SETTING_UUID を発見")
            } else if characteristic.UUID.isEqual(CBUUID(string: "229B3002-03FB-40DA-98A7-B0DEF65C2D4B")) {
                self.outputCharacteristic = characteristic
                print("KONASHI_PIO_OUTPUT_UUID を発見")
            }
        }
    }
    
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}