shizuokapy4_データヴィジュアライズのための簡単なweb api開発まめ知識

23
データヴィジュアライズのための 簡単なWeb API開発まめ知識 2014 Shizuoka.py #4

Upload: nao-oec

Post on 12-Jul-2015

178 views

Category:

Data & Analytics


0 download

TRANSCRIPT

Page 1: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

データヴィジュアライズのための簡単なWeb API開発まめ知識

2014 Shizuoka.py #4

Page 2: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

自己紹介

♪ オーイシ(@oec014) ♪ dogrun Inc. ♪ 電子書籍(企画・デザイン等) 現在は読書の補助&拡張ツールの開発… ♪データマイニング、ビジュアライズなど

Page 3: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

今回の資料は…• 特に、とにかく簡単にWeb APIを作ってみたい!という人向けです。

• データセットを見てどのように実装できるか、デザインできるかなど、作業を見通すためにも、普段サービス構築に関わらない人もAPIの理解を深めることがサービス構築にとても立つはず。

• PythonのORマッパーつかうと簡単にできます。

Page 4: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

つぶやきの音楽情報集めてます

• Twitterで#nowplaying されたつぶやきを集めて、アーティスト、楽曲のランキングを作っています。(beatcaster.net)

• 音楽そのものの価値に加えて、コンテンツへの言及やユーザーの関わり方がコンテンツ波及の重要な要素になると考えています。ユーザーのコンテンツへの関わり(コンテクスト)の情報がさらにコンテンツの消費を広げる要素になるような情報配信を模索しています。

• TWでは、季節に関連して集中して聞かれる(つぶやかれる)曲を見かけます。「この日にこの曲がよく聞かれる」というような情報がコンテンツの波及に有効かも。

Page 5: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

試しに「この日に聞かれる音楽」のWeb APIを作ってみました• 日本語のつぶやきに限定して、1日に27000~2900程度の音楽がTwitterで#nowplayingされます。このつぶやきを2年分集計しました。

• つぶやきから機械的に曲名、アーティスト名抽出をしています。正規化していない…のでノイズ多めです。

• 『つぶやきの量』&TFIDFで『特定の日の特定の曲のつぶやきの重みの指標』をJSONで返します。

Page 6: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

musicinfo_countDataFrame

特定日のTWをカウント

NPs(ある日の総TW数)

Days(TWのあった日数)

ある曲のTWが有った日をカウント

tfidfの値をupdate

ただし10TW/day以上の曲に限る。

musicinfo_allMySQL

TW数をカウント

musicinfo_countMySQL

tfidf = (count/NPs) * log( 1/(Days/365) )

DataFrameで集計

TFIDF集計プロセス

Page 7: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

day: VARCHARcount: INTsong: VARCHARartist: VARCHARtfidf: FLOAT

musicinfo_count

user: VARCHARdate: DATEsong: VARCHARartist: VARCHARtxt: VARCHAR

musicinfo_all

user: VARCHARid: BIGINTday: VARCHARtxt: VARCHAR

import_ja

song/artist 抽出:

musicinfo

count:

count

tfidf集計:

get tfidf

1日に10件以上のデータのあるsong-artistの組み合わせのみ登録

update

artist: VARCHARcategory: VARCHAR

category

API用データベースの概念モデル

Page 8: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

df = pd.DataFrame(dic, columns=['id', 'count', 'tfidf']) plt.scatter(df['count'], df['tfidf']) plt.show()

TW数

TFIDF

Page 9: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

APIサーバを簡単に作るために…ORマッパーを使います。

• Webサービス構築にORMを使うとデータベースとの接続処理を専用のクラスに任せ、その処理を意識せずオブジェクトの追加や取り出しができるようになります。

• 今回の例では自分が軽量フレームワークのFlaskとのセットでよく使っている”SQLAlchemyで”サンプルのサービスを作っています。

Page 10: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

モデルの定義とセッションの初期化テーブル定義とクラスマッピング

from sqlalchemy import Table, Column, Integer, String, Float from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class Music(Base): __tablename__ = 'musicinfo_count' id = Column(Integer, primary_key=True) day = Column(String(12)) song = Column(String(100)) artist = Column(String(200)) count = Column(Integer) tfidf = Column(Float) def __init__(self, id, day, song, artist, count, tfidf): self.id = id self.day = day self.song = song self.artist = artist self.count = count self.tfidf = tfidf class ArtistCategory(Base): __tablename__ = 'artist_category' id =Column(Integer, primary_key=True) artist = Column(String(200)) category = Column(String(10)) def __init__(self, artist, category): self.artist = artist self.category = category

モジュールを作りアプリケーション内で使いまわします。

Page 11: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

モデルの定義とセッションの初期化セッションの作成

##~いろいろ省略

from sqlalchemy import create_engine, Date, and_, or_ from sqlalchemy.orm import sessionmaker, join from music import Music, Base, ArtistCategory from marshmallow import fields, Schema, Serializer import json ##~いろいろ省略

!Session = sessionmaker() engine = create_engine('mysql://root:xxx@localhost/xxx',encoding='utf-8)') Base.metadata.create_all(engine) Session.configure(bind=engine) session = Session()

SQLAlchemy のSessionは「ORMとデータベースとの対話を全て担当して、データベースから読み出したり生成したマッピングインスタンスを保存しておく場所」とのこと。

Page 12: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

ORMを使ったデータの取得単純なselect

SQL では select * from Music; !SQLAlchemyでは result = session.query(Music).all() !※SQLAlchemyでは、Sessionのquery() メソッドを 使ってQueryオブジェクトを生成します。

Page 13: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

ORMを使ったデータの取得filterによる条件指定のパターン• 単純な問い合わせ。all()を実行することでDBに実際に問い合わせが発生する。 session.query(Model).filter(Model.objectname == “hoo”).all() • カンマ区切りでAND条件を指定 session.query(Model).filter(Model.object1==“hoo”, Model.object2==‘’bar” • filterメソッドの複数指定でAND条件 session.query(Model).filter(Model.id==1).filter(Model.name==“hoo”).allI() • OR条件 session.query(Model).filter(or_(Model.id==1, Model.name==“foo”).all() • ORとANDの組み合わせ session.query(Model).filter(or_(Model.id==1, Model.name==“hoo”), Model.value==1).all() • SQL文を指定 session.execute(“SELECT * from musicinfo_count”) • LIKEによる部分一致 session.querry(Model).filter(Model.name.like(‘%hoge%’).allI() • IN演算子 session.query(Model).filter(Model.id.in_([1,2,3])).all() • BETWEEN演算子 session.query(Model).filter(Model.value.between(1,3)

Page 14: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

ORMを使ったデータの取得単純な条件指定でのデータ取得の例

@app.route('/feature')

def getRanking():

days = request.args.get("byday")

if days:

mu = session.query(Music).filter(Music.day.like('%'+ days +’%’)) \

.order_by(Music.tfidf.desc()).all()

Page 15: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

ORMを使ったデータの取得marshmallowによるデータのシリアライズ

from marshmallow import fields, Schema, Serializer import json !##~諸々省略

@app.route('/feature') def getRanking(): days = request.args.get("byday") if days: mu = session.query(Music).filter(Music.day.like('%'+ days +’%')).\ order_by(Music.tfidf.desc()).all() serialized = muserializer(mu, many=True).data return json.dumps(serialized, ensure_ascii=False).encode('utf-8') !class muserializer(Serializer): class Meta: fields = ("song", "artist","count", "tfidf")

Page 16: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

day: VARCHARcount: INTsong: VARCHARartist: VARCHARtfidf: FLOAT

musicinfo_count

user: VARCHARdate: DATEsong: VARCHARartist: VARCHARtxt: VARCHAR

musicinfo_all

user: VARCHARid: BIGINTday: VARCHARtxt: VARCHAR

import_ja

song/artist 抽出:

musicinfo

count:

count

tfidf集計:

get tfidf

1日に10件以上のデータのあるsong-artistの組み合わせのみ登録

update

artist: VARCHARcategory: VARCHAR

category

API用データベースの概念モデル

Page 17: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

JSON生成のプロセス

SQLAlchemy

day: VARCHARcount: INTsong: VARCHARartist: VARCHARtfidf: FLOAT

musicinfo_count

filter()

API (getRanking)song:artist:count:tfidf:category:

json

byday: %m-%dd: %dm: %mc:[idol, voice actor, その他]

query

marshmallow

artist: VARCHARcategory: VARCHAR

category

Page 18: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

別テーブルの項目の追加内部結合を含む条件指定

単純な内部結合はテーブルとカラムを指定し、 filter()メソッドを複数AND条件で結合する。 !session.query(ArtistCategory).\ filter(Music.artist==ArtistCategory.artist).filter(Music.artist==artist).all() !!

Page 19: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

別テーブルの項目の追加queryのリスト化

複合的な条件指定にクエリをリスト化する方法があります。 検索条件が複雑になったときのフィルタを書きやすいかも。def getRanking2(): d = request.args.get("d") m = request.args.get("m") c = request.args.get("c") params = [] if d: md = m + "-" + d params.append(Music.artist==ArtistCategory.artist) params.append(Music.day==md) params.append(ArtistCategory.category==c) p = and_(*params) mu = session.query(Music).filter(p).all() serialized = mucatserializer(mu, many=True).data return json.dumps(serialized, ensure_ascii=False).encode('utf-8')

filterの条件をリストに追加し and_メソッドで条件を結合した後 リストをfilterメソッドに渡します。

Page 20: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

別テーブルの項目の追加シリアライザで項目をJSONに追加する

class mucatserializer(Serializer):

category = fields.Method("get_category")

def get_category(self, Music):

ar = Music.artist

return getcategory(ar)

class Meta:

fields = ("song", "artist", "count", "tfidf", "category")

def getcategory(artist): name = session.query(ArtistCategory).filter(Music.artist==ArtistCategory.artist)\ .filter(Music.artist==artist).all() if name: return name[0].category else: return ""

シリアライザ内でArtistCategoryテーブルの 結合した項目を取得し追加ます。

Page 21: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

別テーブルの項目の追加AND と ORの複合条件

if ct: cts = ct.split(',') if len(cts) == 1: if "other" in ct: params.append(ArtistCategory.category=="") elif "VA" in ct: params.append(ArtistCategory.category=="VA") elif "IDOL" in ct: params.append(ArtistCategory.category=="IDOL") elif len(cts) == 2: param = (ArtistCategory.category==cts[0]) for item in cts: param = param | (ArtistCategory.category==item) params.append(param) md = m + "-" + d params.append(Music.artist==ArtistCategory.artist) params.append(Music.day==md) p = and_(*params) mu = session.query(Music).filter(p).all() serialized = mucatserializer(mu, many=True).data return json.dumps(serialized, ensure_ascii=False).encode('utf-8')

OR条件でリストに追加

AND条件でリストに追加

Page 22: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

D3.jsデータをAPIをD3.jsを使って視覚化してみます

Page 23: Shizuokapy4_データヴィジュアライズのための簡単なWeb API開発まめ知識

次回Shizuoka.pyがあるならやりたいこと…

RDF Triplestore用のORMとして、SQLAlchemyと近いコードで記述できる”RDFAlchemy”があるようです。 !>>> c = Company.query.get_by(symbol = 'IBM') >>> print(c.companyName) International Business Machines Corp.