Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

550 views

Published on

Published in: Data & Analytics
  • Be the first to comment

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

  1. 1. データヴィジュアライズのための 簡単なWeb API開発まめ知識 2014 Shizuoka.py #4
  2. 2. 自己紹介 ♪ オーイシ(@oec014) ♪ dogrun Inc. ♪ 電子書籍(企画・デザイン等) 現在は読書の補助&拡張ツールの開発… ♪データマイニング、ビジュアライズなど
  3. 3. 今回の資料は… • 特に、とにかく簡単にWeb APIを作ってみたい!とい う人向けです。 • データセットを見てどのように実装できるか、デザイン できるかなど、作業を見通すためにも、普段サービス構 築に関わらない人もAPIの理解を深めることがサービス 構築にとても立つはず。 • PythonのORマッパーつかうと簡単にできます。
  4. 4. つぶやきの音楽情報集めてます • Twitterで#nowplaying されたつぶやきを集めて、アーティスト、楽 曲のランキングを作っています。(beatcaster.net) • 音楽そのものの価値に加えて、コンテンツへの言及やユーザーの関わ り方がコンテンツ波及の重要な要素になると考えています。ユーザー のコンテンツへの関わり(コンテクスト)の情報がさらにコンテン ツの消費を広げる要素になるような情報配信を模索しています。 • TWでは、季節に関連して集中して聞かれる(つぶやかれる)曲を見 かけます。「この日にこの曲がよく聞かれる」というような情報がコ ンテンツの波及に有効かも。
  5. 5. 試しに「この日に聞かれる音楽」の Web APIを作ってみました • 日本語のつぶやきに限定して、1日に27000~2900程 度の音楽がTwitterで#nowplayingされます。このつぶ やきを2年分集計しました。 • つぶやきから機械的に曲名、アーティスト名抽出をして います。正規化していない…のでノイズ多めです。 • 『つぶやきの量』&TFIDFで『特定の日の特定の曲のつ ぶやきの重みの指標』をJSONで返します。
  6. 6. musicinfo_count DataFrame 特定日のTWをカウント NPs (ある日の総TW数) DataFrameで集計 ある曲のTWが有った日 をカウント Days (TWのあった日数) tfidfの値をupdate ただし10TW/day以 上の曲に限る。 musicinfo_all MySQL TW数をカウント musicinfo_count MySQL tfidf = (count/NPs) * log( 1/(Days/365) ) TFIDF集計プロセス
  7. 7. musicinfo_count day: VARCHAR count: INT song: VARCHAR artist: VARCHAR tfidf: FLOAT import_ja user: VARCHAR id: BIGINT day: VARCHAR txt: VARCHAR musicinfo song/artist 抽出: musicinfo_all user: VARCHAR date: DATE song: VARCHAR artist: VARCHAR txt: VARCHAR count: count 1日に10件以上のデータのある song-artistの組み合わせのみ登録 tfidf集計: get tfidf update category artist: VARCHAR category: VARCHAR API用データベースの概念モデル
  8. 8. df = pd.DataFrame(dic, columns=['id', 'count', 'tfidf']) plt.scatter(df['count'], df['tfidf']) plt.show() TW数 TFIDF
  9. 9. APIサーバを簡単に作るために… ORマッパーを使います。 • Webサービス構築にORMを使うとデータベースとの接 続処理を専用のクラスに任せ、その処理を意識せずオブ ジェクトの追加や取り出しができるようになります。 • 今回の例では自分が軽量フレームワークのFlaskとのセッ トでよく使っている”SQLAlchemyで”サンプルのサービ スを作っています。
  10. 10. モデルの定義とセッションの初期化 テーブル定義とクラスマッピング 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 モジュールを作りアプリケーション内で使いまわします。
  11. 11. モデルの定義とセッションの初期化 セッションの作成 ##~いろいろ省略 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とデータベースとの対話を全て担当して、データベース から読み出したり生成したマッピングインスタンスを保存しておく場所」とのこと。
  12. 12. ORMを使ったデータの取得 単純なselect SQL では select * from Music; ! SQLAlchemyでは result = session.query(Music).all() ! ※SQLAlchemyでは、Sessionのquery() メソッドを 使ってQueryオブジェクトを生成します。
  13. 13. 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)
  14. 14. 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()
  15. 15. 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")
  16. 16. musicinfo_count day: VARCHAR count: INT song: VARCHAR artist: VARCHAR tfidf: FLOAT import_ja user: VARCHAR id: BIGINT day: VARCHAR txt: VARCHAR musicinfo song/artist 抽出: musicinfo_all user: VARCHAR date: DATE song: VARCHAR artist: VARCHAR txt: VARCHAR count: count 1日に10件以上のデータのある song-artistの組み合わせのみ登録 tfidf集計: get tfidf update category artist: VARCHAR category: VARCHAR API用データベースの概念モデル
  17. 17. musicinfo_count marshmallow query category JSON生成のプロセス day: VARCHAR count: INT song: VARCHAR artist: VARCHAR tfidf: FLOAT SQLAlchemy filter() API (getRanking) song: artist: count: tfidf: category: json byday: %m-%d d: %d m: %m c:[idol, voice actor, その他] artist: VARCHAR category: VARCHAR
  18. 18. 別テーブルの項目の追加 内部結合を含む条件指定 単純な内部結合はテーブルとカラムを指定し、 filter()メソッドを複数AND条件で結合する。 ! session.query(ArtistCategory). filter(Music.artist==ArtistCategory.artist).filter(Music.artist==artist).all() ! !
  19. 19. 別テーブルの項目の追加 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メソッドに渡します。
  20. 20. 別テーブルの項目の追加 シリアライザで項目を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テーブルの 結合した項目を取得し追加ます。
  21. 21. 別テーブルの項目の追加 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条件でリストに追加
  22. 22. D3.js データをAPIをD3.jsを使って視覚化してみます
  23. 23. 次回Shizuoka.pyがあるならやりたいこと… RDF Triplestore用のORMとして、SQLAlchemyと近いコードで記述でき る”RDFAlchemy”があるようです。 ! >>> c = Company.query.get_by(symbol = 'IBM') >>> print(c.companyName) International Business Machines Corp.

×