NINのブログ

主に機械学習とか統計モデリングとか金融とか

自動補完入力の実装

Androidアプリの検索ボックス内で、自動補完入力を行う必要が出てきました。
AutoCompleteTextViewで自動補完機能を実装しました。

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.autocomplete.MainActivity" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Search" />

        <AutoCompleteTextView
            android:id="@+id/autoCompleteTextView1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="text"
            android:ems="10" />
    </LinearLayout>
    
</RelativeLayout>

layoutの下の階層にlist.xmlを作ります。
list.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="10dp"
    android:textSize="16sp"
    android:textColor="#000">
</TextView>

最後にMainActivityです。
MainActivity.java

package com.example.autocomplete;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;

public class MainActivity extends ActionBarActivity {
	static final String[] MUSIC = new String[] {
		"アート・ロック","パワー・ポップ","シューゲイザー","ポスト・グランジ","ドリーム・ポップ"
		,"ニュー・ウェーヴ","ロックンロール","ノイズポップ","ノイズロック","サイケデリック・ロック"
		,"オルタナティヴ・ロック","エモ","テクノポップ","グランジ"
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		//補完入力の実装
		AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView1);
		ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list,MUSIC);
                textView.setAdapter(adapter);
                textView.setThreshold(1);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}
}

実行結果
f:id:RYNIN:20140902232805p:plain

これでユーザーが文字を入力する手間が省けます。
しかしながら今回実装したのは前方一致の場合であり、部分一致を行いたいケースも生じると思うので、次回は部分一致の場合のプログラムを書きたいと思います。

Google Maps API v2について

友人と位置情報サービスの開発に着手していて、Google Maps APIを使う必要が出てきたのですが、Google Maps API v2のデモ使用ではまったのでメモします。
・プロジェクトを実機で実行する際に、実機が認識されない
→実機とPCを繋ぐUSBケーブルが、充電用でデータ転送用でなかった。

・実機で実行しても、マップが表示されない
Failed to load map. Error contacting Google servers. This is probably an authentication issue (but could be due to network errors).
というエラーが出てきます。
Google APIs ConsoleでAPI Keyを取得する際、異なるパッケージ名で登録していた。
Googleが出しているデモバージョンのパッケージ名はcom.example.mapdemoなので、正しくは
SHA1のフィンガープリント+;com.example.mapdemo
として登録します。

正しいAPI Keyを取得した後、AndroidManifest.xlmを編集します。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.example.mapdemo"
  android:versionCode="8"
  android:versionName="2.10.0">
  <!-- Copied from Google Maps Library/AndroidManifest.xml. -->
  <uses-sdk
    android:minSdkVersion="9"
    android:targetSdkVersion="17"/>
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  <uses-permission android:name="android.permission.INTERNET"/>
  <!-- External storage for caching. -->
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  <!-- My Location -->
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
  <!-- Maps API needs OpenGL ES 2.0. -->
  <uses-feature
    android:glEsVersion="0x00020000"
    android:required="true"/>
  <!-- End of copy. -->
  <application
    android:icon="@drawable/ic_launcher"
    android:label="@string/demo_title"
    android:hardwareAccelerated="true">
    <!-- ** You need to replace the key below with your own key. **
         The example key below will not be accepted because it is not linked to the
         certificate which you will use to sign this application.
         See: https://developers.google.com/maps/documentation/android/start
         for instructions on how to get your own key. -->
    <meta-data android:name="com.google.android.maps.v2.API_KEY"
    android:value="取得したキーを書く"/>
    <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
    <activity android:name=".MainActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
      </intent-filter>
    </activity>
    <activity
      android:name=".LegalInfoActivity"
      android:label="@string/legal_info"/>
    <activity
      android:name=".BasicMapDemoActivity"
      android:label="@string/basic_map_demo_label"/>
    <activity
      android:name=".CameraDemoActivity"
      android:label="@string/camera_demo_label"/>
    <activity
      android:name=".CircleDemoActivity"
      android:label="@string/circle_demo_label"/>
    <activity
      android:name=".EventsDemoActivity"
      android:label="@string/events_demo_label"/>
    <activity
      android:name=".GroundOverlayDemoActivity"
      android:label="@string/ground_overlay_demo_label"/>
    <activity
      android:name=".IndoorDemoActivity"
      android:label="@string/indoor_demo_label"/>
    <activity
      android:name=".LayersDemoActivity"
      android:label="@string/layers_demo_label"/>
    <activity
      android:name=".LocationSourceDemoActivity"
      android:label="@string/location_source_demo_label"/>
    <activity
      android:name=".MapInPagerDemoActivity"
      android:label="@string/map_in_pager_demo_label"/>
    <activity
      android:name=".MarkerDemoActivity"
      android:label="@string/marker_demo_label"/>
    <activity
      android:name=".MultiMapDemoActivity"
      android:label="@string/multi_map_demo_label"/>
    <activity
      android:name=".MyLocationDemoActivity"
      android:label="@string/my_location_demo_label"/>
    <activity
      android:name=".OptionsDemoActivity"
      android:label="@string/options_demo_label"/>
    <activity
      android:name=".PolygonDemoActivity"
      android:label="@string/polygon_demo_label"/>
    <activity
      android:name=".PolylineDemoActivity"
      android:label="@string/polyline_demo_label"/>
    <activity
      android:name=".ProgrammaticDemoActivity"
      android:label="@string/programmatic_demo_label"/>
    <activity
      android:name=".RawMapViewDemoActivity"
      android:label="@string/raw_map_view_demo_label"/>
    <activity
      android:name=".RetainMapDemoActivity"
      android:label="@string/retain_map_demo_label"/>
    <activity
      android:name=".SaveStateDemoActivity"
      android:label="@string/save_state_demo_label"/>
    <activity
      android:name=".SnapshotDemoActivity"
      android:label="@string/snapshot_demo_label"/>
    <activity
      android:name=".SplitStreetViewPanoramaAndMapDemoActivity"
      android:label="@string/split_street_view_panorama_and_map_demo_label"/>
    <activity
      android:name=".StreetViewPanoramaBasicDemoActivity"
      android:label="@string/street_view_panorama_basic_demo_label"/>
    <activity
      android:name=".StreetViewPanoramaEventsDemoActivity"
      android:label="@string/street_view_panorama_events_demo_label"/>
    <activity
      android:name=".StreetViewPanoramaNavigationDemoActivity"
      android:label="@string/street_view_panorama_navigation_demo_label"/>
    <activity
      android:name=".StreetViewPanoramaOptionsDemoActivity"
      android:label="@string/street_view_panorama_options_demo_label"/>
    <activity
      android:name=".StreetViewPanoramaViewDemoActivity"
      android:label="@string/street_view_panorama_view_demo_label"/>
    <activity
      android:name=".TileCoordinateDemoActivity"
      android:label="@string/tile_coordinate_demo_label"/>
    <activity
      android:name=".TileOverlayDemoActivity"
      android:label="@string/tile_overlay_demo_label"/>
    <activity
      android:name=".UiSettingsDemoActivity"
      android:label="@string/ui_settings_demo_label"/>
    <activity
      android:name=".VisibleRegionDemoActivity"
      android:label="@string/visible_region_demo_label"/>
  </application>
</manifest>

実行できました!
f:id:RYNIN:20140815164415p:plain

Sierpinskiの三角形

ProcessingでSierpinskiの三角形を描きます。
フラクタルとしての性質を持つSierpinskiの三角形は、再帰関数を用いて書くのが良いでしょう。

void setup() {
  size(600, 600, P3D);
  colorMode(RGB,256);
  background(#050000);
  smooth();
  fill(#FFFFFF);
  triangle(300,130,100,470,500,470);
}

void circlesR(float x1, float y1, float x2, float y2, float x3, float y3, int n) {
  triangle((x1+x2)/2,(y1+y2)/2,(x2+x3)/2,(y2+y3)/2,(x3+x1)/2,(y3+y1)/2);
  if (n>1) {
  circlesR(x1,y1,(x1+x2)/2,(y1+y2)/2,(x1+x3)/2,(y1+y3)/2,n-1);
  circlesR(x2,y2,(x1+x2)/2,(y1+y2)/2,(x2+x3)/2,(y2+y3)/2,n-1);
  circlesR(x3,y3,(x2+x3)/2,(y2+y3)/2,(x1+x3)/2,(y1+y3)/2,n-1);
  }
}

void draw(){
    fill(#050000);
    circlesR(300,130,100,470,500,470,4);
    save("4.png"); 
}

再帰の深さ1
f:id:RYNIN:20140809011347p:plain
再帰の深さ3
f:id:RYNIN:20140809011354p:plain
再帰の深さ4
f:id:RYNIN:20140809011632p:plain
再帰の深さ6
f:id:RYNIN:20140809011359p:plain

ProcessingでSound Visualization

Processingでリアルタイム波形処理をし、可視化します。
音楽ファイルはStudioOneで作成しました。

import ddf.minim.*;

Minim minim;
AudioPlayer player;

void setup()
{
  size(600, 600, P3D);
  colorMode(RGB,256);
  minim = new Minim(this);//インスタンス
  
  // loadFile will look in all the same places as loadImage does.
  // this means you can find files that are in the data folder and the 
  // sketch folder. you can also pass an absolute path, or a URL.
  player = minim.loadFile("Mixdown.mp3");
  
  // play the file from start to finish.
  // if you want to play the file again, 
  // you need to call rewind() first.
  player.play();
}

void draw()
{
  background(0);//彩度
  stroke(200);
  // draw the waveforms
  // the values returned by left.get() and right.get() will be between -1 and 1,
  // so we need to scale them up to see the waveform
  // note that if the file is MONO, left.get() and right.get() will return the same value
  for(int i = 0; i < player.bufferSize() - 1; i++)
  {
    float x1 = map( i, 0, player.bufferSize(), 0, width );
    float x2 = map( i+1, 0, player.bufferSize(), 0, width );
    stroke(#47B8FC);   
    line( x1, 60 + player.left.get(i)*100, x2, 80 + player.left.get(i+1)*100 );
    line( x1, 520 + player.right.get(i)*100, x2, 540 + player.right.get(i+1)*100 );
    noStroke ();
    fill(#FA0D15);
    ellipse(200,200,player.left.get(i)*50,player.right.get(i)*50);
    fill(#FFFCFD);
    ellipse(200,400,player.left.get(i)*50,player.right.get(i)*50);
    fill(#FFFCFD);
    ellipse(400,200,player.left.get(i)*50,player.right.get(i)*50);
    fill(#FFFCFD);
    ellipse(400,400,player.left.get(i)*50,player.right.get(i)*50);
  }
}

出力

階層型クラスタリングと非階層型クラスタリングの考察

今回はPythonで階層型クラスタリングと非階層型クラスタリングアルゴリズムから実装し、両者の違いについて考察します。

階層型クラスタリングとは
概念
似ているものどうしを同じクラスタに、似てないものを別のクラスタにグルーピングします。
f:id:RYNIN:20140807173400j:plain

アルゴリズム
一番近い要素またはサブクラスタ間を繋ぎ、また距離を計算する、ということを繰り返し行います。得られたデンドログラムと指定した基準値から、データのクラスタリングが出来ます。



非階層クラスタリングとは
概念
クラスタの平均を用いることで、与えられたクラスタ数にデータを分類します。
f:id:RYNIN:20140807173406j:plain

アルゴリズム
各データに対してランダムにクラスタを割り振ります。
割り振ったデータをもとに各クラスタの中心 を計算します。計算は通常割り当てられたデータの各要素の算術平均が使用されます。
各データと各クラスタの中心との距離を求め、各データを最も近い中心のクラスタに割り当て直し、上記の処理で全てのデータに対しクラスタの割り当てが変化しなかった場合、あるいは変化量が事前に設定した一定の閾値を下回った場合に、収束したと判断して処理を終了します。そうでない場合は新しく割り振られたクラスタからクラスタの中心を再計算して上記の処理を繰り返します。


用いたデータはR言語kernlab付属のデータセットであるirisです。
3種類のアヤメの花の特徴量(sepal length, sepal width, petal length, petal width)をもとにしてクラスタリングを行います。


まず、階層型クラスタリングの実装ですが、今回は最短距離法を用いました。
f:id:RYNIN:20140807173607p:plain

#coding:utf-8

import csv
import math

f = open('iris.csv','rb')
data = []
c = csv.reader(f)
for row in c:
    data.append(row)
f.close()

vector = [] #データをベクトルに入れる
num  = len(data)
for i in range(1,num):
    vector.append(data[i])
    data[i].pop(0)

vector_num = len(vector) #類似度の行列を作る
mat = []
dist = 0

def make_mat(vector):
    sub_mat = []
    for i in range(1,len(vector)):
        for j in range(i):  # ユークリッド距離の計算
            dist = math.sqrt((float(vector[i][0])-float(vector[j][0]))**2+(float(vector[i][1])-float(vector[j][1]))**2+(float(vector[i][2])-float(vector[j][2]))**2+(float(vector[i][3])-float(vector[j][3]))**2)
            sub_mat.append(dist)
            dist = 0
        mat.append(sub_mat)
        sub_mat = []
    return mat

def dd(list1,list2):
    dist = math.sqrt((float(list1[0])-float(list2[0]))**2+(float(list1[1])-float(list2[1]))**2+(float(list1[2])-float(list2[2]))**2+(float(list1[3])-float(list2[3]))**2)
    return dist

def min(list):  #最小値検索をする関数
    min = list[0]
    for i in range(len(list)):
        if min >= list[i]:
            min = list[i]
    return min

def min_num(list):  #最小値検索をする関数
    min_number = 0
    min = list[0]
    for i in range(len(list)-1):
        if min >= list[i]:
            min_number = i
            min = list[i]
    return min_number

def mat_min(matrix):
    m = matrix[0][0]
    row = 0
    for i in range(len(matrix)):
        if m > min(matrix[i]):
            m = min(matrix[i])
            row = i
    col = min_num(matrix[row])
    return m,row,row+1,col #データに対応するのはrow+1,colである。

def mean(list1,list2):   #データの平均値リストを返す
    mm = [(float(list1[0])+float(list2[0]))*1.0/2,(float(list1[1])+float(list2[1]))*1.0/2,(float(list1[2])+float(list2[2]))*1.0/2,(float(list1[3])+float(list2[3]))*1.0/2,list1[4]+"/"+list2[4]]
    return mm

def large(a,b):
    if a > b:
        return [b,a]
    if b > a:
        return [a,b]

def re_mat(mat,vector,num): #最小値をグルーピングをし、再構成を行う関数
    row = num[2]
    col = num[3]
    dist = mat_min(mat)[0]
    ll = large(row,col)
    del mat[ll[0]]
    del mat[ll[1]-1]
    mat.append(vector)
    store = [row,col,dist]
    return mat,store

for i in range(len(vector)-3):
    mat = []
    mat = make_mat(vector)
    mmmat = mat_min(mat)
    ave = mean(vector[mmmat[2]],vector[mmmat[3]])
    rr = re_mat(vector,ave,mmmat)
    print rr
    #    print len(rr[0])
    mat = rr
print "*************"
print rr[0][0][4]
print "*************"
print rr[0][1][4]
print "*************"
print rr[0][2][4]
print "*************"
実行結果
*************
virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica/virginica
*************
setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa/setosa
*************
versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/virginica/virginica/virginica/virginica/virginica/virginica/virginica/versicolor/virginica/virginica/versicolor/versicolor/virginica/virginica/virginica/virginica/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor/versicolor
*************

次に、非階層型クラスタリングですが、K-Means法を用いました。

#coding:utf-8

import csv
import math
import random

f = open('iris.csv','rb')
data = []
c = csv.reader(f)
for row in c:
    data.append(row)
f.close()

vector = []
num  = len(data)
for i in range(1,num):
    vector.append(data[i])
    data[i].pop(0)

num_vector = len(vector)

for i in range(num_vector):
    vector[i].append(random.randint(1,3))

def make_list(mat,num):
    ll = []
    for i in range(len(mat)):
        ll.append(mat[i][num])
    return ll

def z_score(list):
    sum = 0
    num = len(list)
    for i in range(num):
        sum += float(list[i])
    ave = sum*1.0/num

    sum_1 = 0
    for i in range(num):
        sum_1 += (float(list[i])-ave)**2
    sd = math.sqrt(sum_1*1.0/num)

    out = []
    for i in range(num):
        out.append((float(list[i])-ave)*1.0/sd)
    return out

l0 = make_list(vector,0)
l1 = make_list(vector,1)
l2 = make_list(vector,2)
l3 = make_list(vector,3)

z0 = z_score(l0)
z1 = z_score(l1)
z2 = z_score(l2)
z3 = z_score(l3)

vector_1 = []
for i in range(len(vector)):
    vector_1.append([z0[i],z1[i],z2[i],z3[i],vector[i][4],vector[i][5]])


def dist(list_1,list_2):  #距離を求める関数
    num = math.sqrt((float(list_1[0])-float(list_2[0]))**2+(float(list_1[1])-float(list_2[1]))**2+(float(list_1[2])-float(list_2[2]))**2+(float(list_1[3])-float(list_2[3]))**2)
    return num

def min(list):  #最小値検索をする関数
    min = list[0]
    for i in range(len(list)):
        if min >= list[i]:
            min = list[i]
    return min

def gravity(list):  #グループ内の重心を計算する関数
    num = len(list)
    sum1 = 0
    sum2 = 0
    sum3 = 0
    sum4 = 0
    for i in range(len(list)):
        sum1 = sum1 + float(list[i][0])
        sum2 = sum2 + float(list[i][1])
        sum3 = sum3 + float(list[i][2])
        sum4 = sum4 + float(list[i][3])
    gra = [sum1*1.0/num,sum2*1.0/num,sum3*1.0/num,sum4*1.0/num]
    return gra

def group(list): # グルーピングを行う関数
    group_1 = []
    group_2 = []
    group_3 = []
    for i in range(len(list)):
        if list[i][5] == 1:
            group_1.append(list[i])
        elif list[i][5] == 2:
            group_2.append(list[i])
        else:
            group_3.append(list[i])
    return group_1,group_2,group_3

def re_group(list,g1,g2,g3): #グループ再構成を行う関数

    group_1 = []
    group_2 = []
    group_3 = []
    for i in range(len(list)):
        m1 = dist(list[i],g1)
        m2 = dist(list[i],g2)
        m3 = dist(list[i],g3)
        if min([m1,m2,m3]) == m1:
            group_1.append(list[i])
        elif min([m1,m2,m3]) == m2:
            group_2.append(list[i])
        else:
            group_3.append(list[i])
    return group_1,group_2,group_3

g = group(vector_1)

for i in range(2):
    g1 = gravity(g[0])
    g2 = gravity(g[1])
    g3 = gravity(g[2])
    store = re_group(vector_1,g1,g2,g3)
    g1 = store[0]
    g2 = store[1]
    g3 = store[2]

for i in range(len(g1)):
    print g1[i][4]
print "********************************"
for i in range(len(g2)):
    print g2[i][4]
print "********************************"
for i in range(len(g3)):
    print g3[i][4]
実行結果
versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,
********************************
setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,setosa,versicolor
********************************
versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,versicolor,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica,virginica


考察
非階層型クラスタリングのK-means法では初期設定において、データに対してランダムにクラスタを割り当てるため、実行結果が毎回異なりました。今回は階層型クラスタリングの方が精度が良かったですが、K-means法の方が実行時間が短くなりました。K-means++法という初期値の選択法を改良したクラスタリング法が考案されているそうです。

PythonでSVMの実装

PythonSVMを実装します。
SVM(サポートベクターマシン)は教師あり学習を用いる識別手法の一つです。
SVMは、線形入力素子を利用して 2 クラスのパターン識別器を構成する手法であり、訓練サンプルから、各データ点との距離が最大となるマージン最大化超平面を求めるという基準で、線形入力素子のパラメータを学習します。

f:id:RYNIN:20140807002819j:plain

用いたデータ
R言語パッケージkernlabに付属する、データセットspamを使いました。データセットは、4601通の電子メールを58項目に分けて記録したもので、第58列がクラス情報spam,nonspamで、残りの57項目はメールの特徴を記録したものです。

spam,nonspamと判定されたメールの半数をそれぞれ教師データに、もう一方をテスト用データに分割し、教師データを用いて学習をさせた後、テスト用データでメールの分類の精度をF値を用いて検証しました。

モジュールとしてsklearnを使いました。
それでは、実装します

#coding:utf-8

from sklearn import svm
import numpy as np
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report
import csv

f = open('SVM.csv', 'rb')
data = []
c = csv.reader(f)  # CSV読み込み用オブジェクトの生成
for row in c:
    data.append(row)   #spamデータをリスト型のdataに格納
f.close()

# dataの個数は4601個で属性のベクトルは58次元.58個目の要素が判別値.ex).data[1][58] = spam
# 1~1813:spam 1を返す ,1814~4601:nonspam 0を返す

num = len(data)       #4602
for i in range(1,num):
    if data[i][58] == 'spam':
        data[i][58] = 1          #負例、正例の値を振り分ける
    else:
        data[i][58] = 0

for i in range(num):            #idを削除する
    data[i].pop(0)


#まずは適当にデータを分割してSVMによる判定を行う。

x = []
y = []
one = 1
zero = 0

for i in range(1,907):     #正例の教師値
    x.append(data[i])

for i in range(1814,3207): #負例の教師値
    x.append(data[i])

teach_num = len(x)     #2209

for i in range(teach_num):   #クラスレベル
    if i < 906:
        y.append(one)
    else:
        y.append(zero)

test_data = []
answer_data = []

for i in range(907,1813):     #正例の教師値
    test_data.append(data[i])

for i in range(3207,4602): #負例の教師値
    test_data.append(data[i])

test_num = len(test_data)

for i in range(test_num):   #クラスレベル
    if i < 906:
        answer_data.append(one)
    else:
        answer_data.append(zero)

pre_list = []
pre_num = len(test_data)
num_answer = 0

clf = svm.SVC(kernel='rbf') #Support Vector Classification,RBFカーネルを使用
clf.fit(x,y) #学習
pre_list = clf.predict(test_data) #予測

for i in range(pre_num):
    if answer_data[i] == pre_list[i]:
        num_answer += 1

#print confusion_matrix(answer_data,pre_list)   #分類結果を表示する

accuracy = (num_answer*1.0/pre_num)*100
#print accuracy

target_names = ['class0', 'class1']
print (classification_report(answer_data,pre_list,target_names=target_names)) 

実行結果

             precision    recall  f1-score   support

     class0       0.87      0.82      0.85      1395
     class1       0.75      0.81      0.78       906

avg / total       0.82      0.82      0.82      2301

F値は0.82となりました。
次回は交差検定により、SVMのチューニングをし、精度を高める手法を紹介します。

TwitterAPIでツイートの取得

Pythonで自分のツイートを取得する方法を紹介します。
Twitter Developersに登録をして、consumer_key , consumer_secret , access_token_key , access_token_secretを取得します。

#coding:utf-8
import twitter

#取得したkey,secretを書く
api = twitter.Api(
                  consumer_key = secret.twDict['consumer_key'],
                  consumer_secret = secret.twDict['consumer_secret'],
                  access_token_key = secret.twDict['access_token_key'],
                  access_token_secret = secret.twDict['access_token_secret']
                  )
status = api.GetUserTimeline()
for tweet in status:
    print tweet.text

PythonからTwitterのタイムラインなどを取得することも出来ます。
tf-idf法などと込み合わせることで、診断系のアプリ作成に使えるでしょう!!