カテゴリ:python( 13 )
PythonでPostgresqlを操作する
目的
PythonでPostgresqlを操作する

環境
Python 2.x / 3.c
PostgresSQL 9.3
psycopg2をつかう
Windowsの場合は以下のページからダウンロードしてExeを実行
http://www.stickpeople.com/projects/python/win-psycopg/

テーブル定義
CREATE TABLE t01prefecture
(
  pref_cd integer NOT NULL,
  pref_name character varying(10),
  CONSTRAINT t01prefecture_pkey PRIMARY KEY (pref_cd)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE t01prefecture
  OWNER TO postgres;

PostgresSQLのユーザ定義関数
CREATE OR REPLACE FUNCTION test_sp(IN from_cd integer, IN to_cd integer)
  RETURNS TABLE(code integer, name varchar) AS
$$
DECLARE
BEGIN
    RETURN QUERY SELECT PREF_CD,PREF_NAME FROM t01Prefecture
            WHERE PREF_CD BETWEEN from_cd AND to_cd;
END;
$$ LANGUAGE plpgsql;

Python3.x
# -*- coding: cp932 -*-
# Winddows の場合は以下からダウンロード
#  http://www.stickpeople.com/projects/python/win-psycopg/
#

import psycopg2

try:
    cnn = psycopg2.connect("dbname=Sample001 host=localhost user=postgres password=xxxx")
    cur = cnn.cursor()

    #試験データの整理
    pref_cd = 100
    cur.execute("""DELETE FROM t01prefecture WHERE PREF_CD >= %d"""
                % (pref_cd,))
    cnn.commit()

    print("単純なSELECT文==========================")
    from_id = 45
    to_id = 999
    cur.execute("""SELECT PREF_CD,PREF_NAME FROM t01prefecture
                WHERE PREF_CD BETWEEN %d AND %d""" % (from_id, to_id, ))
    rows = cur.fetchall()
    for row in rows:
        print("%d %s" % (row[0], row[1]))

    print("コミットの試験==========================")
    pref_cd = 100
    pref_name = "モテモテ国"
    cur.execute("""INSERT INTO t01prefecture(PREF_CD, PREF_NAME)
                VALUES ('%s', '%s')""" % (pref_cd, pref_name))

    pref_cd = 101
    pref_name = "野望の国"
    cur.execute("""INSERT INTO t01prefecture(PREF_CD,PREF_NAME)
                VALUES ('%s', '%s')""" % (pref_cd, pref_name,))
    cnn.commit()
    cur.execute("""SELECT PREF_CD,PREF_NAME FROM t01prefecture
                WHERE PREF_CD BETWEEN %d AND %d""" % (from_id, to_id, ))
    rows = cur.fetchall()
    for row in rows:
        print("%d %s" % (row[0], row[1]))


    print("ロールバックの試験==========================")
    pref_cd = 102
    pref_name = "ロール"
    cur.execute("""INSERT INTO t01prefecture(PREF_CD,PREF_NAME)
                VALUES ('%s', '%s')""" % (pref_cd, pref_name,))

    cur.execute("""SELECT PREF_CD,PREF_NAME FROM t01prefecture
                WHERE PREF_CD BETWEEN %d AND %d""" % (from_id, to_id, ))
    rows = cur.fetchall()
    for row in rows:
        print("%d %s" % (row[0], row[1]))

    print("-------------------------")
    cnn.rollback()
    cur.execute("""SELECT PREF_CD,PREF_NAME FROM t01prefecture
                WHERE PREF_CD BETWEEN %d AND %d""" % (from_id, to_id, ))
    rows = cur.fetchall()
    for row in rows:
        print("%d %s" % (row[0], row[1]))

    print("ユーザー定義==========================")
    cur.execute("""SELECT * FROM test_sp(%d,%d)""" % (from_id, to_id, ))
    rows = cur.fetchall()
    for row in rows:
        print("%d %s" % (row[0], row[1]))

    cur.close()
    cnn.close()

except (psycopg2.OperationalError) as e:
    print (e)
python2.x
# -*- coding: cp932 -*-
# Winddows の場合は以下からダウンロード
#  http://www.stickpeople.com/projects/python/win-psycopg/
#

import psycopg2

try:
    cnn = psycopg2.connect("dbname=Sample001 host=localhost user=postgres password=xxxxx")
    cur = cnn.cursor()

    #試験データの整理
    pref_cd = 100
    cur.execute("""DELETE FROM t01prefecture WHERE PREF_CD >= %d"""
                % (pref_cd,))
    cnn.commit()

    print("単純なSELECT文==========================")
    from_id = 45
    to_id = 999
    cur.execute("""SELECT PREF_CD,PREF_NAME FROM t01prefecture
                WHERE PREF_CD BETWEEN %d AND %d""" % (from_id, to_id, ))
    rows = cur.fetchall()
    for row in rows:
        print("%d %s" % (row[0], unicode(row[1],'utf-8')))

    print("コミットの試験==========================")
    pref_cd = 100
    pref_name = u"モテモテ国"
    cur.execute(u"""INSERT INTO t01prefecture(PREF_CD, PREF_NAME)
                VALUES ('%s', '%s')""" % (pref_cd, pref_name))

    pref_cd = 101
    pref_name = u"野望の国"
    cur.execute(u"""INSERT INTO t01prefecture(PREF_CD,PREF_NAME)
                VALUES ('%s', '%s')""" % (pref_cd, pref_name,))
    cnn.commit()
    cur.execute("""SELECT PREF_CD,PREF_NAME FROM t01prefecture
                WHERE PREF_CD BETWEEN %d AND %d""" % (from_id, to_id, ))
    rows = cur.fetchall()
    for row in rows:
        print("%d %s" % (row[0],unicode(row[1],'utf-8')))


    print("ロールバックの試験==========================")
    pref_cd = 102
    pref_name = u"ロール"
    cur.execute(u"""INSERT INTO t01prefecture(PREF_CD,PREF_NAME)
                VALUES ('%s', '%s')""" % (pref_cd, pref_name,))

    cur.execute("""SELECT PREF_CD,PREF_NAME FROM t01prefecture
                WHERE PREF_CD BETWEEN %d AND %d""" % (from_id, to_id, ))
    rows = cur.fetchall()
    for row in rows:
        print("%d %s" % (row[0], unicode(row[1],'utf-8')))

    print("-------------------------")
    cnn.rollback()
    cur.execute("""SELECT PREF_CD,PREF_NAME FROM t01prefecture
                WHERE PREF_CD BETWEEN %d AND %d""" % (from_id, to_id, ))
    rows = cur.fetchall()
    for row in rows:
        print("%d %s" % (row[0], unicode(row[1],'utf-8')))

    print("ユーザー定義==========================")
    cur.execute("""SELECT * FROM test_sp(%d,%d)""" % (from_id, to_id, ))
    rows = cur.fetchall()
    for row in rows:
        print("%d %s" % (row[0], unicode(row[1],'utf-8')))

    cur.close()
    cnn.close()

except (psycopg2.OperationalError) as e:
    print (e)
雑感
Python3系は文字コードを意識しなくてもよさげ、Python2.XはUTF8で帰ってくるので、一旦UNICODEに変換してやらねばならない。

ストアドプロシージャーはORACLEのPL/SQLに近い。ただ、テーブル型を戻り値にする関数を指定できるので、ORACLEほど結果セットを返すのがしんどくない。


[PR]
by mima_ita | 2013-12-23 11:16 | python
PythonでORACLEを操作する
目的
Pythonでcx_Oracleを用いてOracleを操作する

環境
Python 2.7 または 3.3

1.Oracleクライアントをインストールする。この際、開発者用の環境をつくる。
 
2.以下からダウンロードしてインストールするか、easy_installする。
   cx_Oracle
   http://cx-oracle.sourceforge.net/

Pythonのコード
# -*- coding: cp932 -*-
# cx_Oracleを用いたPythonでのORACLE操作
#1.Oracleクライアントをインストールする。
# この際、開発者用の環境をつくる。
# (おそらく、OCIが必要?)
# 
#2.以下からダウンロードしてインストールするか、easy_installする。
#  cx_Oracle
#  http://cx-oracle.sourceforge.net/
import cx_Oracle
import os
os.environ["NLS_LANG"] = "JAPANESE_JAPAN.JA16SJISTILDE"
try:
    tns = cx_Oracle.makedsn("localhost", 1521, "Sample")
    conn = cx_Oracle.connect("user", "pass", tns)
    cur = conn.cursor()
    from_cd = 45
    to_cd = 200
    cur.execute("""SELECT * FROM T01PREFECTURE
                WHERE PREF_CD BETWEEN :arg1 AND :arg2""",
                arg1=from_cd,
                arg2=to_cd)
    rows = cur.fetchall()
    for r in rows:
        print("%d : %s" % (r[0], r[1]))

    print ("===================")
    print ("100を消す")
    cur.execute("""DELETE FROM T01PREFECTURE WHERE PREF_CD=:arg1""",
                arg1=100)

    cur.execute("""SELECT * FROM T01PREFECTURE
                WHERE PREF_CD BETWEEN :arg1 AND :arg2""",
                arg1=from_cd,
                arg2=to_cd)
    rows = cur.fetchall()
    for r in rows:
        print("%d : %s" % (r[0], r[1]))

    print ("------------------")
    print ("100 を追加")
    cur.execute("""INSERT INTO T01PREFECTURE
                VALUES (:arg1, :arg2)""",
                arg1=100,
                arg2="あたた")
    conn.commit()

    cur.execute("""SELECT * FROM T01PREFECTURE
                WHERE PREF_CD BETWEEN :arg1 AND :arg2""",
                arg1=from_cd,
                arg2=to_cd)
    rows = cur.fetchall()
    for r in rows:
        print("%d : %s" % (r[0], r[1]))

    print ("===================")
    print ("101追加")
    cur.execute("""INSERT INTO T01PREFECTURE
                VALUES (:arg1, :arg2)""",
                arg1=101,
                arg2="北斗")

    cur.execute("""SELECT * FROM T01PREFECTURE
                WHERE PREF_CD BETWEEN :arg1 AND :arg2""",
                arg1=from_cd,
                arg2=to_cd)
    rows = cur.fetchall()
    for r in rows:
        print("%d : %s" % (r[0], r[1]))

    print ("------------------")
    print ("ロールバック")
    conn.rollback()
    cur.execute("""SELECT * FROM T01PREFECTURE
                WHERE PREF_CD BETWEEN :arg1 AND :arg2""",
                arg1=from_cd,
                arg2=to_cd)
    rows = cur.fetchall()
    for r in rows:
        print("%d : %s" % (r[0], r[1]))

except (cx_Oracle.DatabaseError) as ex:
    error, = ex.args
    print (error.message)
使用感
OCI経由でやっているっぽいのでORACLEクライアントをインストールせねばならないのが結構面倒。

接続方法に癖がある。あと文字コードの指定は環境変数で。

ORACLEのPL/SQLはSQLSERVERと違って結果セット返さない。
(配列を返せるが、ここでは面倒なので実験していない)

明示的にCOMMITしないと変更は破棄される。



[PR]
by mima_ita | 2013-12-20 23:32 | python
PythonでODBC経由でSQLSERVERを操作する
目的
PythonでODBC経由でSQLSERVERを操作する。

環境
Python2.7 or 3.3
pyodbcの使用
SQLSERVER EXPRESS 2012

データベースの設定
SQL SERVER接続を許可する。

テーブル
CREATE TABLE [dbo].[T01Prefecture](
    [PREF_CD] [int] NOT NULL,
    [PREF_NAME] [varchar](10) NULL,
PRIMARY KEY CLUSTERED
(
    [PREF_CD] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ストアド
CREATE PROCEDURE [dbo].[test_sp]
    @from INT,
    @to INT
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Insert statements for procedure here
    SELECT * FROM T01Prefecture WHERE PREF_CD BETWEEN @from AND @to
END

CREATE PROCEDURE [dbo].[test_sp2]
    @cd1 INT,
    @cd2 INT
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Insert statements for procedure here
    SELECT * FROM T01Prefecture WHERE PREF_CD = @cd1
    SELECT * FROM T01Prefecture WHERE PREF_CD = @cd2
END
Pythonのコード
# -*- coding: cp932 -*-
# mssqlの操作サンプル
# pymssqlはVARCHARのエンコードが上手くいかないのでやめとく。
#easy_install pypyodbc

import pyodbc

try:
    cnn = pyodbc.connect("DRIVER={SQL Server};SERVER=127.0.0.1\SQLEXPRESS;" +
                         "UID=sa;PWD=xxxxxxxxx;DATABASE=Sample001")
    cur = cnn.cursor()

    #試験データの整理
    pref_cd = 100
    cur.execute("""DELETE FROM t01prefecture WHERE PREF_CD >= %d"""
                % (pref_cd,))
    cnn.commit()

    print("単純なSELECT文==========================")
    from_id = 45
    to_id = 999
    # 以下は環境の文字コードにあわせること!
    cur.execute("""SELECT PREF_CD,PREF_NAME FROM t01prefecture
                WHERE PREF_CD BETWEEN %d AND %d""" % (from_id, to_id, ))
    rows = cur.fetchall()
    for row in rows:
        print("%d %s" % (row[0], row[1]))

    print("コミットの試験==========================")
    pref_cd = 100
    pref_name = "モテモテ国"
    cur.execute("""INSERT INTO t01prefecture(PREF_CD, PREF_NAME)
                VALUES ('%s', '%s')""" % (pref_cd, pref_name))

    pref_cd = 101
    pref_name = "野望の国"
    cur.execute("""INSERT INTO t01prefecture(PREF_CD,PREF_NAME)
                VALUES ('%s', '%s')""" % (pref_cd, pref_name,))
    cnn.commit()

    print("ロールバックの試験==========================")
    pref_cd = 102
    pref_name = "ロール"
    cur.execute("""INSERT INTO t01prefecture(PREF_CD,PREF_NAME)
                VALUES ('%s', '%s')""" % (pref_cd, pref_name,))
    cnn.rollback()

    cur.execute("""SELECT PREF_CD,PREF_NAME FROM t01prefecture
                WHERE PREF_CD BETWEEN %d AND %d""" % (from_id, to_id, ))
    rows = cur.fetchall()
    for row in rows:
        print("%d %s" % (row[0], row[1]))

    print("ストアドプロシージャの試験==========================")
    cur.execute("""exec test_sp %d, %d """ % (from_id, to_id, ))
    rows = cur.fetchall()
    for row in rows:
        print("%d %s" % (row[0], row[1]))

    print("ストアドプロシージャの試験 複数 ====================")
    cur.execute("""exec test_sp2 %d, %d """ % (1, 10, ))
    while True:
        print ("レコードセット...")
        rows = cur.fetchall()
        for row in rows:
            print("%d %s" % (row[0], row[1]))
        if not cur.nextset():
            break

    cur.close()
    cnn.close()

except (pyodbc.Error) as e:
    print (e.args[1])
感想
pymssqlというライブラリがあるが、エンコードがうまくいっていないので却下。そもそもPython3xでは使えない。

pypyodbcもあり、今回紹介したpyodbcと同じような感じだが、python3.xでは使えない。


[PR]
by mima_ita | 2013-12-20 17:58 | python
pythonでMySQLにつなげる
目的
PythonでMySQLを操作する

環境
Python2.7 または3.3
mysql-connector-python
MySQL 5.6.15

データベースの設定

テーブル
CREATE TABLE `t01prefecture` (
  `PREF_CD` int(3) NOT NULL DEFAULT '0',
  `PREF_NAME` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`PREF_CD`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


単一のレコードセットを返すストアド
DELIMITER $$
CREATE DEFINER=`username`@`%` PROCEDURE `test_sp`(IN fromNo INT,
                                                  IN toNo INT)
BEGIN
    select * from t01prefecture WHERE PREF_CD BETWEEN fromNo AND toNo ;
END$$
DELIMITER ;

複数のレコードセットを返すストアド
DELIMITER $$
CREATE DEFINER=`username`@`%` PROCEDURE `test_sp2`(IN cd1 INT,IN cd2 INT)
BEGIN
  select * from t01prefecture WHERE PREF_CD = cd1;
  select * from t01prefecture WHERE PREF_CD = cd2;

END$$
DELIMITER ;

Functionの例
DELIMITER $$
CREATE DEFINER=`username`@`%` FUNCTION `test_fn`(cd INT) RETURNS varchar(10) CHARSET utf8
BEGIN
    DECLARE ret VARCHAR(10);
    SELECT PREF_NAME INTO ret  FROM t01prefecture WHERE PREF_CD = cd;
   
RETURN ret;
END$$
DELIMITER ;


Pythonのコード

# -*- coding: cp932 -*-
# mysqlの操作サンプル
#easy_install mysql-connector-python
import mysql.connector

try:
    cnn = mysql.connector.connect(host='localhost',
                                  port=3306,
                                  db='Sample001',
                                  user='root',
                                  passwd='root',
                                  charset="cp932")
    cur = cnn.cursor()

    #試験データの整理
    pref_cd = 100
    cur.execute("""DELETE FROM t01prefecture WHERE PREF_CD >= %d"""
                % (pref_cd,))
    cnn.commit()

    print("単純なSELECT文==========================")
    from_id = 45
    to_id = 999

    # 以下は環境の文字コードにあわせること!
    cur.execute("""SELECT PREF_CD,PREF_NAME FROM t01prefecture
                WHERE PREF_CD BETWEEN %d AND %d""" % (from_id, to_id, ))
    rows = cur.fetchall()
    for row in rows:
        print("%d %s" % (row[0], row[1]))

    print("コミットの試験==========================")
    pref_cd = 100
    pref_name = "モテモテ王国"
    cur.execute("""INSERT INTO t01prefecture(PREF_CD, PREF_NAME)
                VALUES ('%s', '%s')""" % (pref_cd, pref_name))

    pref_cd = 101
    pref_name = "野望の国"
    cur.execute("""INSERT INTO t01prefecture(PREF_CD,PREF_NAME)
                VALUES ('%s', '%s')""" % (pref_cd, pref_name,))
    cnn.commit()

    print("ロールバックの試験==========================")
    pref_cd = 102
    pref_name = "ロールバック"
    cur.execute("""INSERT INTO t01prefecture(PREF_CD,PREF_NAME)
                VALUES ('%s', '%s')""" % (pref_cd, pref_name,))
    cnn.rollback()

    print("ストアドプロシージャの試験==========================")
    cur.callproc("test_sp", (from_id, to_id))
    for rs in cur.stored_results():
        print("レコードセット...")
        rows = rs.fetchall()
        for row in rows:
            print ("%d %s" % (row[0], row[1]))

    print("ストアドプロシージャの試験(複数)==================")
    cur.callproc("test_sp2", (1, 100))
    for rs in cur.stored_results():
        print("レコードセット...")
        rows = rs.fetchall()
        for row in rows:
            print ("%d %s" % (row[0], row[1]))

    print("ファンクションの試験==========================")
    pref_cd = 100
    cur.execute("""SELECT test_fn(%d)""" % (pref_cd,))
    rows = cur.fetchall()
    for row in rows:
        print("code:%d name:%s" % (pref_cd, row[0]))

    cur.close()
    cnn.close()
except (mysql.connector.errors.ProgrammingError) as e:
    print (e)

MYSQLのストアドの雑感
・SQLSERVERに近い感じ。

・ストアドを実行したあとは、 cur.stored_resultsにレコードセットが入っている。。

・MySQL-pythonってライブラリもあるが3.x系で動作しないからやめとこう。使い方はだいたい同じ。
[PR]
by mima_ita | 2013-12-20 14:08 | python
Pythonでツイッターの検索を行う
目的
python_twitterを用いてツイッターの検索をする。

使用するAPI

search/tweets.json
https://dev.twitter.com/docs/api/1.1/get/search/tweets

application/rate_limit_status.json
https://dev.twitter.com/docs/api/1.1/get/application/rate_limit_status

注意!
APIを経由した検索は公式ページからの検索と結果が異なる場合があります。
公式では7日前のツイートでも検索されますが、APIの場合、過去のツイートはひっかかりません!



目的
検索する文字には以下のような論理式が使える
(えーりん OR 永琳) AND (BBA OR 婆 OR ババア)
その他の式についてはTwitterの高度の検索を実行して作成される演算子を参考にすると良い。
https://twitter.com/search-advanced

取得方法は時系列で取得する必要がある。
これは"result_type=recent"で実現できる。

1回の検索で100件しかとれない。


200件以上とりたいときは取得したstatusのidで最も小さいのを取得して、次に実行するときにmax_idのパラメータに与えてやればよい。
"max_id = 前回の最小id-1"

ただし、twitterのAPIの呼び出し制限は結構厳しいのでrate_limit_statusをみつつ行うこと。
rate_limit_statusを実行すると、各APIの最大回数と、残りの回数、リセット時間が取得できる。

コード
!/usr/bin/python
# -*- coding: utf-8 -*-
# python_twitter 1.1
import twitter
from twitter import Api
import sys
import time
reload(sys)
sys.setdefaultencoding('utf-8')
from collections import defaultdict



maxcount=1000
maxid =0
terms=["八意永琳","永琳","えーりん"]
search_str=" OR ".join(terms)

api = Api(base_url="https://api.twitter.com/1.1",
                  consumer_key='XXXXX',
                  consumer_secret='XXXXX',
                  access_token_key='XXXXX',
                  access_token_secret='XXXXX')
rate = api.GetRateLimitStatus()
print "Limit %d / %d" % (rate['resources']['search']['/search/tweets']['remaining'],rate['resources']['search']['/search/tweets']['limit'])
tm = time.localtime(rate['resources']['search']['/search/tweets']['reset'])
print "Reset Time  %d:%d" % (tm.tm_hour , tm.tm_min)
print "-----------------------------------------\n"
found = api.GetSearch(term=search_str,count=100,result_type='recent')
i = 0
while True:
  for f in found:
    if maxid > f.id or maxid == 0:
      maxid = f.id
    print f.text
    i = i + 1
  if len(found) == 0:
    break
  if maxcount <= i:
    break
  print maxid
  found = api.GetSearch(term=search_str,count=100,result_type='recent',max_id=maxid-1)

print "-----------------------------------------\n"
rate = api.GetRateLimitStatus()
print "Limit %d / %d" % (rate['resources']['search']['/search/tweets']['remaining'],rate['resources']['search']['/search/tweets']['limit'])
tm = time.localtime(rate['resources']['search']['/search/tweets']['reset'])
print "Reset Time  %d:%d" % (tm.tm_hour , tm.tm_min)


[PR]
by mima_ita | 2013-12-03 21:26 | python
Pythonでdictionaryの中を見やすく表示する
Pythonでdictionaryの中を見やすく表示する

def dict_tree(data,indent=0):
  for k, v in data.items():
    if isinstance(v, dict):
      print ' ' * indent, k
      dict_tree(v, indent+1)
    else:
      print ' ' * indent,k, ':' , type(v) ,':' , v

[PR]
by mima_ita | 2013-12-03 14:11 | python
tf-idfで文章の重み付けをする
■説明
MeCabで形態素解析を行い、文章中に含まれる名詞にかんしてtf-idfで重み付けをする。
nltk.TextCollection() を用いることで計算はおこなえる。

tf: Term Frequency 単語出現頻度
 文章jにおける単語iの出現回数 / 全文章で出現する総単語数

idf: Inverse Document Frequency 逆文章頻度
log(総ドキュメント数/単語iを含むドキュメント数)

tf-idf : tf * idf
 idfを逆数で取得しているのは、他の文章でよく使われる単語は、特定の文章の特徴をあらわすことにならないことを現している。
 つまり、他の文章で使われなくて、調査対象の文章でよく使われる単語は重くなる。

■コード

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import MeCab
import nltk
from collections import defaultdict
mecab = MeCab.Tagger("")

class tf_idf_result:
def __init__(self,doc):
self.text = ''.join(doc)
self.term_scores = defaultdict(int)

def set_score(self,term,score):
self.term_scores[term] = score

def get_tokens(text):
"""
テキストから単語のリストを取得する
text:UTF-8の文章
return 単語のリスト
"""
node = mecab.parseToNode(text)
words = []
while node:
fs = node.feature.split(",")
if (node.surface is not None) and node.surface != "" and fs[0] in [u'名詞']:
words.append(node.surface)
node = node.next
return words


all_text = [u'ここはまりさのゆっくりプレイスなのぜ!痛いめにあいたくなかったら、ゆっくりできない糞人間はあまあまをおいてさっさと出ていくのぜ!',
u'我輩は、まりさである。お飾りはない。どこで生まれたかも見当もつかぬ。なんでもゆっくりプレイスで「ゆんやー、ゆんやー」と泣いていたことだけは記憶している。我輩はここで初めて人間というものをみた。',
u'まりさは激怒した。かならずかの邪智暴虐の人間を除かねばらぬと決意した。まりさには政治がわからぬ。まりさは、町のゆっくりである。歌を歌い、れいむと遊んで暮らしていた。しかし、ゆっくりできないことには、ゆっくり一倍敏感であった。今日未明、まりさは村を出発して迷子になりました。おしまい。',
u'むかしむかし、あるところに、ありすとまりさとが住んでいました。ありすはゆっくりしに、まりさは川へゆっくりしに行きました。まりさが川でゆっくりしていると、ドンブラコ、ドンブラコと大きなれいむが流れてきました。沈みました。おしまい。',
u'むかしむかし、ある村に、心のやさしい、まりさというゆっくりがいました。まりさが海辺をとおりかかると、子供たちがゆっくり・れいむを捕まえていました。そばによってみると子供たちがみんなで、ゆっくり・れいむをいじめていました。「やい、くそ人間 。さっさとれいむから手を離すのぜ!さもないとこの最強のまりさ様がせいっさいするのぜ!」逆に制裁されました。おしまい',
u'ここはれいむのゆっくりプレイスだよ!ゆっくりしないででていってね!可愛くってごめんねー!']

docs = []
for txt in all_text:
docs.append( get_tokens(txt.encode('utf-8')) )

col = nltk.TextCollection(docs)

results = []

# tf : Term Frequency 単語出現頻度 文章jにおける単語iの出現回数/全文章で出現する総単語数
# idf : Inverse Document Frequency 逆文章頻度 log(総ドキュメント数/単語iを含むドキュメント数)
# tf-idf : tf * idf
for doc in docs:
ret = tf_idf_result(doc)
terms = list(set(doc))
for term in terms:
#print "%s : tf-idf%f tf;%f idf:%f" % (term, col.tf_idf(term, doc), col.tf(term, doc), col.idf(term, doc))
ret.set_score(term,col.tf_idf(term, doc))
results.append(ret)

i = 1
for ret in results:
print "(%d)の上位100位キーワード"%(i)
j = 1
for k, v in sorted(ret.term_scores.items(), key=lambda x:x[1], reverse=True):
print " %s : %f" % ( k, v )
if j > 100:
break
j = j + 1
i = i + 1



[PR]
by mima_ita | 2013-06-18 23:10 | python
テキストを類似度毎に階層的クラスタリングで分類してみた
■説明
・それぞれの文字列をmasiで類似度を計測する
 これは前回の記事参照

・clusterモジュールのHierarchicalClusteringを使用して階層的クラスタリングで分類する
easy_install cluster でインストールできる
 このアルゴリズムの説明は以下参照
 http://home.deib.polimi.it/matteucc/Clustering/tutorial_html/hierarchical.html

 HierarchicalClusteringのインスタンスを作るとき、第三引数で"single","complete","average"の3種類が選択できる。デフォルトはsingle. クラスターとクラスターを比較するさいに、最も近い距離動詞のアイテムで比較するか、平均するか、遠くのものを選択するかを選べる。

 階層型クラスタリングは全てのノードがそれぞれのノードに対する距離を計算しているのでアホみたいに遅い。

・pydotを経由してGraphVizで階層構造を表現する
 以下をダウンロードしてインストールする。
 http://www.graphviz.org/
 http://pyparsing.wikispaces.com/
 http://code.google.com/p/pydot/
 ★PATH を設定してdot.exeへのパスを設定しておく
 GraphVizで日本語を表示したい場合は、UTF-8のコードで記述して、ノードやエッジを作る際に、fontnameを指定してやればよろしい。

■コード

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
from cluster import HierarchicalClustering
import pydot
import MeCab
import nltk

mecab = MeCab.Tagger("")



def get_tokens(text):
"""
テキストから単語のリストを取得する
text:UTF-8の文章
return 単語のリスト
"""
node = mecab.parseToNode(text)
words = []
while node:
if (node.surface is not None) and node.surface != "":
words.append(node.surface)
node = node.next
return words

class token_data:
"""
トークンの情報
tokens : MeCabで解析した単語のセット
text : 解析元の文
"""
def __init__(self, text):
self.tokens = set(get_tokens(t.encode('utf-8')))
self.text = text

def score(t1, t2):
"""
階層クラスタリングの際の距離を計算する
t1 : token_data 単語セット
t2 : token_data 単語セット
"""
ret = nltk.metrics.distance.masi_distance(t1.tokens,t2.tokens)
return ret

def add_node(graph,next_id,node_r,data):
"""
Graphにノードを追加する
graph : 操作対象のグラフ
next_id : 次のノードに割り当てるID
node_r : 接続先のノード
data : 今回解析対象のノード
return 次のID
"""
if type(data) == tuple or type(data) == list:
node_data = pydot.Node(str(next_id), label=" ", style="filled", fillcolor="green",fontname = "ms ui gothic")
next_id=next_id+1
graph.add_node(node_data)
graph.add_edge(pydot.Edge(node_r, node_data))
for d in data:
next_id = add_node(graph,next_id,node_data,d)
else:
label = data.text
node_data = pydot.Node(str(next_id), label=label, style="filled", fillcolor="white",fontname = "ms ui gothic", shape="box")
next_id=next_id+1
graph.add_node(node_data)
graph.add_edge(pydot.Edge(node_r, node_data))
return next_id


tests = [u"Take it easy!",
u"Yu-.We can take it easy here even if mister rain fall.",
u"Yufufu...nobady can find Maricha.",
u"Reimyu is Mister Bird!",
u"Maricha has got the sky in her hand je!",
u"YAAAAAAAAAAAAAAAAAAAAAAA-HA!",
u"ここはまりさのゆっくりプレイスだよ!",
u"ここはまりさのゆっくりプレイスだよ!ここからさっさとでっていってね!",
u"ゆっくりしていってね!ここはまりさのゆっくりプレイスだよ!",
u"ここはまりさのゆっくりプレイスなのぜ!",
u"きょきょはまりちゃのゆっくちプレイちゅなのじぇ!",
u"ここはれいむのゆっくりプレイスだよ!",
u"むーしゃむーしゃするよ!しあわせー!",
u"ぷくー!",
u"ヒャッハーーー!!!!",
]
test_tokens = []
for t in tests:
test_tokens.append(token_data(t))

hc = HierarchicalClustering(test_tokens,score)
hc.cluster()
datas = hc.topo()

next_id = 0
graph = pydot.Dot(graph_type='digraph')
node_r = pydot.Node(str(next_id), label=" ", style="filled", fillcolor="green", fontname = "ms ui gothic")
graph.add_node(node_r)
next_id=next_id+1
for d in datas:
next_id = add_node(graph,next_id,node_r,d)

graph.write_png('HierarchicalClustering.png')


■結果
b0232065_2403864.png

[PR]
by mima_ita | 2013-06-18 02:43 | python
文字列の類似度の尺度について試してみた
MeCabで形態素解析したものをnltkを使用して距離を取得する。
今回実験した内容は次の機能
・編集距離
 nltk.metrics.distance.edit_distance
・Nグラム類似度
 nltk.bigramsによるバイグラムの取得。
・Jaccard距離
 nltk.metrics.distance.jaccard_distance
・MASI距離
 nltk.metrics.distance.masi_distance

■コード

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

import MeCab
import nltk

mecab = MeCab.Tagger("")

def get_tokens(text):
node = mecab.parseToNode(text)
words = []
while node:
if (node.surface is not None) and node.surface != "":
words.append(node.surface)
node = node.next
return words

print "単語の編集距離===================================================="
print "片方の文字がもう片方の文字列に変換するには、挿入、削除、置換を何回やらなければならないかを計算する。小さいほど類似"
s = u"まりさ"
tests = [u"まりさ",u"まりざ",u"まりちゃ",u"まり",u"まいしゃ",u"まっけんろー",u"れいむ",u"れいみゅ"]
for t in tests:
print t + str( nltk.metrics.distance.edit_distance(s,t) )

print "Nグラム類似度===================================================="
print "2つの文に共通するバイグラムがいくつあるか調べる。大きいほど類似"
s = u"ここはまりさのゆっくりプレイスだよ!"
tests = [u"ここはまりさのゆっくりプレイスだよ!",
u"ここはまりさのゆっくりプレイスだよ!ここからさっさとでっていってね!",
u"ゆっくりしていってね!ここはまりさのゆっくりプレイスだよ!",
u"ここはまりさのゆっくりプレイスなのぜ!",
u"きょきょはまりちゃのゆっくちプレイちゅなのじぇ!",
u"ここはれいむのゆっくりプレイスだよ!",
u"むーしゃむーしゃするよ!しあわせー!",
u"ぷくー!"
]
ceo_bigrams = nltk.bigrams( get_tokens(s.encode('utf-8')),pad_right=True,pad_left=True)
print "元文章のバイグラムの数:" + str(len(set(ceo_bigrams)))
for t in tests:
cto_bigrams = nltk.bigrams( get_tokens(t.encode('utf-8')),pad_right=True,pad_left=True)
print " " + t +":"+ str(len(set(ceo_bigrams).intersection(set(cto_bigrams))))

print "Jaccard距離===================================================="
print "2つの集合の類似度を |set1 ∩ set2| / |set1 ∪ set2|であらわした。小さいほど類似"
for t in tests:
r = nltk.metrics.distance.jaccard_distance(set(get_tokens(s.encode('utf-8'))),set(get_tokens(t.encode('utf-8'))))
print " " + t + ":" + str(r)

print "MASI距離===================================================="
print "Jaccard距離の改造重複があったら距離が短くなる。小さいほど類似"
for t in tests:
r = nltk.metrics.distance.masi_distance(set(get_tokens(s.encode('utf-8'))),set(get_tokens(t.encode('utf-8'))))
print " " + t + ":" + str(r)


■実行結果

C:\dev\python\nltk>python distance.py
単語の編集距離====================================================
片方の文字がもう片方の文字列に変換するには、挿入、削除、置換を何回やらなければならないかを計算する。小さいほど類似
まりさ0
まりざ1
まりちゃ2
まり1
まいしゃ3
まっけんろー5
れいむ3
れいみゅ4
Nグラム類似度====================================================
2つの文に共通するバイグラムがいくつあるか調べる。大きいほど類似
元文章のバイグラムの数:9
ここはまりさのゆっくりプレイスだよ!:9
ここはまりさのゆっくりプレイスだよ!ここからさっさとでっていってね!:9
ゆっくりしていってね!ここはまりさのゆっくりプレイスだよ!:8
ここはまりさのゆっくりプレイスなのぜ!:6
きょきょはまりちゃのゆっくちプレイちゅなのじぇ!:1
ここはれいむのゆっくりプレイスだよ!:7
むーしゃむーしゃするよ!しあわせー!:2
ぷくー!:0
Jaccard距離====================================================
2つの集合の類似度を |set1 ∩ set2| / |set1 ∪ set2|であらわした。小さいほど類似
ここはまりさのゆっくりプレイスだよ!:0.0
ここはまりさのゆっくりプレイスだよ!ここからさっさとでっていってね!:0.428571428571
ゆっくりしていってね!ここはまりさのゆっくりプレイスだよ!:0.111111111111
ここはまりさのゆっくりプレイスなのぜ!:0.4
きょきょはまりちゃのゆっくちプレイちゅなのじぇ!:0.923076923077
ここはれいむのゆっくりプレイスだよ!:0.222222222222
むーしゃむーしゃするよ!しあわせー!:0.833333333333
ぷくー!:1.0
MASI距離====================================================
Jaccard距離の改造重複があったら距離が短くなる。小さいほど類似
ここはまりさのゆっくりプレイスだよ!:0.0
ここはまりさのゆっくりプレイスだよ!ここからさっさとでっていってね!:0.617142857143
ゆっくりしていってね!ここはまりさのゆっくりプレイスだよ!:0.404444444444
ここはまりさのゆっくりプレイスなのぜ!:0.802
きょきょはまりちゃのゆっくちプレイちゅなのじぇ!:0.974615384615
ここはれいむのゆっくりプレイスだよ!:0.743333333333
むーしゃむーしゃするよ!しあわせー!:0.945
ぷくー!:1.0

C:\dev\python\nltk>

[PR]
by mima_ita | 2013-06-13 17:10 | python
PythonでXpathを利用したHTMLの操作
urlib2で取得した内容をlxmlに渡して遣ればよろしい。


# -*- coding: utf/-8 -*-
# lxmlのインストール
# easy_install lxml
import urllib2
import lxml.html
import codecs
import datetime, time
import sys

def download(url):
html = ""
for line in urllib2.urlopen (url):
html = html + "\n" + line
html = html.replace("\r","\n")
root = lxml.html.fromstring(html)
contents = root.xpath('//dd')
for content in contents:
print content.text_content().encode('utf-8')

html = sys.argv[1]
download(html)



■使用例:
2chの内容を落としてCabochaによる係り受けの解析をする
http://needtec.sakura.ne.jp/serif/main.py?Analyze2ch
[PR]
by mima_ita | 2013-06-11 17:24 | python



実験ですお
検索
カテゴリ
最新の記事
.NET4.5におけるasy..
at 2014-07-02 00:46
.NETでTwitterを検..
at 2014-06-29 00:49
Redmineのプラグインで..
at 2014-06-28 03:29
IO.popenのwrite..
at 2014-06-28 03:25
RedmineのWikiでU..
at 2014-06-28 03:16
以前の記事
最新のトラックバック
その他のジャンル
ブログパーツ