20210504のPythonに関する記事は30件です。

LinkedIn Visualizer ~Dash & Plotlyを用いて LinkedIn データ可視化 Web アプリを作る~

1. はじめに 今回、plotly、dash というライブラリを用いて LinkedIn データを可視化する Web アプリを作っていこうと思います。 完成イメージは下の画像のような感じです。 要は、 1. ユーザーがアップロードしたデータに応じて 2. plotlyでグラフを書き 3. グラフをユーザーに返してあげる ような Dash アプリケーションを作ろうというものです。 https://linkedin-visualizer.herokuapp.com/ にて試していただくこともできます。 サンプルデータは こちら をお使いください。 LinkedInアカウントをお持ちの方は、(取得方法) に沿って Connections.csv というファイルを取得すると、ご自身のデータを可視化することができます。 2. Plotly、Dashについて 2.1 Plotly Document から引用します Plotly's Python graphing library makes interactive, publication-quality graphs. Examples of how to make line plots, scatter plots, area charts, bar charts, error bars, box plots, histograms, heatmaps, subplots, multiple-axes, polar charts, and bubble charts. (https://plotly.com/python/) 注目すべきは interactive というところ。 例えばマウスをホバーするとその時点の数字としてのデータが表示されたり、 ズームしたりできます。 実は、Dash Core Componentというモジュールを用いると、スライサーをつけたり pull down をつけたりと、もう少し高度なことができます。 2.2 Dash これも Document から引用します。 Dash is a productive Python framework for building web analytic applications. Written on top of Flask, Plotly.js, and React.js, Dash is ideal for building data visualization apps with highly custom user interfaces in pure Python. It's particularly suited for anyone who works with data in Python. Through a couple of simple patterns, Dash abstracts away all of the technologies and protocols that are required to build an interactive web-based application. Dash is simple enough that you can bind a user interface around your Python code in an afternoon. Dash apps are rendered in the web browser. You can deploy your apps to servers and then share them through URLs. Since Dash apps are viewed in the web browser, Dash is inherently cross-platform and mobile ready. この中で、"interactive web-based application" を簡単に構築できて、サーバーにデプロイすれば他の人とも作成物を共有できる、ということが書かれています。 ここに書かれていることを信じてやってみます。 今回はインタラクティブ性を「ユーザーがアップロードしたデータに応じたグラフのレンダリング」として与えることとし、 アプリケーションは Heroku サーバにデプロイすることとします。 3. 開発 ということで、作っていきます。 掲載するソースコードの全体は https://github.com/camsenec/linkedIn-visualization にあります。 実装は、 1. ユーザーがアップロードしたデータに応じて 2. plotlyでグラフを書き 3. グラフをユーザーに返してあげる という流れで進めます。 使用したモジュールとそのバージョンは以下です。必要に応じてインストールしてください。 numpy==1.20.1 dash==1.20.0 plotly==4.14.3 pandas==1.2.2 dash_html_components==1.1.3 dash_core_components==1.16.0 dash_table==4.11.3 3.1 準備 とりあえずDashアプリケーションを実行してみましょう。 app.py import dash import dash_html_components as html app = dash.Dash(__name__) app.layout=html.P("Hello World") if __name__ == "__main__": app.run_server(debug=True, use_reloader=True) というファイルを作成したうえで実行です。 python app.py 流れは、 1. Dashアプリケーションのインスタンスを作って 2. レイアウトを定義して 3. 実行する という形です。 コマンドライン上に Dash is running on http://127.0.0.1:8050/ といった表示がされるのでアクセスしてみましょう。すると、こんなページが見えるはずです。 このapp.layoutの値を変えれば、好きなようにhtmlレイアウトを構成できます。 ということで、こんな感じにしましょう。 app.py # Initiate Application Instance app = dash.Dash(__name__) app.title = "LinkedIn Visualizer" # HTML document that is initially displayed, which consists of a title area and an input form) app.layout = html.Div(children=[ # title area html.Div( children=[ html.H1( children="LinkedIn Visualizer", className="header-title" ), html.P( children="Analyze your LinkedIn Data", className="header-description", ), ], className="header", ), ]) if __name__ == "__main__": app.run_server(debug=True, use_reloader=True) CSSファイルやJSファイルは、assetsというディレクトリを作成しその配下に置くことで自動的に読み込まれます ( https://dash.plotly.com/dash-enterprise/static-assets )。 今回作るアプリのassetsディレクトリ内ファイルは、簡単な style.css のみで、 https://github.com/camsenec/linkedIn-visualization/tree/master/assets にあります。 assets/style.css を配置するとこんな感じになります。 ではこれより機能実装していきましょう。 3.2 機能別実装 3.2.1 ユーザーのファイルアップロード ファイルをアップロードするためのフォームには、dash_core_components.Upload() を用いることができます。 今回は Documentation で例示されているフォーム をほぼそのまま利用します。 app.py import dash import dash_core_components as dcc import dash_html_components as html from dash.dependencies import Input, Output, State import visualizer # Initiate Application Instance app = dash.Dash(__name__) app.title = "LinkedIn Visualizer" # HTML document that is initially displayed, which consists of a title area and an input form) app.layout = html.Div(children=[ # title area html.Div( children=[ html.H1( children="LinkedIn Visualizer", className="header-title" ), html.P( children="Analyze your LinkedIn Data", className="header-description", ), ], className="header", ), # input form dcc.Upload( id='upload-data', children=html.Div([ 'Drag and Drop or ', html.A('Select your Connections.csv') ]), style={ 'width': '100%', 'height': '60px', 'lineHeight': '60px', 'borderWidth': '1px', 'borderStyle': 'dashed', 'borderRadius': '5px', 'textAlign': 'center', 'margin': '10px' }, # Allow multiple files to be uploaded multiple=True ), # a hidden html element html.Div(id='output-data-upload'), ]) 次に、アップロードされたファイルを処理する関数を書きます。この関数はコールバックとして実装し、アップロードフォームに紐づけます。具体的には以下のようにします。これもDocumentation で例示されているもの をほぼそのまま利用しています。 app.py @app.callback(Output('output-data-upload', 'children'), Input('upload-data', 'contents'), State('upload-data', 'filename'), State('upload-data', 'last_modified')) def update_output(list_of_contents, list_of_names, list_of_dates): if list_of_contents is not None: children = [ visualizer.parse_contents(c, n, d) for c, n, d in zip(list_of_contents, list_of_names, list_of_dates)] return children 簡単に解説すると、この関数は id=output-data-uploadで参照される HTML element の children (=アップロードフォーム) に入力されたファイルを受け取り contents と filename を State としてもち id=output-data-uploadで参照される HTML element の children というフィールドに返り値を代入する ということをします。つまり、dcc.Upload() 内の # a hidden html element html.Div(id='output-data-upload') が、ユーザーのファイルアップロードに応じて # a hidden html element # children is the return value of upload_output function html.Div(id='output-data-upload', children=children) と形を変えます。この children に HTML element を与えてあげることで、動的なビューを生成することができます。 このあとのステップは 2. plotlyでグラフを書き 3. グラフをユーザーに返してあげる という形ですが、これまで行ってきたことを考えると、 plotlyでグラフを書いて、HTML フォーマットでレイアウトして、そのレイアウトを返却する関数 を書けばよさそうです。その返り値が html.Div(id='output-data-upload', children=children) の children に代入され、グラフビューを生成することになります。 3.2.2 plotlyでグラフを書く Plotlyでのグラフの書き方そのものについてはこの記事では言及しません。公式ページに様々な例が紹介されており、それぞれコードを参照することができます。 また、Qiita上にも [Python] Plotlyでぐりぐり動かせるグラフを作る JavaScriptとQiitaAPIで取得した人気タグ情報をplotlyで散布図表示してみる といった記事を見つけることができました。 今回は、Connections.csvという 以下のような形式のデータ(取得方法 )を用います。 Connections.csv First Name,Last Name,Email Address,Company,Position,Connected On Mcqueen, Mejiro, mcqueen@mejiro.com, Mejiro Shouji, Race Horse, 04-May-21 ... このデータをもとに、 コネクション数の変化を表すグラフ つながっている人の所属分布 つながっている人が所属している企業 つながっている人が働いているポジション を図示することにします。 graph.py import plotly.graph_objects as go import plotly.express as px import datetime # Changes of the number of connections def trend(connections_df): # This format list is prepared for the format variety # of LinkedIn Connection.csv dataset. format_cand = ["%d %b %y", "%d %b %Y", "%d-%b-%y", "%d-%b-%Y"] for format in format_cand: try: connections_df["Connected On"] = connections_df["Connected On"].apply( lambda x: datetime.datetime.strptime(x, format).strftime("%Y-%m-%d")) except: print("format error") continue else: break df = connections_df.groupby(by="Connected On").count().reset_index() df["count"] = 0 for i, index in enumerate(df.index): if i == df.index[0]: df.loc[index,"count"] = df.loc[index,"First Name"] else: df.loc[index,"count"] = df.iloc[i-1]["count"] + df.loc[index,"First Name"] fig = go.Figure() fig.add_trace(go.Scatter(x=df["Connected On"], y=df["count"])) fig.update_layout(title='Changes of your number of Connections', xaxis_title='Connected On', yaxis_title='Number') return fig # Distribution of companies connected people work at def company_hist(connections_df): fig = px.histogram(connections_df, x = "Company") fig.update_layout(title='Distribution of companies your connected people work') return fig # Companies where connected people work def company_treemap(connections_df): df_by_company = connections_df.groupby(by="Company").count().reset_index().sort_values( by="First Name", ascending=False).reset_index(drop=True) company_treemap = px.treemap(df_by_company[:100], path=["Company"], values="First Name", labels={"First Name": "Count"}) company_treemap.update_layout(title='Companies where your connected people work') return company_treemap # Job Positions of connected people def position_treemap(connections_df): df_by_position = connections_df.groupby(by="Position").count().reset_index().sort_values( by="First Name", ascending=False).reset_index(drop=True) position_treemap = px.treemap(df_by_position[:100], path=["Position"], values="First Name", labels={"First Name": "Count"}) position_treemap.update_layout(title='Job Positions of your connected people') print(type(position_treemap)) return position_treemap 3.2.3 グラフをユーザーに返す 最後にステップ 2 で定義した関数を呼び出し、ページ内に HTML Element として組み込んでいきます。parse_contents() という関数はファイルアップロードと同時に呼び出されるコールバック関数 update_output() 内で呼び出していた関数です。 ここではまず、 csv ファイルを pandas Dataframe として読み込み、そのDataframeを引数としてgraph.pyで定義した関数を呼び出しています。帰り値である plotly.graph_objects を dash_core_components.Graph でラップしてあげることでグラフを HTML Element として組み込むことができます。 visualizer.py import dash_core_components as dcc import dash_html_components as html import pandas as pd import graphs import base64 import datetime import io def parse_contents(contents, filename, date): content_type, content_string = contents.split(',') decoded = base64.b64decode(content_string) try: if 'csv' in filename: # Assume that the user uploaded a CSV file # Sometimes, LinkedIn dataset has "Notes" at the beginning # of the csv file. In this case, the "Notes" is removed. if "Notes:" == decoded.decode('utf-8')[0:6]: connections_df = pd.read_csv(io.StringIO(decoded.decode('utf-8').split('\n\n')[1])) else: connections_df = pd.read_csv(io.StringIO(decoded.decode('utf-8'))) else: return html.Div([ 'This file extension is not supported' ]) except Exception as e: print(e) return html.Div([ 'There was an error processing this file.' ]) return html.Div( children=[ html.Div( children=[ html.Div( children=dcc.Graph( figure=graphs.trend(connections_df) ), className="card", ), html.Div( children=dcc.Graph( figure=graphs.company_hist(connections_df) ), className="card", ), html.Div( children=dcc.Graph( figure=graphs.company_treemap(connections_df) ), className="card", ), html.Div( children=dcc.Graph( figure=graphs.position_treemap(connections_df) ), className="card", ), ], className="wrapper", ), ] ) 3.3 テスト 最後に、 python app.py と実行しローカルホストにもう一度アクセスしてみましょう。 すると、以下のようなページが見えるはずです。 ここに、サンプルデータを投げてみましょう。4つのグラフが表示されれば成功です。 うまくいかない場合や、私のコードに誤りがある場合はコメントいただけると幸いです。 4. まとめ 今回は、Dash と Plotly を用いて LinkedIn のデータを可視化するアプリを作ってみました。 他にも、 1. ユーザーがアップロードしたデータに応じて 2. plotly でグラフを書き 3. グラフをユーザーに返してあげる という流れで、 あらゆるデータセットから、あらゆる可視化をおこなうことができます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Matplotlibの日本語化

結論 $ pip install japanize-matplotlib import matplotlib.pyplot as plt import japanize-matplotlib japanize_matplotlib.japanize() 以上。 どうして...? Matplotlib 日本語化 でググって出てくる記事を上から3つくらい読んでもjapanize-matplotlibの話が出てきません。こんなに簡単なのにどうして…? pipでパッケージをインストールしなければならない点と、フォントを選べない点を欠点として挙げている記事もありました。見た目にこだわったサービスを組織で開発しているケースなら別ですが、個人でデータ分析していててっとり早く可視化したいだけの私にはjapanize-matplotlibで十分でした。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

matplotlibの日本語化

結論 %pip install japanize-matplotlib import matplotlib.pyplot as plt import japanize-matplotlib japanize_matplotlib.japanize() 以上。 どうして...? Matplotlib 日本語化 でググって出てくる記事を上から3つくらい読んでもjapanize-matplotlibの話が出てきません。こんなに簡単なのにどうして…? pipでパッケージをインストールしなければならない点と、フォントを選べない点を欠点として挙げている記事もありました。見た目にこだわったサービスを組織で開発しているケースなら別ですが、個人でデータ分析していててっとり早く可視化したいだけの私にはjapanize-matplotlibで十分でした。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

f文字列を扱えるようになろう (今日のPython Day4)

0. はじめに  ついに4日目になりました。これで3日坊主ではならなくなります。『やり抜く力 GRIT』という本にも書かれていたのですが継続することはとても大切です。一緒に頑張りましょう!  毎日1問、Pythonの問題を出題します。出題範囲は特に定めていませんがはじめの1ヶ月くらいは『入門Python3 第2版』の第1~11章までのことが分かれば解ける問題にしたいと思います。「こういう問題を作って欲しい」などのリクエストがございましたら初心者ながら頑張って作問します。また「別解を思いついた」、「間違えを見つけた」などがありましたら遠慮なくコメント欄にて教えて下さい。記事を執筆している当人もこの記事を読んでくださった方も新たなことを学ぶことができるので。 1. 問題 「私はダルエスサラーム出身です。」という文章を出力しましょう。ただし東京の部分は変数にしましょう。 2. 解答 p = "ダルエスサラーム" print(f"私は{p}出身です。") 3. 解説  今回はf文字列というものを用いました。python3.6以降で新しく導入された機能です。すごく便利なのでここで覚えてしまいましょう。書き方はまずダブルクオーテーション(シングルクオテーション)の前にfをつけます(大文字でも可)。そして表示させる変数は中括弧で囲います。f文字列が導入される前は次のような方法を用いていました。 別解1 p = "ダルエスサラーム" print("私は" + p + "出身です。") 別解2 p = "ダルエスサラーム" print("私は{}出身です。".format(p))  別解1は文章中の変数が1つだとまだしも変数が2つ、3つと増えると書くのが面倒くさくなります。別解2に関しては問題集でお目にかかったくらいで自分はほとんど使ってないです。 4. おまけトーク  ダルエスサラームはタンザニア最大の都市らしいです。「タンザニアってどこだよ」という方、タンザニアはアフリカの国です。本当におまけでしたね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

50歳からのプログラミング言語入門

転職(16) 65歳からのプログラミング入門 https://qiita.com/kaizen_nagoya/items/1561f910c275b22d7c9f 上記記事のうち、50歳からの話を、表を作ったことで切り離すことにした。 50歳から毎年1言語学習を目指してきた。 1言語習得とは言えない。勉強しても使えるようになるとは限らないから。 最低でも基本的な教科書の1冊は全部動かしてみる。 Uml./~python, Ruby, spin, C#, Coq, SML#, VDM, Event-B.uppaal, VHDL, ObjectiveC, R, System C, SMV, alloy。 Haskell, prolog, Z, verifarstは処理系を起動しただけで、ほぼ手が止まっている。 教師の欄は、直接教えてもらった人以外に、 いろいろやりとりのあった人、 本を参考にさせていただいた人などを含みます。 短縮名 内容 Go 打って動かした量 check 検査した量 edu 教育した量 get 習得度。10が先生、1が初心者 量の表示で、0.1は1の100分の1、10は1の100倍。 年齢 西暦 言語 教師 Go check edu. get 50 2004 Verilog HDL 末吉敏則 1 3 6 10 51 2005 UML 児玉公信 3 3 3 9 52 2006 SPIN 青木利晃 1 2 3 6 53 2007 VHDL 渡部謹二 0.5 2 2 5 54 2008 R 石井一夫 1 3 3 7 55 2009 Uppaal 掘武司 0.3 1 3 4 56 2010 Event-B 掘武司 0.5 1 1 3 57 2011 SMV 早水公二 0.4 0.5 1 2 58 2012 VDM 栗田太郎 0.1 0.2 0.4 0.7 59 2013 Ruby 田中和明 1 2 2 5 60 2014 alloy 斉藤直希 0.2 0.2 0.4 0.8 61 2015 Objective C 斉藤直希 0.5 1 1 3 62 2017 coq 今井宜洋 0.2 1 1 2 63 2018 python 東北大学 1 2 5 8 64 2019 SML# 齋藤啓太 0.1 0.4 0.4 0.9 65 2020 C# 尾崎秀典 1 1 2 4 66 2021 Kotlin Youtube 0.1 0.1 0.1 0.3 67 2022 Go これから 0 0 0 0 Errata of the Book "Modeling in Event-B" http://www.event-b.org/A_errata.pdf ちなみに、50歳までにお金になった仕事で取り組んだことがある言語は、 アセンブラ、C、C++, JAVA, Basic, Fortran, COBOL、LaTeX。10年に3つくらいの言語しか学習していない。20代に、アセンブラ、BASIC, COBOL, fortranをやっていて、30代にC++とJAVAとLaTex。40代は、、、。 LISPとSmallTalkは動かして見たけど実用的または研究的なプログラムは1行たりとも書いたことがなかった。 Squarkの子供向け教育は何度か行った。 Small Talkのデバッグは少しした。 電総研では、LISPが主言語の研究室に3ヶ月滞在したことがある。最初の1ヶ月でSmall C Compailerを入力し、次の1ヶ月でPascalで書かれたコンパイラをC言語に移植し、OBJという言語のシンタックスチェッカを作成して学会で発表した。 当時、パナソニック在籍の田中伸明さんも電総研にいたらしいことを後で知った。 仮説・検証(153)成功体験は語っても、成功体験に頼らないために。清水吉男・田中伸明・柏原一雄 https://qiita.com/kaizen_nagoya/items/d32adfaf7b2568bfd9d2 電総研当時に書いたまとめで、SEAで発表した際に、気が付いたことと同じ現象をEvent-Bでも経験した。 Errata of the Book "Modeling in Event-B" http://www.event-b.org/A_errata.pdf 50歳以降で新たに学習した言語で、役にたったのはSlideshareで人気記事のVerilog HDL、VHDL以外には、pythonとRかもしれない。C#, Rubyもなんとか役立てようとしている。 How to use STARC RTL Design Style Guide Verilog-HDL 2011 version https://www.slideshare.net/kaizenjapan/how-to-use-starc-rtl-design-style-guide-veriloghdl-2011-version JAVA, Python, JavaScript, C# あなたはXML処理ソフトをどの言語で書きますか? https://qiita.com/kaizen_nagoya/items/08cc37b64d0995774fb1 趣味で使うなら、機械学習できなきゃ。 組織の経営分析をするのにRかPythonがいいかも。 この記事は、当時64歳のプログラマが、同世代のプログラムを組んだことがない方に、相談に応じた記録でもあります。 機械語、アセンブラでも楽しむ方法はある。アセンブラ短歌とか。 趣味ですぐに役立つプログラミングならpythonかも。 2017 年から開催した「ゼロから始めるDeep Learning読書会」 https://qiita.com/kaizen_nagoya/items/537b1810265bbbc70e73 に65歳以上の方が数人参加されており、pythonの導入、習得にいろいろ苦労されている状態を手助けした記録も兼ねています。 機械学習はdocker利用をお勧めしています。 なぜdockerで機械学習するか 書籍・ソース一覧作成中 (目標100) https://qiita.com/kaizen_nagoya/items/ddd12477544bf5ba85e2 古いWindowsしかない方で、どうしてもWindowsでpythonをしたいという方のために作った資料はこちら。 Windows(M.S.)にPython3(Anaconda3)を導入する(7つの罠) https://qiita.com/kaizen_nagoya/items/7bfd7ecdc4e8edcbd679 自分のQiita記事で、一番viewsが多い。読んで、うまくanacondaが導入できたら「いいね」をお願い。 dockerもWindowsもと思う方に、お勧めしているのはRaspberry PI。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python3.10の新機能(2) - Pythonにmatch文がやってくる

はじめに 2021年10月にリリースが予定されているPython3.10で新たに加わる変更をPython3.10の新機能 (まとめ)という記事でまとめています。その中で比較的分量のある項目を別記事に切り出すことにしていますが、これはその第二弾で、PEP-634 で提案されている「構造的パターンマッチング」についてです。 なお、この機能については、既に@tk0miyaさんがPython3 に提案されたばかりのパターンマッチング構文を調べてみたという記事を書かれていてバッチリ網羅的に解説されているので、ここでは Python 3.10のWhat's Newに挙げられた例を使って、私が気になったポイントを書いてみたいと思います。 この変更で解決しようとしている問題 Pythonを使い始めた人が最初に疑問に思うことの一つに「なぜswitch文がないのだろうか?」があります。C言語などでもお馴染みの機能で、ある変数の値によって3つ以上に処理の流れが分かれる場合に便利な機能です。Pythonではこれまで頑なにswitch文の導入を回避してきていました。if ... elif ... else 文で書けるだろう、ということと、辞書型を使えば3つ以上のディスパッチも簡単にできる、というのが理由でした(後者に関しては後ほど例を示します)。まあでも、if文で書けるとは言え、elif ...elif ...elif と何度も場合分けを書くのはちょっと見通しが良くないですし、辞書型を使うのも読むのに少し慣れが必要になります。 それから、より構造的な特徴によって処理を振り分けたいという場合もあります。例えば、タプルが与えられて、その要素の数によって処理を分けたい場合や、オブジェクトの型(クラス)によって処理を分けたい場合など。このような場合には、これまで len()で要素数をまず取り出してそれによって if文で切り分けていくとか、isinstance()を使ってどのクラスなのかをif文の中でチェックしていくなどしなければなりませんでした。これは書くのも大変ですし、さらに読む方にとっても見通しが悪いという問題がありました。 このような問題に対して、RustやScalaのような言語ではパターンマッチングの記法を導入して解決しています。switch文と似たような記法ですが、単に値のマッチングだけではなく構造的なマッチングも行うことのできる記法で、これが 3.10でPythonに取り入れられることになります。 match文の利用例 パターンマッチングの機能はmatch文によって実現されますが、幾つか使い方があります。 リテラルマッチング これは switch文的な使い方ですね。 def http_error(status): match status: case 400: return "Bad request" case 404: return "Not found" case 418: return "I'm a teapot" case _: return "Something's wrong with the Internet" これはstatusの値を見てそれに対応するエラーメッセージを返すという例です。パッと見で何をしているかはすぐにわかるかと思います。最後の _は何にでもマッチするワイルドカードのようなもので、これでデフォルト動作を定義しています。 実は、これだけであれば、これまでも def http_error(status): error_string = { 400: "Bad request", 404: "Not found", 418: "I'm a teapot", } return error_string.get(status, "Something's wrong with the Internet") という形で書くことができました。辞書型でステータスコードとエラーメッセージの対応表を作っておいて、それをdict.get()で取り出す、値がない場合はデフォールト値を返す、というコードです。これが上記で述べた辞書型を使ったやり方ですが、行数は少ないものの、慣れないと何をやっているか直感的にはわかりにくいかなと思います。 なお、caseのマッチする値は複数指定できて、例えば case 401 | 403 | 404:というように| かorをつかって連結できます。 リテラルと変数の組み合わせパターンにマッチング もう少し複雑な例を考えてみます。点を(x,y)のタプルで表すとして、それによって今どこにいるのかを文字列で返す関数は以下のように書けます。 def where_am_i(point): match point: case (0, 0): return "Origin" case (0, y): return f"Y={y}" case (x, 0): return f"X={x}" case (x, y): return f"X={x}, Y={y}" case _: raise ValueError("Not a point") ここのパターンをみると、リテラル(0)と変数(x、y)が組み合わせられています。match文は上からチェックしていくので、この例だと、まずはじめに (0,0)であるかをチェックされ、マッチすれば "Origin"を返し、次にxの値が0のモノ、yが0のモノとチェックされ、case (x,y)に到達する時点ではxもyも0ではないものがマッチすることになります。 この例を今までのPythonで書くと例えばこのようになります。 def where_am_i(point): try: x,y = point except ValueError: raise ValueError("Not a point") if x == 0 and y == 0: return "Origin" elif x == 0: return f"Y={y}" elif y == 0: return f"X={x}" else: return f"X={x}, Y={y}" 行数的には同じくらいですが、わかりやすさと例外を出す場合も含めて統一的に書ける点でmatch文は良いですね。 クラスでのマッチング 前の例では点を表すのにタプルを使っていましたが、クラスを使うこともできます。 from dataclasses import dataclass @dataclass class Point: x: int y: int def where_am_i(point: Point): match point: case Point(x=0, y=0): return "Origin" case Point(x=0, y=yy): return f"Y={yy}" case Point(x=xx, y=0): return f"X={xx}" case Point(x=xx, y=yy): return f"X={xx}, Y={yy}" case _: raise ValueError("Not a point") ここでは点を表すのにPointをデータクラスとして定義していて、それでマッチングを行っています。クラスのコンストラクタに値を与えるような形で Point(x=0, y=0)と書くとxもyも0のPointクラスとマッチし、"Origin"という文字列を返しています。 面白いのは変数も指定できることで、ここでは混乱しないようにxxとyyとしていますが、例えば case Point(x=0, y=yy)だと、「xは0、yは何でも良いのでそれをyyとする」と解釈されます。そしてcase文の本体でその変数 yyを使えるということですね。ちょっと直感的にわかりにくいかも知れません。 クラスコンストラクタの引数の形で変数を与える代わりに、マッチしたオブジェクトそのものを使うやり方もあります。 def where_am_i(point: Point): match point: case Point(x=0, y=0): return "Origin" case Point(x=0) as p: return f"Y={p.y}" case Point(y=0) as p: return f"X={p.x}" case Point() as p: return f"X={p.x}, Y={p.y}" case _: raise ValueError("Not a point") asを使ってマッチしたオブジェクトを変数pに入れ、それをcase分本体で使っています。この例の場合は、変数pointを使っても同じことができますが、match文の対象が変数ではなく式だったりする場合にこのasを使ったやり方は便利かと思います。個人的にはこちらの方が記法としてはわかりやすいですね。 そして、だんだん難しくなってきますが、これも既存のPythonで書いてみたいと思います。 def where_am_i(point: Point): if not isinstance(point, Point): raise ValueError("Not a point") if point.x == 0 and point.y == 0: return "Origin" elif point.x == 0: return f"Y={point.y}" elif point.y == 0: return f"X={point.x}" else: return f"X={point.x}, Y={point.y}" こちらも例外ケースの処理を別にしなければならないのと、if ... elif ... else で値比較をしていかなければならないのでちょっと煩雑ですね。 複数クラスのマッチング 上記では一つのクラスだけの例を示しましたが、match文の中に複数のクラスのパターンが書かれていても問題なく動作します。例えばこんな例。 @dataclass class Point: x: int y: int @dataclass class Rectangle: width: float length: float @dataclass class Circle: radius: float def identify_shape(shape): match shape: case Point(): return f"This is a Point({shape.x}, {shape.y})" case Rectangle(): return f"This is a Rectangle({shape.width}, {shape.length})" case Circle(): return f"This is a Circle({shape.radius})" case _: return "Unknown shape" 与えられたshapeがどのクラスかによって返すメッセージが変わります。これまでのPythonでも例えば def identify_shape(shape): if isinstance(shape, Point): return f"This is a Point({shape.x}, {shape.y})" elif isinstance(shape, Rectangle): return f"This is a Rectangle({shape.width}, {shape.length})" elif isinstance(shape, Circle): return f"This is a Circle({shape.radius})" else: return "Unknown shape" とすれば同じことができますが、match文の方がスッキリ書けると思います。 まとめ Python 3.10で導入される構造的パターンマッチングの機能を、これまでの実装方法と比較しながら見てみました。これからどんどん使われる様になるのではないかと思います。 なお、Rustなどではマッチする値の完全制をコンパイラがチェックしてくれるので、パターンの書き忘れや、enumのバリエーションが増えた時の修正漏れなどがないのですが、Pythonのmatch文はそこまで親切(おせっかい)ではない点は注意しておいた方が良いかも知れません。 また、matchが文であって式じゃないので結果を変数で受けられないのがちょっと残念なところですが、Python的にはその方が自然ということですかね。いずれ、for文に対するリスト内包表現のように、matchの結果を返す式が書けるようになると良いなと期待しています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Django + Nginx + uwsgi + Mariadb環境構築

概要 Django + NGinx + uwsgi + mariadbで開発環境を作ったときのメモ 環境 GCP(無料枠) centos7 Python3.9 Nginx 最新 uwsgi 2.0.19.1 MariaDB 10 前提 root(su)で作業します。 ※ uwsgi周りがpermission error連発して苦労したので GCPはrootで入れなかったので、 sudo passwd root しました。 GCP(無料枠)は↓を参考にインスタンス作りました。 SELinuxをオフ $ vim /etc/selinux/config SELINUX=enforcing ↓ SELINUX=disabled $ reboot python3.9インストール # $ yum install gcc openssl-devel bzip2-devel libffi-devel zlib-devel wget make # $ wget https://www.python.org/ftp/python/3.9.2/Python-3.9.2.tgz # $ tar xzf Python-3.9.2.tgz # $ cd Python-3.9.2 # $ ./configure --enable-optimizations # $ make install $ pip3 install --upgrade pip $ pip3 install django==3.1.7 $ pip3 install uwsgi==2.0.19.1 $ pip3 install django-environ==0.4.5 【Python】参考にしたサイト MariaDB レポジトリの登録 $ vim /etc/yum.repo.d/MariaDB.repo ↓ # MariaDB 10.5 CentOS repository list - created 2020-07-18 18:32 UTC [mariadb] name = MariaDB baseurl = http://yum.mariadb.org/10.5/centos7-amd64 gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB gpgcheck=1 CentOS7にデフォルトでインストールされているMariaDB 5を削除 $ rpm -qa | grep -i "mariadb" mariadb-libs-5.5.44-1.el7_1.x86_64 // インストールされているかどうかの確認 $ yum remove mariadb-libs MariaDB 10をインストール $ yum install MariaDB-server MariaDB-client // バージョンを確認 $ mysql --version mysql Ver 15.1 Distrib 10.5.4-MariaDB, for Linux (x86_64) using readline 5.1 mysqlclientのインストール $ yum install MariaDB-shared python3-devel mysql-devel libmysqlclient-dev $ pip3 install mysqlclient==2.0.3 MariaDB初期設定 $ systemctl start mariadb $ systemctl enable mariadb $ mysql -u root -p // データベース新規作成 $ CREATE DATABASE データベース名; $ SHOW CREATE DATABASE データベース名; // データベースユーザ新規作成 $ CREATE USER test2@localhost IDENTIFIED BY 'test2'; // 権限付与 $ GRANT ALL PRIVILEGES ON データベース名.* to 'test2'@'localhost'; $ GRANT FILE ON *.* TO 'test2'@'localhost'; $ FLUSH PRIVILEGES; settings.pyに↑で作成したmariadbの設定をする。 任意で、一緒にpython manage.py collectstaticも。 【MariaDB】参考にしたサイト Nginx Nginxのインストール $ vim /etc/yum.repos.d/nginx.repo ↓ // 最新versionをインストールするように記載 [nginx] name=nginx repo baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/ gpgcheck=0 enabled=1 $ yum install -y nginx $ systemctl start nginx.service $ systemctl enable nginx.service // httpを追加(80) $ firewall-cmd --add-service=http --permanent // httpsを追加 $ firewall-cmd --add-port=443/tcp --permanent // 任意↓ 8000番を追加 $ firewall-cmd --add-port=8000/tcp --zone=public --permanent $ firewall-cmd --reload $ firewall-cmd --list-all Nginxの設定 $ vim /etc/nginx/nginx.conf ↓ user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { upstream config { server unix:///var/run/uwsgi/master.sock; } server { listen 80; server_name ◯.◯.◯.◯; root /usr/share/nginx/html/config; charset utf-8; include /etc/nginx/default.d/*.conf; client_max_body_size 100M; include /etc/nginx/mime.types; location /static { alias /static; } location / { uwsgi_pass config; include /etc/nginx/uwsgi_params; } } } include /etc/nginx/mime.types; ↑を忘れていて痛い目見ました。 uwsgi uwsg.iniの設定 $ vim uwsig.ini ↓ [uwsgi] uid = nginx gid = nginx chdir = /usr/share/nginx/html/ module = config.wsgi master = true processes = 2 threads = 1 socket = /var/run/uwsgi/master.sock pidfile = /var/run/uwsgi/master.pid chmod-socket = 666 vacuum = true thunder-lock = true max-requests = 6000 max-requests-delta = 300 # log logto = /var/log/uwsgi/uwsgi.log deamonize = /var/log/uwsgi/uwsgi-@(exec://date +%Y-%m-%d).log log-reopen = true uwsgi.serviceの設定 $ vim /etc/systemd/system/uwsgi.service ↓ [Unit] Description=uWSGI After=syslog.target [Service] // chown 任意のユーザー:nginx ExecStartPre=/bin/bash -c 'mkdir -p /var/run/uwsgi; chown root:nginx /var/run/uwsgi; chmod g+w /var/run/uwsgi;' ExecStart=/bin/bash -c 'uwsgi --ini /usr/share/nginx/html/uwsgi.ini;' #Restart=always Restart=on-failure KillSignal=SIGQUIT Type=notify StandardError=syslog NotifyAccess=all [Install] WantedBy=multi-user.target 必要フォルダの作成(uwsgiのpermission error多い) $ mkdir /var/log/nginx $ mkdir /var/log/uwsgi $ chown nginx:nginx uwsgi $ chmod 662 $ mkdir /var/run/uwsgi $ chown root:nginx uwsgi $ systemctl daemon-reload $ systemctl start uwsgi 【Nginx + uwsgi】参考にしたサイト 権限周りは↓が参考になりました
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

django復習(matplot)

とりあえずdjangoの復習用に適当にテーブルを作成。 投入データは下記から取得。 日本政府が出してるっぽいデータ from django.db import models from datetime import datetime # 人口テーブル class Population(models.Model): prefectures_code = models.CharField(max_length=10,verbose_name="都道府県コード", null=False) prefectures = models.CharField(max_length=10,verbose_name="都道府県", null=False) era = models.CharField(max_length=500, verbose_name="元号", null=False) jp_calendar = models.CharField(max_length=500, verbose_name="和暦", null=False) year = models.CharField(max_length=500, verbose_name="西暦", null=False) population = models.CharField(max_length=500, verbose_name="人口", null=False) man = models.CharField(max_length=500, verbose_name="男", null=False) woman = models.CharField(max_length=500, verbose_name="女", null=False) create_date = models.DateTimeField(default=datetime.now, null=True, verbose_name="登録日") def __str__(self): return self.prefectures 適当すぎて人口の数値部分も文字列で作成。 問題ないかと思いそのまま続行した結果、色々被害続出。 その辺の話 文字列の問題は置いといて、今回はmatplotで県ごとの人口をグラフにした時のメモ。 適当に作ったらY軸に1e6となってしまった。 分かりにくい。 調べてみるといい記事が見つかった。 MatplotlibのY軸の目盛りを指数表記(10のN乗表記)に変更する ex3)Y軸の目盛りを10のべき乗表記に変更するを真似するといい具合に動いた。 でもまだ10の6乗と言われてもピンとこないので万人単位で固定しようと下記を真似したが、動かない。 ex4)Y軸の目盛りを1×10^6から1×10^4に変更する ScalarFormatterの中身を見て確認すると自分の環境だと下記のオーバーライドしてるメソッドが違った。 (記事の)_set_orderOfMagnitude (自分の)_set_order_of_magnitude なので_set_orderOfMagnitudeの部分を_set_order_of_magnitudeに書き換えたらうまく動きました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

あのアルゴリズムはどこ? Pythonを使用してAtCoderの緑色や水色を目指す方に、30以上のアルゴリズムスニペットと100問以上の問題(ACコード付き)を紹介!

0.はじめに 2020年の5月よりAtcoderのコンテストに参加してから一年経った、現在水色コーダーとなりました、H20と申します。 AtCoderではPythonを使用して参加しており、水色になるまでに様々なアルゴリズムを使用しました。 アルゴリズムについてはほとんど自作せず、有識者の作成されたスニペットを調べては、ある程度理解しながら使用していました。 この記事では、Pythonにてあるアルゴリズムを使用する際にお勧めな書き方の説明をしているスニペットの記事に、それを利用してACしたコードを添えて紹介していきたいと思います。 (ただ、私のACコードは極力見ないで自力で解いてください。綺麗とは言い難いので…) 1.目次 ※各アルゴリズムで紹介している問題は、感覚的な難易度順に並べています。基本的に後半は解けたら凄い!くらいの想いで載せてます。  解き方は多種多様であり、特に難易度の低い問題では、必ずしもそのアルゴリズムを使わないといけないわけではありません。 ●除算の切り上げ、切り下げ ●約数列挙 ●素因数分解 ●エラトステネスの篩 ●BIT全探索 ●Union-Find ●クラスカル法(最小全域木) ●リスト(配列)の中身を連結・結合して文字列に ●多次元配列のソート ●defaultdict(辞書) ●カウンター ●ModInt ●逆元 ●階乗 ●コンビネーション ●ある値の累乗の何度も使用する場合 ●最大公約数 ●中国剰余定理 ●DFS ●二分探索(bisect) ●二分探索(その他) ●最長増加部分列(LIS) ●累積和(合わせて、いもす法) ●短めな順列の作成 ●二次元累積和 ●ダイクストラ法 ●ワーシャルフロイド法 ●セグメント木(セグ木) ●転倒数 ●桁DP ●ダブリング ●最長共通部分列 ●BitDP ●10進数を2進数、8進数、16進数に変換 ●10進数とn進数の変換 ●正規表現 ●キュー ●優先度付きキュー ●しゃくとり法 ●おすすめな情報 ●アルゴリズムを使用するにあたって ●おわりに ●よければのお話 2.除算の切り上げ、切り下げ リンク:割り算をするときの切り上げと切り捨て Pythonの切り捨てとして、処理が高速かつ短く書けるコードです。mathをimportする必要はありません。 Pythonでの切り捨て除算は除算値を超えない最大の整数となるため、値をマイナスにして、さらにマイナスを掛けることで、切り上げの値を取得できます。 慣れれば、切り上げもそらで書けるようになるはずです。 # 整数A,BについてA/Bの切り捨てを求める書き方 F = A // B # 整数A,BについてA/Bの切り上げを求める書き方 C = -(-A // B) 老婆心ながら、小数点を求めたい場合でない除算については/ではなく切り捨て除算の//演算子を使用しましょう。 詳細については以下の記事が参考になると思います。 切り捨てはmath.floor()より//演算子を使ったほうが良いかも pythonの除算結果が浮動小数点数になったので、必要な精度が失われた話 問題: ABC176 A Takoyaki - 【ACコード】 ABC195 B Many Oranges - 【ACコード】 ABC046 C AtCoDeerくんと選挙速報 - 【ACコード】 3.約数列挙 リンク:約数を高速で列挙するコード(Python) 問題によってはそのまま貼るだけだったことも。 計算量が $O(\sqrt{N})$ となるため、制約の$N$が$10^{12}$までなど大きな値をとる場合にはまず約数を疑ってかかるのも手です。 問題: ABC180 C Cream puff - 【ACコード】 MojaCoder Polygon of Polygons - 【ACコード】 ABC112 D Partition - 【ACコード】 ABC190 D Staircase Sequences - 【ACコード】 diverta 2019 D - DivRem Number - 【ACコード】 (expert!) ARC108 A Sum and Product - 【ACコード】 アルゴリズムを理解して、その処理を応用する解法の問題にも対応できるようになっておきましょう。 4.素因数分解 リンク:Pythonで素因数分解(試し割り法) note.nkmk.meさんのサイトより。皆さんご存じだとは思いますがこのサイトは、紹介しきれないくらいのいい記事がたくさんありますので、ググって見つかったらまず参考にしています。 他のアルゴリズムでもこのサイトを紹介しているものがあります。 問題: MojaCoder 楔数(くさびすう) - 【ACコード】 ABC169 D Div Game - 【ACコード】 ABC177 E Coprime - 【ACコード】 ABC152 F Flatten - 【ACコード】 若干難しくなりがちなので、素因数分解を使用すれば解けると気づけたときはレートアップのチャンスですね。 最初の楔数の問題は拙作です。ABCのCで出る灰色問題を想定しました。作問後、解いた方から別のアルゴリズムを使用して、制約が $1 \leq N \leq 10^8$ あたりでもTLEせずに、とても効率よく解く方法を教えてもらいました。ここで紹介しているアルゴリズムを複数使用します。解法は記載しませんが、皆さんは気づきますでしょか? この制約の場合水色以上の難易度だと思います。 5.エラトステネスの篩 リンク:Pythonで競技プログラミング 〜基本的なアルゴリズム 〜(エラトステネスの篩) $N$までの素数の一覧を作成するには $\sqrt{N}$ まで確認すればよいです。 引数$N$までについてis_primeではその値が素数かどうか、tableでは素数である値の一覧の二つの情報が返却されるところが好きです。 元のコードでのis_primeは整数1からNまでのテーブルとなるので、インデックスで混乱しやすいこともあり、is_primeを使用する場合は、先頭にFalse(0)を追加して返却するように書き換えて使用しています。 問題: 天下一プログラマーコンテスト2012 予選C A - 【ACコード】 ABC149 C Next Prime - 【ACコード】 (expert!) ABC170 D Not Divisible - 【ACコード】 天下一プログラマーコンテスト2012 予選Aの問題についてPypyで解くとMLE(メモリオーバー)するので、Pythonで提出してください。 古い問題のためメモリ制限が64MBで、Pypyで提出するとオーバーしてしまいます。 6.BIT全探索 リンク:Python de アルゴリズム(bit全探索) $2^N$のパターンを全て試す際に使います。制約の中に10~20前後(またはそれに落とし込める)の値があれば、BIT全探索を使用する問題の可能性が高いです。 問題探るとC問題に結構出やすいことに気付きました。頻出なので、これを簡単に使えるようになっていないと辛い時が来ると思います。 問題: ABC167 C Skill Up - 【ACコード】 ABC182 C To 3 - 【ACコード】 ABC190 C Bowls and Dishes - 【ACコード】 ARC114 A Not coprime - 【ACコード】 ABC197 C ORXOR - 【ACコード】 ABC128 C Switches - 【ACコード】 ABC147 C HonestOrUnkind2 - 【ACコード】 ABC104 C All Green - 【ACコード】 7.Union-Find リンク:PythonでのUnion-Find(素集合データ構造)の実装と使い方 それぞれ、素な集合を互いにくっつけていった後の状態を管理するのに使用します。 作り方によっては外すこともできるらしいですが、あまり詳しくないです。基本的にできるのは、くっつけるだけと思って構いません。 ARCの問題、または、友達関係を表す問題で出やすいです。 ACLに同機能のDSUがありますが、個人的には上記リンク先の内容の方に慣れてしまっているため、こちらの方が好きです。 少し古い話になりますが、上記リンク先はARC106の後の2020年10月25日にアップデートがありました。 all_group_members()の処理が最適化されています。 それ以前に入手された方は最新のものを使用しましょう。 問題: ABC177 D Friends - 【ACコード】 ACL Beginner Contest C - 【ACコード】 yukicoder No.1390 Get together - 【ACコード】 ARC106 B Values - 【ACコード】 MojaCoder Bonsai - 【ACコード】 ARC114 B Special Subsets - 【ACコード】 ABC157 D Friend Suggestions - 【ACコード】 ABC120 D Decayed Bridges - 【ACコード】 ARC111 B Reversible Cards - 【ACコード】 ARC183 F Confluence - 【ACコード】 Confluenceを解く場合は、dictの知識が必要です。defaultdictの章も参考になると思います。ちなみに、カウンターを使用するとTLEしました。 8.クラスカル法(最小全域木) リンク:Prim法とKruskal法をPython 3で実装してみた:無向グラフの最小全域木を求めるアルゴリズム 説明が分かりやすいリンクを載せましたが、↓のACコードはUnion-Findで紹介したスニペットを使用して書いてます。 最小全域木は、全域木を構成する辺のコストの総和が最小となるグラフのことです。それを求める有名なアルゴリズムの一つがクラスカル法です。 600点以上の難しい問題で解法のためにこの方法プラスαで使わないと解けない、という問題が出るらしいです。が、そういうのは解いたことなく… 恐らく簡単な問題でこのアルゴリズムを使う問題が出るとすると、言い換えると最小全域木となる問題だった、というのが出るのかなと。 未だAtCoderのコンテスト本番で出会った経験はないのですが...作問する側にとって作りにくい問題な気もがします。 最小全域木の問題を解くアルゴリズムはクラスカル法のほかにプリム法がありますが、どちらか片方だけ覚えればよいです。 Union-Findを使えるようになれば、クラスカル法も簡単に使えますので、プリム法は覚えなくてよいかなと思います。 Union-Findで挙げたある問題にについて、こちらに載せるとただのネタバレとなるため上記問題に入れました。その問題について、正しくは最小全域木の問題です。 問題: いろはちゃんコンテスト Day2 D - 【ACコード】 ABC065 D Built? - 【ACコード】 多次元配列のソートの章も参照ください。 9.リスト(配列)の中身を連結・結合して文字列に それといった参考元が見つからず、そのまま以下にスニペットを貼りました。 文字列などをリスト化して編集した後、それをまた文字列の形式に戻します。 文字列を文字列として扱うよりは、リスト化した方が値をいじりやすく、使う機会は多いと思われるスニペットです。 L = list(input()) #中略(要素に対して色々と書き換えを行う) print(''.join(map(str, L))) #空白区切りで出力する場合→ print(' '.join(map(str, L))) #カンマ区切りで出力する場合→ print(','.join(map(str, L))) 天下一プログラマーコンテスト2012 予選A B - 【ACコード】 ARC039 A A - B problem - 【ACコード】 ABC192 Kaprekar Number - 【ACコード】 ABC137 C Green Bin - 【ACコード】 ABC199 C IPFL - 【ACコード】 ABC137 Cについて、順番前後しますが、カウンターの章も参照のことお願いします。 10.多次元配列のソート リンク:【Python】2次元配列を二番目の要素に注目して降順にソートする いくつかのパターンを覚えるのではなく、配列の要素の二番目を降順でソートするスニペットを持っておけば、そのスニペットの応用で、たいていのソートを悩まず扱えるはずです。 L = [[1,2,3],[2,3,4],[3,4,5]] L = sorted(L, reverse=True, key=lambda x: x[1]) #[1]に注目して降順ソート print(*L) 複数キーのソート方法については↓です。 多重キーでのソート ただ私は、優先度の低いキー順にソートを複数回実行する方法でソートしています。その分処理に時間かかるのであんまりよくはないのですが… sort()は元のリストをソートし、sorted()はソートした新たなリストを生成します。 sort()の方が高速です。(参考) 昇順、降順がどちらの順に並ぶか混乱するときは、階段を昇っていく、降りていくをイメージすると迷わなくなります。 階段は1段目→2段目→3段目...と昇り、昇順は1→2→3と並べる、とイメージすると覚えやすいです。 補足として、二次元配列を使う場合の宣言(初期化)の書き方もおいておきます。(参考) L = [[0] * 4 for i in range(3)] # [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] 問題: ABC128 D Guidebook - 【ACコード】 キーエンス プログラミング コンテスト 2020 B Robot Arms - 【ACコード】 ABC113 C ID - 【ACコード】 11.defaultdict(辞書) リンク:Python defaultdict の使い方 辞書型です。dict を使用した場合、存在しないキーに代入しようとするとエラーとなるため、その分岐処理の煩わしさを解消すべく、defaultdictを使います。 ただリストを用意すれば解ける問題に、defaultdictを使ったとしても、それが原因でTLEに繋がることはまずないため、バンバン使ってもいいと思います。(keyにタプルを使用し、そのキーの数が相当数になる場合は別…) また、これがあるおかげで、通常のdictはあまり使用していないです。周りの人がどうかはちょっと詳しくないですが。 累積和の章にもdefaultdictを使用する問題を記載してますので、それも解いてみてください。 問題: yukicoder No.1338 Giant Class - 【ACコード】 ABC127 D Integer Cards - 【ACコード】 ABC188 F +1-1x2 - 【ACコード】 順番前後しますが、ABC188 Fはメモ化再帰を使用します。後述のDFSの章を理解した上で解いてください。 12.カウンター リンク:PythonのCounterでリストの各要素の出現個数をカウント collections.Counterでリストの出現回数が調べられます。 使う場面はとても多いです。 難しい問題になると、そのアルゴリズム+カウンターの兼ね合わせで答える問題が多いと、この記事を作る際に感じました。 collections.Counterは多機能なため、使いこなせるようになるとACコードを書くまでの時間を短縮できるはずです。 問題: yukicoder No.1468 Colourful Pastel - 【ACコード】 ABC118 B Foods Loved by Everyone - 【ACコード】 ABC082 C Good Sequence - 【ACコード】 ABC163 C management - 【ACコード】 ABC171 D Replacing - 【ACコード】 AGC031 A Colorful Subsequence - 【ACコード】 ABC181 D Hachi - 【解説】(解説にそのままコードが記載されているため…) ABC111 C /\/\/\/ - 【ACコード】 ABC052 C Factors of Factorial - 【ACコード】 ABC052 Cについては、前述の素因数分解も参照のこと挑んでください。 13.ModInt リンク:Pythonでmodintを実装してみた modをとる問題で使います。大きな値になると、C++などではオーバーフローしてしまうため、modをとった値で答えを出力することが多いです。 Pythonでは大きな値も扱えるには扱えますが、そのままでは処理速度はとても遅くなるため、modを取りながら計算する必要がある問題もよく出ます。 この際に、ModIntを使用すると計算が楽に行えます。 ModIntで四則演算が行えば、勝手に$10^9+7$など、定めた値で割った余りの値になってくれます。 習うより慣れろで試してみることをお勧めします。 ここでは問題を紹介しません。計算中にMOD取るのが煩わしい場合に使用するものであり、絶対使わないといけないというものではないため、問題紹介が難しく… 今回紹介している問題で私が使用したのは素因数分解で紹介したFlattenのみです。 14.逆元 MODの世界で割り算が必要な時があります。 ModIntを使ってもよいのですが、わざわざ割り算のためだけに使うのもなって時、割り算を行いたいときは逆元を掛ける、ということを行えばよいです。(参考) ModInt使うなら、そこまで使う必要もないのですが、記憶の片隅に留めておいて困ることはないと思います。 バージョン差で、Pythonで提出する場合には使用でき、Pypyでは使用できない方法があります。 #Pypy(7.3.0)、Python(3.8.2)どちらでも提出可能 #ただし、modは素数、aとmodは素である必要あり(AtCoderで提出する場合は、そこまで気にする必要はなさそうです) a = 2 mod = 10**9+7 div = pow(a, mod - 2, mod) #Python(3.8.2)で提出可能、Pypy(7.3.0)で提出するとエラー #ただし、aとmodは素である必要あり(AtCoderで提出する場合は、そこまで気にする必要はなさそうです) a = 2 mod = 10**9+7 div = pow(a, -1, mod) 問題: リンク:ABC177 C Sum of product of pairs - 【ACコード】 紹介した問題は、別に逆元とる必要なかった問題でしたが(使用しないACコード)、一応記載します。 パッといい問題は見つからず… 15.階乗 (参考程度に読んでください) $N!$を求めます。AtCoderでは組み合わせを使用する問題は巨大な値となることが多く、$10^9+7$などでModを取った値を答える必要のある問題が多いです。 仮にModをとり、何度も使用することがある場合は、以下のような下準備をしてあると便利です。 MOD = 10**9+7 fact = [1] N = 10000 for n in range(1,N+1): fact.append(fact[-1]*n%MOD) math.factorial()という階乗を求める関数がmathモジュールに用意されていますが、呼び出す度に指定した値の階乗を求める計算が行われます。AtCoderで使用する場合は最悪TLEする危険があるため、注意が必要です。 何度も繰り返し階乗の計算する問題では気を付けましょう。 #仮に、1~10000までの階乗を全て求める場合 #MODなしfactorial、実行時間PyPyにて4000ms以上 import math fact = [1] for n in range(1,10001): fact.append(math.factorial(n)) # Modなし 150ms程度 fact = [1] for n in range(1,10001): fact.append(fact[-1]*n) #MODありfactorial、実行時間PyPyにて4000ms以上 MOD = 10**9+7 fact = [1] for n in range(1,10001): fact.append(math.factorial(n)%MOD) #MODあり 100msを切る MOD = 10**9+7 fact = [1] for n in range(1,10001): fact.append(fact[-1]*n%MOD) と、ここまで書いて挙げたAtCoderの階乗の問題は、math.factorial()を使用して解けちゃう問題ですが多いです。 複雑な処理が必要な問題は、コンビネーションの問題になってくるので、コンビネーションの知識を使用せずに、上の知識のみが必要になってくる問題は見つからず… 問題: ABC 055 B Training Camp - 【ACコード】 ABC 185 C Duodecim Ferra - 【ACコード】 16.コンビネーション リンク:Python で二項係数 nCr を高速に計算したい 階乗の続きとなり、コンビネーションも下準備をしておくと、その結果を使用して高速に求められます。 内部で逆元の計算もしているのでさらに高速です。使う側は逆元について意識する必要はありません。 pは問題のmodの値に合わせて変更してください。 コンビネーションで計算した結果に、ModIntを使用してさらに計算する、といった解き方で解く問題が多いと思われます。 (とは思いつつもその難易度の問題を解いたことがないです…) 問題: ABC034 C 経路 - 【ACコード】 ABC145 D Knight - 【ACコード】 ABC132 D Blue and Red Balls - 【ACコード】 ABC167 E Colorful Blocks - 【ACコード】 $998244353$で割った余りの問題もありますので、気を付けてください。 ちなみに、$998244353$が使われる理由は、ACL-for-pythonのconvolutionのwikiに書かれていました。 (フーリエ全く分かってない…) 17.ある値の累乗の何度も使用する場合 何度も累乗の計算をしていると、TLEする恐れがあるため、階乗と同じく下準備しておく方が無難です。 MOD = 10**9+7 N=1000000 p = [1] for n in range(N): p.append(p[-1]*2%MOD) Pythonのpowやべき乗は繰り返し二乗法により高速に計算するのですが、使用する指数がかなり大きくなれば処理は遅くなってしまいます。 以下、参考までに簡単に調べた処理速度です。 #仮に、2^1から2^Nまでの乗数を全て求める場合(他のパターンはTLEしたので除外) #MODあり 300ms前後 MOD = 10**9+7 p = [1] for n in range(1,5000000): p.append(p[-1]*2%MOD) #MODありpow、実行時間PyPyにて2000ms前後 MOD = 10**9+7 p = [1] for n in range(1,5000000): p.append(pow(2,n,MOD)) 問題: HHKB プログラミングコンテスト 2020 E Lamps - 【ACコード】 Lampsを解くためには、ABC129 D Lamp - 【ACコード】が解けている必要があります。挑戦する前にこの問題を解いてください。 18.最大公約数 リンク:Pythonで最大公約数と最小公倍数を算出・取得 バージョンの差異に気を付けてください。2021年4月現在のAtCoderで使用できるPythonのバージョンは3.8.2なので最大公約数は以下の方法取得できます。古い書き方であるfractions.gcdも3.8.2では使用できません。 3つ(以上)の要素について最大公約数を調べたい場合は、2つの最大公約数を調べた結果と3つ目の要素の最大公約数をとるように使用すればよいです。最小公倍数も同様です。 import math def my_lcm(x, y): return (x * y) // math.gcd(x, y) print(my_lcm(6, 4)) 最大公約数や3つ以上の引数をサポートする3.9以降が使用できる日が待ち遠しいですね。AtCoderの言語アップデートはそろそろ行われるはずです。 ちなみに、Python 3.9の次バージョンはPython 3.10らしいです。わかりにくい… 問題が少ないため、最大公約数のほか、最小公倍数を使用した問題も並べます。どちらを使用する問題か、検討して使用してみてください。 問題: ABC102 A Multiple of 2 and N - 【ACコード】 ARC105 B MAX-=min - 【ACコード】 ABC131 C Anti-Division - 【ACコード】 yukicoder No.1464 Number Conversion - 【ACコード】 ARC110 A Redundant Redundancy - 【ACコード】 19.中国剰余定理 リンク:ACL-for-python/math.py     Wiki(使用例) 以下のような問題を解くのに使用します。 3で割ると2余り、5で割ると3余り、7で割ると2余る。この条件を満たす(最小の)正の整数を求めよ。 アルゴリズムを理解するのは難しいですが、使うだけなら非常に楽です。その上、解けば水色や青色のパフォを出すことも夢ではありません。 次に中国剰余定理の知識が必要な出た場合は、みんな勉強してきてると思われるのでdifficultyの数値は下がりそうですが… 中国剰余定理はACLに含まれているので、そのPython移植版を使用します。 #ACL部分は省略 #3で割ると2余り、5で割ると3余り、7で割ると2余る C = [3,5,7]#これで割ったら R = [2,3,2]#この余りになる対のリスト r,m = crt(R,C) print(r)#23 矛盾(例として4で割って1余り、2で割って0余る。などという存在しえない条件の場合)のある場合は返却値の2つ目の要素が0であるかで判断できます。 ちなみに、2つ目の要素は値が一巡する法の値となります。 内部処理をPythonに置き換えた人が処理を細かく説明している記事もありますので、そちらも確認してみてください。(参考) 問題: ABC186 E Throne - 【ACコード】 ABC193 E Oversleeping - 【ACコード】 20.DFS リンク:よくやる再帰関数の書き方 〜 n 重 for 文を機械的に 〜 問題解決力を鍛える!アルゴリズムとデータ構造の著者で有名なけんちょんさんの記事です。 いつもはC++のコードですが、DFSの記事については、Pythonのコードも載っています。 popの書き方は毎回そのような書き方をする必要があるわけではないです。 上記サイトの『細かい注意点』に記載があるよう、以下の書き方は毎回リストを作り直すような挙動になるため、注意が必要とあります。 そこまで長くならないと制約から読み取れるDFSの処理では以下の書き方でよいのでは、と思っています。 制約から深くなりそうと思えば、popやリストを外だしで管理して使用する書き方にするのがいいと思います。 比較的簡単な問題ではlistを引数にするのではなく、値を引数にすることが多いかと思います。 import sys sys.setrecursionlimit(10 ** 9) #再帰回数の限界を変更 def dfs(A): # 数列の長さが N に達したら打ち切り if len(A) == N: # 処理 return for v in range(M): dfs(A+[v]) dfs([]) 元のコードよりもMLEやTLEが心配ですが、そこまで大きな値にならないと分かれば上記の書き方の方が分かりやすいかなと。 Python版のACコードがなかったり、ちょっとだけ変えた書き方をしましたので、上記記事で紹介されている問題も↓に並べます。 問題: ABC114 C 755 - 【ACコード】 ABC161 D Lunlun Number - 【ACコード】 ABC165 C Many Requirements - 【ACコード】 パナソニックプログラミングコンテスト D String Equivalence - 【ACコード】 ABC119 C Synthetic Kadomatsu - 【ACコード】 ABC198 E Unique Color - 【ACコード】 ABC196 D Hanjo - 【ACコード】 21.二分探索(bisect) リンク:Python標準ライブラリ:順序維持のbisect 昇順ソートされたリストに対してソート順序を保ったまま値を挿入したい(よくある問題としては挿入される場所を知りたい)場合はbisectを使用します。 入力された値がばらばらなリストの内容を昇順リストに変換してから二分探索を行うといった問題が出やすいです。 left、rightの違い、また0から開始する(正しい言い回しとしては、zero-basedとか0オリジンとか)ことに気を付けて使いましょう。 問題: ABC143 D Triangles - 【ACコード】 ABC077 C Snuke Festival - 【ACコード】 22.二分探索(その他) リンク:めぐる式二分探索 コピペで使えるPython実装 上記bisectによる二分探索は、昇順リストの中身を二分探索して調べるものです。 昇順リストではない、ある閾値を調べるための二分探索する場合のアルゴリズムとして有名なものが【めぐる式二分探索】です。 自作するとどうしてもバグが起きやすいとされる二分探索のバグを極端に減らしてくれる優れものです。 あるキャラのなりきりアカウントから有名になった手法のため、こんな名前がつきました。 色々あって、公には使いにくい名称となっているよう。きっとこのなりきりをしていたお茶目な方は、今も元気に仕事とTwitterをやっていそうですね。 問題: yukicoder No.1101 鼻水 - 【ACコード】 ARC109 B log - 【ACコード】 ABC174 E logs - 【ACコード】 ARC050 B 花束 - 【ACコード】 23.最長増加部分列(LIS) リンク:最長増加部分列 処理や機能の説明は以下のサイトが分かりやすかったです。 最長増加部分列(LIS)の長さを求める 同じ値も増加列とみなす場合は広義最長増加列と言います。 広義最長増加列を取得したい場合紹介したアルゴリズムのこの部分だけを直せば問題ないです。 変更前 idx = bisect(dp, a-1)#最長増加部分列(original) 変更後 idx = bisect(dp, a)#広義最長増加部分列 逆に最長減少部分列の長さを確認したい場合は、リストを逆順にして、最長増加部分列のアルゴリズムを行えば取得できます。 LISのアルゴリズムの紹介先のサイトでは、他にも様々なアルゴリズムなどがありますので一通り眺めてみることをお勧めします。文字列系のアルゴリズムが他にも記載されています。(GitHubはこちらから) 後半で説明する転倒数、最長共通部分列もこちらのサイトから紹介しています。 問題: ABC006 D トランプ挿入ソート - 【ACコード】 ABC134 E Sequence Decomposing - 【ACコード】 (expert!) AGC024 B Backfront - 【ACコード】 24.累積和(合わせて、いもす法) リンク:すごいぞitertoolsくん(順列・組み合わせ) itertools.accumulateで累積和を求めることができます。累積和をたったワンライナーで求めることができます。 累積和を前準備することで範囲を求める処理が $O(1)$ で済みます。 累積和を求めるメリットの詳細はけんちょんさんの記事がよくわかると思います。 いもす法についてもけんちょんさんの記事を読んでください。(何か書こうにも丸パクリの上に劣化になっちゃうので…) 累積和にてある範囲を取る場合、範囲の指定はこのようになります。 import itertools L = list(range(1,7)) #[1,2,3,4,5,6] AC = list(itertools.accumulate(L)) #[1,3,6,10,15,21] #要素の3つ目から5つ目の合計が知りたい場合の書き方(3+4+5=12) l,r=2,4#0から開始なので1個ずれちゃいます(正しい言い回しとしては、zero-basedとか0オリジンとか) print(AC[r]-AC[l-1])# 12 AC[r]からAC[l-1]を引くと範囲となる この書き方をすることで問題ないように思えますがlが1つ目の要素だった場合、l-1は、マイナスの値になってしまいます。 ここで、Pythonはリストの-1を指定するとリストの末尾を参照してくれる優れた機能があるため、累積和の末に0を付け加えると、lが0でも気にならなくなるテクニックがあります。 ぜひ覚えておいてください。 import itertools L = list(range(1,7)) #[1,2,3,4,5,6] AC = list(itertools.accumulate(L))+[0] #[1,3,6,10,15,21,0] #要素の1つ目から5つ目の合計が知りたい場合の書き方(1+2+3+4+5=15) l,r=0,4 print(AC[r]-AC[l-1])# 15 (AC[4]-AC[-1]→15-0→15) また、いもす法を実現する場合にもr+1まで値を更新することになるため、元のリストの長さに要素を一つ追加した長さのリストを用意しておくと便利です。 ちなみに、負の値のないリストの累積和を取る場合、昇順ソートされた状態になるので二分探索(bisect)とも相性が良いです。 問題: AGC023 A Zero-Sum Ranges - 【ACコード】 ABC014 C AtColor - 【ACコード】 ABC183 D Water Heater - 【ACコード】 ABC035 D オセロ - 【ACコード】 ABC188 D Snuke Prime - 【ACコード】 東京海上日動 プログラミングコンテスト2020 C Lamps - 【ACコード】 ABC105 D Candy Distribution - 【ACコード】 ARC100 D Equal Cut - 【ACコード】 25.短めな順列の作成 リンク:すごいぞitertoolsくん(順列・組み合わせ) 全探索するための順列をワンライナーで作成できます。 itertools.productを使用して、BIT全探索をことも可能なようです。 ここでは2問しか紹介しませんでしたが、この章以外の問題でも使っています。 問題: ABC028 C 数を3つ選ぶマン - 【ACコード】 ABC183 C Travel - 【ACコード】 26.二次元累積和 リンク:蟻本 Python 二次元累積和 競技プログラミング Atcoder 二次元累積和です。 累積和の方では、範囲を求めるためにリストの末尾に[0]を付けることをお勧めしましたが、今回紹介した内容は、始点の計算についてモジュール内で正しく分岐されるようになっているため不要です。(一次元の時と同じく、いもす法を実現するのであればリストの末尾に[0]を付けていた方が処理を考えるのに楽です) 二次元累積和を求める計算が短く、なんでこれだけの要素だけで求められるのだろうと気になって調べたら、こういう理屈だったと知って思わず感嘆しました。 数学弱者にはこんなの思いつけない… 累積和でも紹介しましたが、二次元でのいもす法の値の設定方法もいもす法のサイトに記載されているので参照ください。 問題: MojaCoder ASCII Squares - 【ACコード】 ARC025 B チョコレート - 【ACコード】 27.ダイクストラ法 リンク:競技プログラミングで使う有名グラフアルゴリズムまとめ ダイクストラ法(defaultdictで実装) 経路復元も リンク先のダイクストラ法は、頂点をdefaultdictで管理するため、数値以外の頂点も使用できます。 (キーにタプルなどを使用すると少々処理が遅くなるため、頂点の数の注意が必要です) また経路復元を行った結果も返却されます。 ダイクストラを使用する問題では、その処理の中身を変更しないといけない問題が多いので、カスタマイズできるよう、コードはしっかり理解しましょう。 問題: ARC109 A Hands - 【ACコード】 ABC160 D Line++ - 【ACコード】 ABC191 E Come Back Quickly - 【ACコード】 (expert!) MojaCoder As Soon As Possible - 【ACコード】 (expert!) ABC192 E Train - 【ACコード】 (expert!※) yukicoder No.807 umg tours - 【ACコード】 (expert!※)ZONeエナジー プログラミングコンテスト E 潜入 - 【ACコード経路復元あり】【ACコード経路復元なし】 expert!について、中のアルゴリズムを書き換える必要があったり、中の処理が分かればすぐ答えられる問題となっています。 ※について、解けはしましたが制限時間ギリギリで、頂点を1次元で管理(特殊な頂点はマイナス扱い)、経路復元処理なしなど処理を変更することで安定した回答となりました。頂点や辺の数が多い場合は、処理時間の削減できる場所を見つけて処理時間を短縮する必要あります。 経路復元ありを説明に使いましたが、別に経路復元必要な問題解いてないですね… 28.ワーシャルフロイド法 リンク:競技プログラミングで使う有名グラフアルゴリズムまとめ ワーシャルフロイド法 重み付き有向グラフの全ペアの最短経路を取得できます。紹介したリンク先は、ダイクストラ法と同じ記事です。 処理や機能の説明は以下のサイトが分かりやすかったです。 素人によるワーシャルフロイド法 制約から予測するのが危ない場合もありますが、コストを考える必要のあるグラフについて、頂点の数が $1 \leq N \leq 300$ 程度の制約であるとワーシャルフロイドで解く問題なのかと想像します。オーダーが $O(N^3)$ のため。 頂点が増えるとTLEするため、頂点の数が多い場合は使用しないです。 参考のものは負経路を検出できます。使用しないことが多いとは思いますが、あって困らないかなと。戻り値は複数なため、探索結果を受け取る時は↓のようにして受け取りましょう。 hasNegativeCycle, d = graph.WarshallFloyd_search() #dに本来の結果が入る 問題: ARC079 D Wall - 【ACコード】 ARC073 D joisino's travel - 【ACコード】 (expert!) yukicoder No.1344 Typical Shortest Path Sum - 【ACコード】 (expert!) ABC074 D Restoring Road Network - 【ACコード】 29.セグメント木(セグ木) リンク:ACL-for-python/segtree.py     Wiki(使用例) 任意の区間に対する操作(一要素の更新・区間に対するクエリ)を高速に行えます。 中国剰余定理と同様、セグ木もACLに含まれているので、そのPython移植版を使用します。 基本的に使用する操作やそれに必要な要素についてもWikiに載ってますので参照のこと。 相当高度なアルゴリズムなのですが、ただ使うだけの典型問題なら緑Diffになると判明し、話題になりました。 使用する際の個人的な注意点としては、G.prod(l,r)について、範囲は$[l,r)$であり、rが含まれていない点です。 これに気付いていれば解けてた問題をずっと悩んで答えられなかった過去があります… セグ木は私自身そこまで理解できておらず、基本的な方法で解ける問題のみ紹介します。 問題: ABC185 F Range Xor Query - 【ACコード】 ABC123 C GCD on Blackboard - 【ACコード】 yukicoder No.875 Range Mindex Query - 【ACコード】 ACL Beginner Contest D Flat Subsequence - 【ACコード】 30.転倒数 リンク:反転数 転倒数とは、バブルソートをした際の交換する回数を高速に求めるアルゴリズムです。 リンク先の名前は反転数となっていますが、転倒数と同じ意味です。 実装については、ある程度条件がありますので、元のリストが記載された条件に沿わない形であれば沿うような形に直してから行ってください。 ちなみに、転倒数はセグ木でも求められます。セグ木で実装するのは機能過多にあたるそうです。気になった方は調べてみてください。 問題: yukicoder No.742 にゃんにゃんにゃん 猫の挨拶 - 【ACコード】 yukicoder No.1115 二つの数列 / Two Sequences - 【ACコード】 ABC190 F Shift and Inversions - 【ACコード】 31.桁DP リンク:桁DPに入門してみた $1$以上$N$以下の整数のうち○○である個数を求めよ。となっており、$N$の制約が$ 1 \le N \le 10^{10000}$だったりする場合は桁DPの出番です。 紹介したリンクは、普通のforの書き方よりもスマートに書けて、コードの内容も混乱しにくく出来ています。 ただし、defaultdictでの書き方であると、問題によってはTLEするため、リストで管理する書き方(↓)に置き換えて使用しています。 dp=[[[[[0] * 8 for _ in range(3)] for _ in range(2)] for _ in range(2)] for _ in range(n+1)] dp[0][0][0][0][0] = 1 A以下B以上の非負整数のうち、「3が付くまたは3の倍数」かつ「8の倍数でない」数の総数を求める(折り畳みコード) from itertools import product a = int(input()) b = int(input()) def count(x): a = str(x) n = len(a) #配列は末から dp=[[[[[0] * 8 for _ in range(3)] for _ in range(2)] for _ in range(2)] for _ in range(n+1)] dp[0][0][0][0][0] = 1 #条件に合わせてDP for i, less, has3, mod3, mod8 in product(range(n), (0,1), (0,1), range(3), range(8)): max_d = 9 if less else int(a[i]) for d in range(max_d+1): less_ = less or d < max_d has3_ = has3 or d == 3 mod3_ = (mod3 + d) % 3 mod8_ = (mod8*10 + d) % 8 dp[i + 1][less_][has3_][mod3_][mod8_] += dp[i][less][has3][mod3][mod8] #合致するものを合算 ret = 0 for less, mod8 in product((0,1), range(1,8)): ret += dp[n][less][1][0][mod8] ret += dp[n][less][1][1][mod8] ret += dp[n][less][1][2][mod8] ret += dp[n][less][0][0][mod8] return ret print(count(a) - count(b-1)) 他の人の書き方に比べ処置時間は掛かりますが、この書き方のせいでTLEすることはまずないかなと思います。F問題になるとギリギリアウトな問題が出てくるかもしれませんが... 紹介したのは$1$以上$N$以下の整数のうち、といったパターンですが、ビットで行う桁DPの問題などもあるので、気になった場合は調べてみてください。 問題: ABC154 E Almost Everywhere Zero - 【ACコード】 ABC135 D Digits Parade - 【ACコード】 ABC029 D 1 - 【ACコード】 yukicoder189 SUPER HAPPY DAY - 【ACコード】 yukicoder1417 100の倍数かつ正整数(2) - 【ACコード】 100の倍数かつ正整数(2)は拙作です。ちょっと特別なことに気づけないと解けない問題ですが、ぜひ挑戦してくれたら嬉しいです! 解き方が分からない場合は問題の解説を読んでください。 32.ダブリング リンク:[競プロ用]ダブリングまとめ あるリストに対して、毎回同じ変化があり、N回数後の状態を求める問題で、そのNの最大が$10^9$以上など非常に大きな値であればダブリングを使う場面かと思います。詳細はリンクを確認してください。 一回使い方を覚えるとすんなりと使えるようになるはずです。ダブリングでないと解けない問題はそこまで多くはないのですが、覚えておいて損はないかなと。 問題: ABC179 E Sequence Sum - 【ACコード】 ABC013 D 阿弥陀 - 【ACコード】 33.最長共通部分列 リンク:最長共通部分列 LCS (Longest Common Subsequence)とも呼びます。二つの文字列から一部分取り除いて、同じ文字列を作る時の最長となる部分文字列を求めます。 問題: CODE FESTIVAL 2015 あさぷろ Middle B ヘイホー君と削除 - 【ACコード】 34.BitDP リンク:BitDPについて 愚直に解こうとすると$N!$になる数え上げについて、$2^N$まで処理を高速化できます。 巡回セールスマン問題を解く場合にも、このアルゴリズムを使用します。 現在のABCで出てくるとしたらE問題以降だと思います。典型でも水色Diffなので、解けたら大分レートアップするはず。 問題: ABC180 E Traveling Salesman among Aerial Cities - 【ACコード】 ABC142 E Get Everything - 【ACコード】 ABC199 E Permutation - 【ACコード】 ABC180 E がほぼ典型らしいのですが、その典型の情報を知らないで解くと難しいほうの部類に入る気がします。 ABC180 E で理解できなかった場合は、そのまま(参考先の問題含め)別の問題で理解を深めることをお勧めします。 35.10進数を2進数、8進数、16進数に変換 リンク:Pythonで2進数、8進数、16進数の数値・文字列を相互に変換 コンテスト中に調べる時間がもったいないので、このような情報をもって、すぐに使えるようにしておきましょう。 i=255 print(format(i, 'b')) print(format(i, 'o')) print(format(i, 'x')) # 11111111 # 377 # ff # 戻り値は文字列 補足として、popcount(整数値の1ビットの数)を数えるならこんな書き方です。 popcountについての記事を見るとそこまで処理は遅くはないようです。 i=200 print(format(i, 'b').count('1'))#iのpopcountを表示(この場合3) 問題: ABC186 C Unlucky 7 - 【ACコード】 36.10進数とn進数の変換 リンク:Python で10進数とn進数の変換 2進数、8進数、16進数以外に変換したい場合もあります。逆に10進数へ変換した場合もあると思います。上記のリンクのモジュールを用意して変換しましょう。 Base_10_to_n()を使用するときは、切り捨て除算//に置き換えて使用した方がよいかなとは思います。処理ももう少し最適化できますが、AtCoderで出る問題は、C++でも整数型として扱える範囲でしか出ないと思われますので、気にしなくてもよいかなと。 10進数をn進数に変換する他の方法として、標準ライブラリのintを使用する方法があります。 Python 標準ライブラリ(int) int('100', 16)のような書き方で、第二引数の基数に変換できますが、基数として指定できるのは0と2~36までのため、使用する場合は、注意して使用しましょう。 問題: ABC156 B Digits - 【ACコード】 ABC192 D Base n - 【ACコード】 37.正規表現 リンク:Pythonの正規表現モジュールreの使い方(match、search、subなど) 覚えていると非常に簡単。 使いやすいように、以下のような状態ですぐ使えるようにしています。 import re s = input() ans = re.match('^AAA.*$', s) if ans: print('Yes') else: print('No') 問題: Tenka1 Programmer Beginner Contest 2019 B - 【ACコード】 ABC017 B choku語 - 【ACコード】 ABC049 C 白昼夢 - 【ACコード】 38.キュー リンク:Pythonのdequeでキュー、スタック、デック(両端キュー)を扱う Pythonではキューとしてcollections.dequeとqueue.Queueがあります。(listもありますが遅いです。) AtCoderでは、collections.dequeを使用しましょう。queue.Queueはcollections.dequeに比べ機能が少なく、またスレッドセーフとなるようにしているため、処理が遅くTLEしてしまいます。一応、スレッドセーフは本来ありがたい機能ではあるのですが…(参考1)(参考2) 問題: ABC066 C pushpush - 【ACコード】 ARC108 B Abbreviate Fox - 【ACコード】 ZONeエナジー プログラミングコンテスト D 宇宙人からのメッセージ - 【解説】(解説にそのままコードが記載されているため…) AGC033 A Darker and Darker - 【ACコード】 39.優先度付きキュー リンク:【Python】優先度付きキューの使い方【heapq】【ABC141 D】 ある状態での最小値や最大値を取得し、取りうる要素の追加も合間に繰り返す場合に使用します。詳細はリンク先で説明されています。 ちょっとした注意点が、リストの最初のアイテムは常に最小の値となることが保証されている程度であることです。ヒープの中が最小値順にソートされていることは保証されていません。(参考) また、タプルについても優先度付きキューに取り込むことが可能です。(参考) 問題: ABC137 D Summer Vacation - 【ACコード】 AGC053 B Taking the middle - 【ACコード】 40.しゃくとり法 リンク:AtCoder Beginner Contest 172を見直す(その2)C - Tsundoku 尺取り法 forとwhileの組み合わせで見ていきます。 詳細は、けんちょんさんの記事の記事にて。 最近は出てきてない気がしますね…そろそろ出てきそうです。 問題: ARC022 B 細長いお菓子 - 【ACコード】 ABC130 D Enough Array - 【ACコード】 yukicoder No.607 開通777年記念 - 【ACコード】 リンク先の記事については、あまり類題がない逆順からのコードのため、スニペットとして用意するなら、通常の順番であるEnough ArrayなどのACコードで用意しておいた方がいいと思います。 41.おすすめな情報 問題を解くに当たって、ほか有益なだと思われる情報をいくつかピックアップします。 競技プログラミングで解法を思いつくための典型的な考え方  制約によってどのアルゴリズムを使いそうか、といった情報が載っています。 AtCoderで始めるPython入門AtCoderで始めるPython入門  Pythonで解く際の基本的な書き方についてまとめられています。 Pythonで競プロやるときによく書くコードをまとめてみた  Pythonで解く際の基本的な書き方についてまとめられています。 Pythonistaなら知らないと恥ずかしい計算量のはなし  理解していないとTLEしてしまいがちになる計算量の話です。 AtCoder での実力アップを目指そう! ~競プロ典型 90 問~  ACコードがまだ載せられないので挙げませんでしたが、典型問題の紹介です。良問揃いです。 レッドコーダーが教える、競プロ・AtCoder上達のガイドライン【中級編:目指せ水色コーダー!】  上記競プロ典型 90 問作成者であるe869120さんの水コーダーを目指すためのガイドラインです。 unidayoさんのABCの解説  直近のABCのA~Cを解説しています。丁寧な解説のため、より効率的なコードの書き方を覚えることができます。復習にもってこいの記事です。 42.アルゴリズムを使用するにあたって いくつかのアルゴリズムを紹介しました。では、実際にどのように取り出して使用しているかについて、私はCliborというソフトを使用しています。 競プロ界隈で、使用している人は見かけませんが、非常に使い勝手が良いです。 よく使うスニペットを定型文に登録することで、すぐにそのスニペットを取り出すことができます。 定型文の一行目はコメントで何のアルゴリズムであるか記載しておくと見つける際に楽です。 上記で紹介したスニペットの他、↓のようなスニペットを登録して、入力時間の短縮を図っています。 N = int(input()) A = list(map(int, input().split())) N,K = map(int, input().split()) ans = True if ans: print('Yes') else: print('No') コピペに関する作業が一気に効率化されるため、業務でも使用しています。本当にお勧めです。 Clibor(窓の杜) お勧めの設定は↓こんな感じです。 困ることがあるとすれば、デフォルトのショートカットキーがCtrlを二連打なので、Apexを遊ぶ時は機能を止めないとしゃがむ動作でゲームが閉じられてしまうことです... 43.おわりに 上澄みをすくう記事で申し訳ないですが、Pythonのアルゴリズムについて、まとまった情報がなかなか見つかりにくいと感じたので作ってみました。 自分で考えるのは凄く大事ですが、あるものも使うのもよいことだと思います。 大人になるとね、熟考するより、stuck over flowで同じ問題抱えた人の投稿見つける方が大事だったりするんだ… 紹介した方のサイトのようにしっかり考えて作る人には感服するばかりです。 私が言うのはおこがましいですが、この記事を日々の精進に使用したり、本番前の確認に使用していただけたら幸いです。 この記事が誰かのお役に立つといいなと思います。 量の多い紹介となったため、チェックはしましたが、ミスが残っていると思われます。 説明の誤り、誤字脱字等が見つかればご連絡いただけると幸いです。不備があれば申し訳ありません。 また、説明内容に分からない点があれば、お気軽に質問していただけると幸いです。出来る限りお答えしたいと思います。 44.よければのお話 今回紹介したアルゴリズムの紹介先がよい記事であったり、素敵な問題であれば、ぜひともその記事や問題に対してスターや、LGTM、いいねを付けていただけたらと思います。 また、AtCoder以外のサイトやツールについても、AtCoder ProblemsのスポンサーやMojaCoderのスポンサー、yukicoderへのアマギフ提供などが行えます。 競プロの発展に多大な貢献をしていただいている方々に、金銭的な支援を行っていただけたら幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pythonのDjangoをつかって簡単ブログ作成③ CSSを使ってみよう

前回に引き続き挑戦記事です。 前回 今回はCSSも使って、テンプレートしてみよう!!挑戦です。 まず、CSSを記述するためのフォルダとファイルを準備 Djangoでは 「static」と言う名前で作るという決まりがあるみたいです。 この中に「image]もいれるし、あと「java.supript」もこの中にいれるらしい・・・・ 今回はファイル名は「main.css」にします。 そして背景をピンクに指定。 そのあと、htmlのファイルに以下を記述 staticの場合はloadが必要らしい。 しかし、ブラウザで確認したらピンクになってない。。。 しばし戦います。。 あっ!!判明しました!! サーバーの再起動が必要でした〜。。。 無事にトップ画面にはピンクが適用されました〜!! で、aboutページにも同じ記述するのは面倒だし、エラーがでそう そこで今度は別のテンプレートを使う extendsとblockタグを使ってみよう!! また、基盤となるテンプレートファイルを作りそこの繰り返し使う記述をかく 変えたい部分にはblockタグで囲う そしてindexとaboutのファイルを編集 そしてブラウザで変更なってないか確認 大丈夫でした!! そして画像の貼り付け方法 staticフォルダに貼り付けたい画像をアップデート 表示したいhtmlのファイルに記述 なかなか、表示されないと思っていたら。。。imgをimageにしてました。。 なんとかここまでできたよ〜!! まだまだ挑戦は続く・・・
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ヒカキンシンメトリーbotを勝手に復活させた話

はじめに こんにちは。かつて稼働していたTwitterアカウントヒカキンシンメトリbotをご存知でしょうか。 全自動でヒカキンさんのサムネイルなどをシンメトリー(左右対称)にしてTwitterにアップロードするアカウントです。 こんなやつ↓ 本人に取り上げられて一時期有名になりました。 ですがそのアカウントは2019年末より稼働しなくなってしまいました。 なので今回緊急事態宣言発令中でほぼニート状態の暇人がヒカキンシンメトリーbotを勝手に復活させました。 Twitter @SYMHIKA_SEI 本家との変更点 大きな変更 投稿時刻 まず大きな変更として毎日00:10に前日分の画像のシンメトリーを一括して投稿します。 本家シンメトリーbotでは本人様がアップロードされた直後の1時間以内くらいに投稿されてましたが、新しいやつではサーバーの都合上00:10に投稿します。(00:00分じゃ駄目なのかという話もあるかも知れませんが別のbot @randomhikakin の定期実効タイミングだったりMySQLのキャッシュリフレッシュをしてたりと処理が重くなりがちなので10分遅らせています。 取得対象 【旧】HikakinさんのYouTubeサムネイル・Twitter画像 【新】HikakinさんのTwitter画像 +SeikinさんのTwitter画像 新版ではSeikinさんを勝手に追加しました。(ごめんなさい) ※YouTubeのサムネイルの取得を廃止しました。 背景としては2019年頃よりYouTube動画をTwitterで告知する際にOPG(カード画像)が表示されなくなったため動画投稿者は直接Twitter上で動画サムネイル画像をアップロードするようになったからです。YouTube API v3等を使わずにTwitter APIのみで完結するようになったのでありがたいです。 追加取得 後述する問題点に対処するため過去のHikakinTVのサムネイルのシンメトリーを毎日18:00に投稿します。 独自に取得したHikakinTVチャンネル動画データベースから取得する感じです。 全動画のjsonファイルは配布してあります。 ※PHPで特定チャンネル内のすべての動画情報を一括して取得する方法(自筆/下は英語版) システムの変更 顔認識 顔認識を行う仕組みを変更しました。 【旧】Google Cloud Vision API 【新】OpenCV(Python) 退化してんじゃね?って思われそうですが仕方ないんです。お金払うのが嫌なんです… AzureのComputer Vision APIなら制限内で無料でやれるかも知れないんでそれでやるかもしれないです。(情報処理学会のジュニア会員なのでAzure Studentの1万円クーポンがあるから使おうか使うまいか…) システム設計 bot内のシステムは本家botのソースコードは利用せず一から組み直しました。 ※本家Botのソースコードは↓ 使用言語・ライブラリは以下のとおりです。tweepyとかを使うとオールPythonで行けたかも知れませんが動けばヨシ!とにかく暇なうちに…と考えた結果死ぬほど使い倒したPHPのtwitteroauthでツイート関連処理は組みました。 ソースコードは頒布しません。汚いので。 処理 言語(ライブラリ) ツイート画像取得処理 PHP(abraham/twitteroauth) 顔認識&反転処理 Python(OpenCV/numpy) 画像投稿処理 PHP(abraham/twitteroauth) 定期実行処理 Linuxのsystemd.timer ※動作環境:Ubuntu 20.04 LTS / PHP7.4(Composer使用) / Python3.8(pip使用) データフローダイアグラムはこんな感じです。 問題点 今回新しく作った上で生じた問題としてヒカキンさん達が顔加工しまくっててうまく認識されない問題があります。 例えば若干の変顔であればOpenCVの笑顔プリセットで認識してくれます。 ですが↓のようにめちゃくちゃ加工してしまうと認識できないor誤認識してしまうんです。 このことから認識できない場合が多いことが予想されるので比較的補正のかかってない過去のサムネイル画像を投稿する仕組みを導入しました。 皆さんも是非見てみてください。そしてヒカキンさんセイキンさんすみませんm(_ _)m https://twitter.com/SYM_HIKA_SEI 諸連絡 動作に関する不具合やご要望がありましたら@tomox0115までメンション飛ばして教えて下さい。すぐ対応します。 【ブログ】https://0115765.com/ 【Twitter】*@tomox0115
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

スパース主成分分析への理解

スパース主成分分析とは 主成分分析は、[1]によれば、『しかし、各主成分の寄与率が小さいとき、(例えば 10 個の特徴量が持つ情報量を 5 個の主成分で 6 割しか説明できないよう場合であれば、)データ全体を解釈するために、より多くの主成分を選ぶ必要がある。より多くの主成分を選ぶと、その主成分の解釈が難しくなる。この主成分に対してもスパース推定というアプローチをすることができる。主成分を推定する際に、主成分がなるべく 0 になるように推定するアプローチである。』 つまり、 次元圧縮の際、主成分分析は二乗誤差最小化を使うが、スパース主成分分析は、L1正則化(Lasso回帰)を行う。これにより、各主成分から解釈に不要な変数を取り除くことができる。[2] 主成分分析[2] \hat{V} = \underset{V_k}{\operatorname{argmin}} \sum_{i=1}^n ||x_i - \hat{x_i} ||^2 \quad s.t. \quad \hat{x_i} = V_k V_k^T x_i. 主成分分析についてよくまとまった記事がありましたので、詳しく知りたい方はどうぞ。 スパース主成分分析[3] V(\hat{A}, \hat{B}) = \underset{A,B}{\operatorname{argmin}} \{ \sum_{i=1}^n ||x_i - AB^Tx^i ||^2 + \lambda_2 \sum_{j=1}^k || \beta_j ||^2 + \sum_{j=1}^k \lambda_{1,j} || \beta_j ||_1 \}. レポジトリーはこちらです。 スパース推定(Lasso回帰)について E(x) = ||y - Ax||^2 + \lambda \sum_{i=1}^n|w|_1 ここで、過学習を説明する、過学習とは、訓練データを用いた場合は、最適解ではあるが、 未知のデータに適用した場合は、最適解にはならないというものである。 そこで、通常の最小二乗法に対して、正則化項を加えたものを(Lasso回帰、Ridge回帰)という。 一般にL1正則化(Lasso回帰)にスパース回帰に向いているが、L2正則化(Ridge回帰)は向いていない。 上の式の意味は 正則化項で答えの候補を絞り込み 観測データから候補を出す この二つのバランスさせる。 Lasso回帰、Ridge回帰についての詳しい解説はこちら 正則化項の決定 スパース主成分分析は正則化項を自由に設定できる。 正則化項を変更することで、過学習を回避できる。 正則化項の決定には、ベイズ情報量規準(以下、bicと記す)、赤池情報量基準(以下、aicと記す)を使う。 [5]によれば、『予測ではなく妥当なモデルの構造を知りたい』ときに使う。 以下[6]より、 AIC = -2 \sum_{i=1}^n logp(X_i| W^*) + 2d BIC = -2 \sum_{i=1}^n logp(X_i| W^*) + dlogn 実装 import numpy as np import numpy.random as random import matplotlib.pyplot as plt import pandas as pd import matplotlib as mpl import seaborn as sns import scipy as sp from sklearn.linear_model import LassoLarsIC from sklearn.preprocessing import StandardScaler from sklearn.datasets import make_friedman1 from sklearn.decomposition import SparsePCA X, y = make_friedman1(n_samples=200, n_features=30, random_state=0) #標準化 scaler = StandardScaler() scaler.fit(X) X = scaler.transform(X) spca_std = SparsePCA(n_components=5, random_state=0) spca_std.fit(X) X_spca_std = spca_std.transform(X) 主な出力 #データから抽出されたスパース成分。 print(spca_std.components_) #各イテレーションにおけるエラーのベクトル print(spca_std.error_) #想定される構成要素の数(既存バグでエラー、予測変換でも出てこない) #print(spca_std.n_components_) print(spca_std.n_components) #イテレーションの実行回数 print(spca_std.n_iter_) #トレーニングセットから推定された、各特徴の経験的平均値。X.mean(axis=0)と同じです。 print(spca_std.mean_) 正則化項の決定 # defauoltはalpha=1で出す。スパース性が低いとalpha=0が算出されるので注意が必要 model_bic = LassoLarsIC(criterion='bic') model_bic.fit(X, y) alpha_bic_ = model_bic.alpha_ print(alpha_bic_) model_aic = LassoLarsIC(criterion='aic') model_aic.fit(X, y) alpha_aic_ = model_aic.alpha_ print(alpha_aic_) 代入 spca_bic = SparsePCA(n_components=5, random_state=0, alpha = alpha_bic_) spca_bic.fit(X) X_spca_bic = spca_bic.transform(X) print(X_spca_bic.shape) spca_aic = SparsePCA(n_components=5, random_state=0, alpha = alpha_aic_) spca_aic.fit(X) X_spca_aic = spca_aic.transform(X) print(X_spca_aic.shape) 結果 print('defoult a=1 :',np.mean(spca_std.components_ == 0)) #defoult a=1 : 0.6933333333333334 print('bic a=0.02871277337904591 :',np.mean(spca_bic.components_ == 0)) #bic a=0.02871277337904591 : 0.12666666666666668 print('aic a=0.022802510590416925 :',np.mean(spca_aic.components_ == 0)) #aic a=0.022802510590416925 : 0.07333333333333333 情報量規準を用いて正則化項を変更したことで、主成分が0に近づいたことが分かる。 参考文献 [1] [2] [3] [4] [5] [6]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

django復習(tables2)

とりあえずdjangoの復習用に適当にテーブルを作成。 投入データは下記から取得。 日本政府が出してるっぽいデータ from django.db import models from datetime import datetime # 人口テーブル class Population(models.Model): prefectures_code = models.CharField(max_length=10,verbose_name="都道府県コード", null=False) prefectures = models.CharField(max_length=10,verbose_name="都道府県", null=False) era = models.CharField(max_length=500, verbose_name="元号", null=False) jp_calendar = models.CharField(max_length=500, verbose_name="和暦", null=False) year = models.CharField(max_length=500, verbose_name="西暦", null=False) population = models.CharField(max_length=500, verbose_name="人口", null=False) man = models.CharField(max_length=500, verbose_name="男", null=False) woman = models.CharField(max_length=500, verbose_name="女", null=False) create_date = models.DateTimeField(default=datetime.now, null=True, verbose_name="登録日") def __str__(self): return self.prefectures 適当すぎて人口の数値部分も文字列で作成。 問題ないかと思いそのまま続行した結果、色々被害続出。 ・tables2の復習で最新年度の人口の表を作成したが、  ソート機能が文字列(辞書順)でソートしてしまうため、正しくソートできない。  例:   123000,200,500があった場合、辞書順なので1文字目を取って   123000 < 200 < 500 になる。 ・matplotlibの復習で特定の県について年ごとの人口の推移を見ようとしたが、  人口が文字列のため、グラフがちゃんとできない。  例:   1年間で100万人→120万人に増えても1メモリ分しか増加しない。   1年間で100万人→200万人に増えても1メモリ分しか増加しない。 matplotlibの方は特にハマらなかったのでtables2についてメモ。 (model直してDB作り直すのが一番ですが、勉強も兼ねてmodelはそのままで続行) table.pyのソース from population.models import Population import django_tables2 as tables from django_tables2.utils import A from population.models import Population class ButtonLinkColumn(tables.LinkColumn): """ リンク表示用カラム(ボタン) """ def render(self, record, value): if record.count > 0: # ステータス:完了 return "データ表示" else: # ステータス:完了以外 return "" class PopulationTable(tables.Table): """ 人口画面用テーブル Population """ prefectures = tables.Column(verbose_name="都道府県") # リンク用 plot = tables.LinkColumn("population:pop_plot", args=[A("prefectures_code")], verbose_name = "",text="人口グラフ", attrs={"a": {"class": "btn btn-success text-nowrap"}} ) population = tables.Column(verbose_name="総人口") man = tables.Column(verbose_name="人口(男性)") woman = tables.Column(verbose_name="人口(女性)") class Meta: model = Population template_name = 'django_tables2/bootstrap4.html' # 表示する列column fields = ('prefectures_code', 'prefectures', 'plot', 'population', 'man', 'woman', ) attrs = {"class": "table table-striped"} django-tables2の参考サイト 参考サイトを見るとorder_カラム名で対象のカラムのソート条件をいじれるらしい。 from django.db.models.functions import Length ~以下中略~ def order_name(self, queryset, is_descending): queryset = queryset.annotate( length=Length("first_name") ).order_by(("-" if is_descending else "") + "length") return (queryset, True) 真似してmanでやってみると、桁数でのソートはできた。 def order_man(self, queryset, is_descending): queryset = queryset.annotate( length=Length("man") ).order_by(("-" if is_descending else "") + "length") return (queryset, True) じゃぁ次は数値でソートしたいと思ったが、ここからが問題。 理解度が低いせいかLength部分に何が入るか分からず、そこを調べるのに時間がかかった。 色々調べたが、googleでは上手く見つけられずdjango.db.models.functionsを調べることで解決した。 from .comparison import Cast, Coalesce, Greatest, Least, NullIf from .datetime import ( Extract, ExtractDay, ExtractHour, ExtractIsoWeekDay, ExtractIsoYear, ExtractMinute, ExtractMonth, ExtractQuarter, ExtractSecond, ExtractWeek, ExtractWeekDay, ExtractYear, Now, Trunc, TruncDate, TruncDay, TruncHour, TruncMinute, TruncMonth, TruncQuarter, TruncSecond, TruncTime, TruncWeek, TruncYear, ) from .math import ( Abs, ACos, ASin, ATan, ATan2, Ceil, Cos, Cot, Degrees, Exp, Floor, Ln, Log, Mod, Pi, Power, Radians, Round, Sign, Sin, Sqrt, Tan, ) from .text import ( MD5, SHA1, SHA224, SHA256, SHA384, SHA512, Chr, Concat, ConcatPair, Left, Length, Lower, LPad, LTrim, Ord, Repeat, Replace, Reverse, Right, RPad, RTrim, StrIndex, Substr, Trim, Upper, ) from .window import ( CumeDist, DenseRank, FirstValue, Lag, LastValue, Lead, NthValue, Ntile, PercentRank, Rank, RowNumber, ) __all__ = [ # comparison and conversion 'Cast', 'Coalesce', 'Greatest', 'Least', 'NullIf', # datetime 'Extract', 'ExtractDay', 'ExtractHour', 'ExtractMinute', 'ExtractMonth', 'ExtractQuarter', 'ExtractSecond', 'ExtractWeek', 'ExtractIsoWeekDay', 'ExtractWeekDay', 'ExtractIsoYear', 'ExtractYear', 'Now', 'Trunc', 'TruncDate', 'TruncDay', 'TruncHour', 'TruncMinute', 'TruncMonth', 'TruncQuarter', 'TruncSecond', 'TruncTime', 'TruncWeek', 'TruncYear', # math 'Abs', 'ACos', 'ASin', 'ATan', 'ATan2', 'Ceil', 'Cos', 'Cot', 'Degrees', 'Exp', 'Floor', 'Ln', 'Log', 'Mod', 'Pi', 'Power', 'Radians', 'Round', 'Sign', 'Sin', 'Sqrt', 'Tan', # text 'MD5', 'SHA1', 'SHA224', 'SHA256', 'SHA384', 'SHA512', 'Chr', 'Concat', 'ConcatPair', 'Left', 'Length', 'Lower', 'LPad', 'LTrim', 'Ord', 'Repeat', 'Replace', 'Reverse', 'Right', 'RPad', 'RTrim', 'StrIndex', 'Substr', 'Trim', 'Upper', # window 'CumeDist', 'DenseRank', 'FirstValue', 'Lag', 'LastValue', 'Lead', 'NthValue', 'Ntile', 'PercentRank', 'Rank', 'RowNumber', ] 上記にあるメソッドは大体使えるっぽいのでAbs(絶対値)を使って解決した。 def order_population(self, queryset, is_descending): queryset = queryset.annotate( abs=Abs("population") ).order_by(("-" if is_descending else "") + "abs") return (queryset, True) def order_man(self, queryset, is_descending): queryset = queryset.annotate( abs=Abs("man") ).order_by(("-" if is_descending else "") + "abs") return (queryset, True) def order_woman(self, queryset, is_descending): queryset = queryset.annotate( abs=Abs("woman") ).order_by(("-" if is_descending else "") + "abs") return (queryset, True)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】VS Code Run Without Debugging on macOS

Code の Python プログラム 実行 以下のような方法があります. .ipynb ファイルを Jupyter Notebook 風に実行する Interactive cell を別タブで開く(# %% とスクリプトに書いて shift+Enter or ctrl+Enter) ドラッグで選択して shift+Enter Run メニューに有るコマンドを実行する. Jupyter Notebook からの移行は1が便利です.最近使っているのは2です.3はあまり使っていません. 今回は4についての記事です. もとのコマンドがうまく動かない ^ + F5 と書いてあるのですがうまく動きません.BetterTouchToolでも解決を試みましたがよくわかりません. 実行環境:macOS 10.15.4,Code Version: 1.55.2, Python 3.8.6. 解決方法 システム環境設定>キーボード>ショートカット(「ショートカット」で検索)>アプリケーション と入ります.+で Visual Studio Code (Finder では Code) にショートカット Run Without Debugging を追加し,⌘Rを紐付けます.これで完了です.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pythonのDjangoをつかって簡単ブログ作成② テンプレートを使ってみる!!

python初心者なので、勉強中です。 挑戦記事なので、サーバー立ち上げたらエラーなんてザラなのでコードの記述は違うこと多々あるのでそこは多めにみてください(笑) 前回の記事はこちら テンプレートを使うと毎回使う記述を一つにまとめることができるのでエラーにもなりにくい コードが読みやすくなるなど利点が多いです テンプレートを組み立てるのに使う3つの要素 変数 {{ 変数名 }} タグ {% タグ名 %} フィルタ {{ 値 | フィルタ名 }} まずは、テンプレート使わないバージョン 2つのページに同じ記述をしてます。 ブラウザではこんな感じ このままでは、変更があった場合両方のページを修正しないといけない パーツとして切り出す includeタグを使ってきりだす 専用のファイルを作成 テンプレートファイルの名前は先端に「_」をつける そして、切り出したいパーツを切り取ってテンプレートファイルに移し 元の方にはそれをよびだす記述コードをかく ブラウザで変わってないか確認。 そして今度は_footer.htmlを作ってテンプレートで表示させてみる。 これで両方のページに表示できる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pandas 列の並び替え、実はこいつが速かった(決定版)

summary タイトルは煽りです。ごめんなさい。 結論: 次の5通りの方法があるが、並び替え後の列名に新しい列名(既存の列名に含まれない)ケースでのエラーを明示的にするため df[new_col] が無難(タイプ量も少ない観点もプラス)。 速度の違いは微々たるものだが、少しでもパフォーマンス要求される場合は df.loc[:, new_col] が速い。 new_cols = [...] df[new_cols] df.filter(new_cols, axis=1) df.reindex(columns=new_cols) df.reindex(new_cols, axis=1) df.loc[:, new_cols] これは何 Pandas での列の並べ替え方法は複数ある。それらのどれを使えばよいのか調査した。 速度の観点 概ね reindex < filter < .loc[:, ...] < [ の順で時間がかかる filter は内部で reindex を 呼んでいる [ -> __getitem__ -> self._take_with_is_copy (pandas.core.generic.py) -> self.take で 必ずコピーを返す(pandas 1.0 以上) .loc は class _LocationIndexer -> __getitem_ -> _getitem_tuple -> _getitem_tuple_same_dim -> _getitem_axis -> self.obj.iloc[tuple(indexer)] と呼び出す method が多い 列x行の数(以下要素数)に比例して処理時間がかかり、同じ要素数の場合は行数が多い方が処理時間が長い patterns = { 1: lambda: df[cols_new], 2: lambda: df.filter(cols_new, axis=1), 3: lambda: df.reindex(columns=cols_new), 4: lambda: df.reindex(cols_new, axis=1), 5: lambda: df.loc[:, cols_new], } 以下の図は DataFrame の各 shape に対する上記5パターンの対応を timeit.repeat(repeat=10, number=100) にて計測した結果である。 python code import numpy as np import pandas as pd import timeit import seaborn as sns import matplotlib.pyplot as plt def make_df(row_num, col_num, seed=1) -> pd.DataFrame: rng = np.random.default_rng(seed=seed) return pd.DataFrame({f"x{i}": rng.random(row_num) for i in range(col_num)}) rows = [1_000, 10_000, 100_000, 1_000_000, 10_000_000] cols = [10, 100] # limit max shape because (10_000_000, 100) overflows on my machine dfs = [make_df(r, c) for r in rows for c in cols if r * c <= 1e8] def reorder_columns(df, repeat=10, n=100, seed=1) -> dict[int, list[float]]: rng = np.random.default_rng(seed=seed) col_names = [f"x{i}" for i in range(df.shape[1])] cols_new = rng.permutation(col_names) # reorder patterns = { 1: lambda: df[cols_new], 2: lambda: df.filter(cols_new, axis=1), 3: lambda: df.reindex(columns=cols_new), 4: lambda: df.reindex(cols_new, axis=1), 5: lambda: df.loc[:, cols_new], } out = {k: timeit.repeat(v, repeat=repeat, number=n) for k, v in patterns.items()} return out results = {df.shape:reorder_columns(df) for df in dfs} results_df = pd.concat([ pd.DataFrame({"shape": str(k), "row": k[0], "col": k[1], "pattern": k2, "times": v2}) for k,v in results.items() for k2, v2 in v.items() ]) def draw(df: pd.DataFrame, filename: str, show=False) -> None: plt.clf() # sns.set_theme(style="whitegrid") sns.set_style("whitegrid", {'grid.linestyle': '--'}) f, ax = plt.subplots() sns.despine(bottom=True, left=True) # Show each observation with a scatterplot sns.stripplot(x="times", y="shape", hue="pattern", data=df, dodge=True, alpha=.25, zorder=1) # Show the conditional means sns.pointplot(x="times", y="shape", hue="pattern", data=df, dodge=.532, join=False, palette="dark", markers="d", scale=.75, ci=None) # Improve the legend handles, labels = ax.get_legend_handles_labels() pos = len(df['pattern'].unique()) ax.legend(handles[pos:], labels[pos:], title="patterns", handletextpad=0, columnspacing=1, bbox_to_anchor=(1.05, 0.5), loc="center left", ncol=1, frameon=True) # y label ax.set_yticklabels(ax.get_yticklabels(), fontdict={'fontsize' : 8}) f.tight_layout() plt.savefig(f"20210501-python-columns/{filename}") if show: f.show() draw(results_df.loc[lambda df_: df_['row'] * df_['col'] <= 1e5], "shape_<=1e5.png") draw(results_df.loc[lambda df_: df_['row'] * df_['col'] == 1e6], "shape_1e6.png") draw(results_df.loc[lambda df_: df_['row'] * df_['col'] == 1e7], "shape_1e7.png") draw(results_df.loc[lambda df_: df_['row'] * df_['col'] == 1e8], "shape_1e8.png") draw(results_df.loc[lambda df_: df_['shape'] == '(1000000, 10)'], "shape_1e6x1e1.png") draw(results_df.loc[lambda df_: df_['shape'] == '(100000, 100)'], "shape_1e5x1e2.png") draw(results_df.loc[lambda df_: df_['shape'] == '(10000000, 10)'], "shape_1e7x1e1.png") draw(results_df.loc[lambda df_: df_['shape'] == '(1000000, 100)'], "shape_1e6x1e2.png") 列名エラーの観点 既存の列名に含まれない列名を指定した時の挙動 [ (__getitem__) はエラー filter は存在する列のみ抽出 reindex は存在する列のみならず、存在しない列は値を NaN で作成 .loc はエラー df = pd.DataFrame({'x': [0, 2, 3], 'y': list('abc')}) cols_new = ['x', 'z'] # z is not included in df.columns df[cols_new] # KeyError: "['z'] not in index" df.filter(cols_new) # x # 0 0 # 1 2 # 2 3 df.reindex(columns=cols_new) # x z # 0 0 NaN # 1 2 NaN # 2 3 NaN df.reindex(cols_new, axis=1) # x z # 0 0 NaN # 1 2 NaN # 2 3 NaN df.loc[:, cols_new] # KeyError: "Passing list-likes to .loc or [] with any missing labels is no longer supported. The following labels were missing: Index(['z'], dtype='object'). See https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#deprecate-loc-reindex-listlike" 動作環境 $ python -V Python 3.9.4 $ python -c 'import pandas as pd; print(pd.__version__)' 1.2.4 以上。 こういう深掘りが好きな方、ぜひ justInCase へ遊びに来てみてください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

kivyMDチュートリアル其の什伍 Components - Button篇

みなさん、GW期間中はいかがお過ごしでしょうか。 私はとくにやることありませーん!w だからと言って暇だからqiita書いているわけではなく... うそです、すみません。暇だから書いています。。お仕事を...下さい... # わりとガチな要望だったりして なので、みなさんもGW中に学んで「コピペで1千万エンジニア」を目指しましょう。 # 駆け出しエンジニアと繋がりたいとか言ってみたりして という冗談はさておき、KivyMDに入っていきましょう。今日はGW特別企画第2弾ということで、 前回の宣言通りButton篇になります。 Button いつものようにMaterialDesignのリンクは飛ばすようにします。ただし、中に書かれてある ものは結構有益というかそれは当たり前なのですが、原則や注意点などが色々と書かれてあり ます。ひととおり、目を通すことをおすすめします。 少しこのお題は、自身にとって結構重みが深い内容だなぁと思っています。# 急にどうした なので、週末に取り掛かるには少し時間が足りないなぁと思ってGW企画にしました。たかがボタン、 されどボタンというわけで、ボタンのことを触れ込んでいくと1ヶ月ほど掛かりそうな気がします。 人を移動させるエレベーターに使われたりするボタン、核実験の際にも使われたりするボタンなど 用途・場所・時代に応じて色々変化したりします。丸みを帯びたり、角ばった形をしたりと形も様々 となります。 ということで長くなりそうなので、ボタンの詳細はこの辺にしておくことにします。ボタンの構造学 みたいな本があったら、買ってみようかな。まぁ、一旦置いておいてKivyMDに続きます。 # ただのボタンフェチだったりして マニュアルの説明からは、ボタンの概要として以下のように書いてあります。 Buttons allow users to take actions, and make choices, with a single tap. 疑う余地もありません。 で、続きましてKivyMD側のボタンは以下の12種類用意してあるよ、と説明があります。 MDIconButton MDFloatingActionButton MDFlatButton MDRaisedButton MDRectangleFlatButton MDRectangleFlatIconButton MDRoundFlatButton MDRoundFlatIconButton MDFillRoundFlatButton MDFillRoundFlatIconButton MDTextButton MDFloatingActionButtonSpeedDial 先にあれこれマニュアルから触れ込んでもよいのですが、サンプルコードを先に貼り付けておきます。 今日のサンプルコードは、下部あたりにある[See full example]のリンク先にあったサンプルコード からの抜粋です。少しこちらは長かったので、カスタマイズされたものをすべて除外したりMDFloating- -ActionButtonSpeedDialを組み合わせていたりします。オリジナリティは0にほぼ近い内容となります。 xv/buttons.py from kivy.lang import Builder from kivy.factory import Factory from kivymd.app import MDApp Builder.load_string( """ <ExampleButtons@Screen>: MDToolbar: title: app.title elevation: 10 pos_hint: {'top': 1} BoxLayout: padding: dp(10) size_hint: None, None size: self.minimum_size spacing: dp(10) orientation: "vertical" pos_hint: {"center_x": .5} MDIconButton: icon: "sd" pos_hint: {"center_x": .5} MDFloatingActionButton: icon: "plus" opposite_colors: True elevation_normal: 8 pos_hint: {"center_x": .5} MDFlatButton: text: "MDFlatButton" pos_hint: {"center_x": .5} MDRaisedButton: text: "MDRaisedButton" elevation_normal: 2 opposite_colors: True pos_hint: {"center_x": .5} MDRectangleFlatButton: text: "MDRectangleFlatButton" pos_hint: {"center_x": .5} MDRectangleFlatIconButton: text: "MDRectangleFlatIconButton" icon: "language-python" width: dp(230) pos_hint: {"center_x": .5} MDRoundFlatButton: text: "MDRoundFlatButton" pos_hint: {"center_x": .5} MDRoundFlatIconButton: text: "MDRoundFlatIconButton" icon: "language-python" width: dp(200) pos_hint: {"center_x": .5} MDFillRoundFlatButton: text: "MDFillRoundFlatButton" pos_hint: {"center_x": .5} MDFillRoundFlatIconButton: text: "MDFillRoundFlatIconButton" icon: "language-python" pos_hint: {"center_x": .5} MDTextButton: text: "MDTextButton" pos_hint: {"center_x": .5} MDFloatingActionButtonSpeedDial: data: app.data root_button_anim: True """ ) class MainApp(MDApp): def __init__(self, **kwargs): self.title = "KivyMD Examples - Buttons" self.data = { 'language-python': 'Python', 'language-php': 'PHP', 'language-cpp': 'C++', } super().__init__(**kwargs) def build(self): self.root = Factory.ExampleButtons() if __name__ == "__main__": MainApp().run() コードからは以上となります。ここからはマニュアルと比べ合わせながら進んでいきます。 kv側 いや、いきなりマニュアル入らねーのかい!みたいなツッコミがされてそうですが、ちょうど 前回のおさらいがてらkvの最初っから入っていこうではありませんか。 # 謎の提案 レイアウト <ExampleButtons@Screen>: (略) BoxLayout: padding: dp(10) size_hint: None, None size: self.minimum_size spacing: dp(10) orientation: "vertical" pos_hint: {"center_x": .5} レイアウトになります。とりあえず、まだMDToolbarは触れ込んでいないので対象外として 省略しています。あれ、リンク先ではExampleButtonsってBoxLayoutを継承してなかった っけって言う方はするどいです。というかリサーチ力がえぐいです。 これも別に継承させなくてもいいや、えいって継承をなくそうとしたのですが、Factoryでの インスタンス化の制限に引っかかってしまいました。。どうやらFactoryでのインスタンス化 をする上では、ルートウィジェットをいづれのウィジェットから継承させる必要があるそうです。 というか私がkivyの仕様知らなすぎるのと、kivyをこれまでガッツリ触ってきた方は当たり前 のことだったりして。。 ということでひとまず、BoxLayoutを継承させるには少々MDToolbarを使いにくいことと、 レイアウトをそんなに考えなくて済むようにするためにScreenウィジェットを継承させました。 んで、あとは前回のおさらいですが、定義してあるBoxLayoutですね。これが終わればやっと ボタンに進めます。padding・spacing・orientationは以下リンクで触れていますので、 適宜参照してもらえれば。 kivyMDチュートリアル其の伍 Themes - Icon Definitions篇 続きますが、size_hint、size...これはどこかで見かけましたね!なんだこれと言う方は 前回のLayout篇を参照ください。 kivyMDチュートリアル其の什肆 Components - Layout篇 あとは、pos_hintですがこれは今まで出たことあったっけ?と自分でもあやふやになっている ので一応触れますが、単に横方向に中央揃えしますよということになります。この形は縦配置 するときによく使われそうです。良く分からなければ、この形を暗記しましょう。 button ようやく今日のメインディッシュです。 MDIconButton マニュアルから入っていきます。 一旦、マニュアルのサンプルコードは置いておいて説明から進みます。 説明については以下のように述べられています。 The icon parameter must have the name of the icon from kivymd/icon_definitions.py file. You can also use custom icons: MDIconButton:   icon: "data/logo/kivy-icon-256.png" アイコンはicon_definitions.pyに定義されているものを使ってよということですね。 ただしカスタムアイコンも使うことは出来るようです。 By default, MDIconButton button has a size (dp(48), dp (48)). Use user_font_size attribute to resize the button: user_font_sizeって名前微妙じゃねえぇー?という生意気なことを言いたくなりますが アイコンサイズも変更できるようです。デフォルトは(dp(48), dp (48))とのことです。 これは後で結果の方を見てみましょう。 By default, the color of MDIconButton (depending on the style of the application) is black or white. You can change the color of MDIconButton as the text color of MDLabel: MDIconButton:  icon: "android"  theme_text_color: "Custom"  text_color: app.theme_cls.primary_color これは後々わかることですが、アイコンはデフォルトで白黒となるようです。 これもメインのテーマカラーなどに引き継ぐことが出来て、後でこの様子を見てみましょう。 MDFloatingActionButton こちらは浮き上がって見えるようなアイコンボタンになります。まぁ、訳している だけですけどねぇ。。 The above parameters for MDIconButton apply to MDFloatingActionButton. To change MDFloatingActionButton background, use the md_bg_color parameter:  MDFloatingActionButton:   icon: "android"   md_bg_color: app.theme_cls.primary_color MDIconButtonでも使われていたパラメータはこちらでも使えるよ(適用される)ということ でしょうか。あとは、背景変えたければ専用のパラメータを使ってねということもあるので これも後で見てみましょう。 The length of the shadow is controlled by the elevation_normal parameter:  MDFloatingActionButton:   icon: "android"   elevation_normal: 12 影を付けたければ、こんなのもあるよーということも。後回しにします。 MDFlatButton こちらは後述するテキストボタンと似ているものですが、枠線がないボタンになります。 To change the text color of: class:~MDFlatButton use the text_color parameter:  MDFlatButton:   text: "MDFLATBUTTON"   theme_text_color: "Custom"   text_color: 0, 0, 1, 1 文字カラーを変えたければ、これを使ってねーということも。同様、後回しにします。 Or use markup:  MDFlatButton:   text: "[color=#00ffcc]MDFLATBUTTON[/color]" マークアップが使えたり(はえぇーほんとすっごい) To specify the font size and font name, use the parameters as in the usual Kivy buttons:  MDFlatButton:   text: "MDFLATBUTTON"   font_size: "18sp"   font_name: "path/to/font" フォントが使えたりもします。これは試すことはしません(なんという自分勝手なのでしょう)。 MDRaisedButton MDFlatButtonとも似ていますが、こちらは枠の中に色付けをすることもできます。 This button is similar to the MDFlatButton button except that you can set the background color for MDRaisedButton:  MDRaisedButton:   text: "MDRAISEDBUTTON"   md_bg_color: 1, 0, 1, 1 こちらは後で試してみましょうかね。 MDRectangleFlatButton こちらは枠線が付いている中身が色付けされていないボタンになります。 枠線とテキストのカラーが選択できます。こちらは後述するMDRectangleFlatIcon- -Buttonで試すので、そのままで。 MDRectangleFlatButton:  text: "MDRECTANGLEFLATBUTTON"  theme_text_color: "Custom"  text_color: 1, 0, 0, 1  line_color: 0, 0, 1, 1 MDRectangleFlatIconButton こちらはMDRectangleFlatButtonにアイコンがくっ付いたものになりますね。 こちらでは色が付けられるかどうか見てみます。 MDRectangleFlatIconButton:  icon: "android"  text: "MDRECTANGLEFLATICONBUTTON"  theme_text_color: "Custom"  text_color: 0, 0, 1, 1  line_color: 1, 0, 1, 1  icon_color: 1, 0, 0, 1 line_colorをすべて0に設定すると、枠線なしにすることも可能らしいです。 意味があるのかどうか分からないですが。。 MDRoundFlatButton 枠線の角が丸っこいボタンになります。 MDRoundFlatButton:  text: "MDROUNDFLATBUTTON"  text_color: 0, 1, 0, 1 MDRoundFlatIconButton MDRoundFlatButtonにアイコンがくっ付いたものになりますね。 Button parameters MDRoundFlatIconButton are the same as button MDRoundFlatButton:  MDRoundFlatIconButton:   icon: "android"   text: "MDROUNDFLATICONBUTTON" パラメータについてもアイコン以外はMDRoundFlatButtonと同じらしいです。 MDFillRoundFlatButton こちらはMDRoundFlatButtonから枠線の中を全て色付けしているボタンになりますかね。 Button parameters MDFillRoundFlatButton are the same as button MDRaisedButton. こちらはMDRaisedButtonとパラメータは同様になるみたいです。 MDFillRoundFlatIconButton 省略したいところですが、こちらはMDFillRoundFlatButtonにアイコンをくっ付けたボタン。 パラメータについてもMDFillRoundFlatButtonと同様。 MDTextButton こちらはシンプルなボタンになりますね。テキストだけがあるボタンと言えますか。 MDTextButton:  text: "MDTEXTBUTTON"  custom_color: 0, 1, 0, 1 MDFlatButtonと違い、背景の色付けをするプロパティがないようです。これもどうなるか 確認が必要そうですね。 MDFloatingActionButtonSpeedDial 最後になりました。ボタンを押すとさらにボタンが現れるボタンです(ややこしい)。 使用方法はサンプルコードでもありますが、ここではkv側だけをマニュアルから抜粋。 ※ サンプルコードでも同じものを使用しています  MDFloatingActionButtonSpeedDial:   data: app.data   root_button_anim: True 使用方法は特に変わったものはなさそうです。が、dataについては意味不明な供述を しています。でも、ご安心を。この後で出てきますので。 # というかすでにマニュアルでは見えてますけどね class側 ここでは、MDFloatingActionButtonSpeedDialであった伏線を回収するためだけに 記載をします。まぁ、直に見てもらったほうが早そうですね。 class MainApp(MDApp): def __init__(self, **kwargs): self.title = "KivyMD Examples - Buttons" self.data = { 'language-python': 'Python', 'language-php': 'PHP', 'language-cpp': 'C++', } super().__init__(**kwargs) def build(self): self.root = Factory.ExampleButtons() マニュアルでもありましたが、少し形が変わっています。app(MainApp)側でdataとありますが、 MDFloatingActionButtonSpeedDialのdataプロパティの値はこの辞書型のdataと重なります。 マニュアルと変わっているところはまだあります。辞書型の定義がおかしいじゃねーか!何バグを 生み出してんだ!と強く叱責されそうな感じがありますが、これで正しいのです。なんとマニュアル の方がミスを犯していまして、何度も見直しましたがちゃんと動かないことには正しいことを証明 できません。それでも怪しいなと言う方がいらっしゃいましたら、サンプルコードを動かしてみて 下さい。 ふーん、そうなんだと言う方はアイコン名:表示文字列という組み合わせを覚えてもらえれば嬉しいです。 結果 ということで、今日も長かった! んなことはどうでもいいので、さっそく結果をお見せします。 おぉー、というか当たり前ですが出力はこんな感じになります。 で、右下にあるMDFloatingActionButtonSpeedDialボタンを押してみるとこんな感じになります。 うん、問題なさそうだ! MDFloatingActionButtonSpeedDialの方で動かないと述べましたが、少し強調していて動かない わけではないのですが、アイコンの検索ができなく枠がくり抜かれた様子が拝見できます。気になる 方はマニュアルの指定そのままにして実行してみて下さい。 んで、あとは後で見てみますねというものを回収しておきます。対象は以下で再掲しておきます。 MDIconButton MDFloatingActionButton MDFlatButton MDRaisedButton MDRectangleFlatIconButton MDTextButton 角が丸まっているボタンとMDFloatingActionButtonSpeedDialボタン以外になりますね。 ではどうなっているか見てみましょう。変更の仕方は上記で先述した通りでマニュアル記載の ものを変更なく使っています。 うーん、見事に反映されていますね。SDカードのアイコンに関してはツールバーに当たって しまってますね。これはいけない。アンチパターンのひとつですね。あとは影が大きすぎると なんか不恰好に見えてしまいますね。こちらのコードについてはGitHubの方でもアップして いるので、適宜そちらもみてもらえれば。 それにしても僕もKivyMD力が上がったものだ。。なんせ、マニュアルの指摘ができるように なったのだから。 まとめ とまぁ、だれも興味がないであろう独り言をしたところで締めくくろうかと思います。 さて、いかがだったでしょうか。何か使いたい、推しのボタンがありましたでしょうか。 用途によって様々だと思いますが、私はシンプルなMDRaisedButtonですかね。推しが ありましたら、どんどんコメントください。 ということで、GW企画第2弾としてのButton篇でした!スマホだけでなくアプリとしては 協力なアイテムの1つかと思われますので、どんどん使っていきたいものです。 次回は週末予定のGW第3弾のCard篇を予定しています。お楽しみに! それでは、ごきげんよう。 参照 Components » Button https://kivymd.readthedocs.io/en/latest/components/button/ GitHub - kivymd / KivyMD - Components Button https://github.com/kivymd/KivyMD/wiki/Components-Button
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PythonのDjangoで簡単なブログに挑戦

pyhtonのdjangoで簡単なブログを作ろうと挑戦する記事です。 かなり初心者ですが頑張ってみます。 プロジェクト、アプリは追加済み 復習するならこちら https://qiita.com/on97-nakamatsu-mayumi/items/e01f6653bc0b347e3716 https://qiita.com/on97-nakamatsu-mayumi/items/afda1e6b9fe72c5551e6 まずはtemplatesフォルダー(ディレクトリ)を作成 その中に index.html about.html を作成して 中身を記述していく。 次はviews.pyを作成 今度はurls.pyを記述していく ファイルがなければ自分で作成 アプリの方を記述したら、プロジェクトの方のurls.pyにも記述 そして、ドメインの許可とアプリの追加 そして一度サーバーを立ち上げたらエラーがでたので以下を修正 ここまでだとブラウザではこんなかんじ aboutページ トップページ 今回はここまで!! 次回はテンプレートを使いながら勉強します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Streamlit Docker on Heroku

TL;DR 公式のデプロイドキュメントに色々載っているのでその通りにやりましょう やったこと streamlitのお触り streamlit on docker Herokuへのデプロイ Streamlitとは pythonだけで簡単にアプリケーションを作れるフレームワーク。フロントエンドの知識なくてもオッケー。 インタラクティブな機能はもちろん、matplotlib、plotly、bokehなど一通り可視化ツールのサポートをしてるので、可視化結果を見せるのが非常に楽。 ※Dashとかも似たようなものらしいですが、Streamlitはより単純に、素早く書けるのがメリットのようです。その分柔軟性は低い?とか(比較検証はしてません) できたもの NBAのスタッツ(2018~19)とサラリー(2019~2020)を可視化。 こんな感じで見れる。 アプリはここにあります https://demo-lit-app.herokuapp.com/ コードはこっち https://github.com/iusami/demo-streamlit-heroku 未解決の話 cache機能があるのでそれでplot部分を高速化できないかなと思ったが、エラーが出て上手く動作しなかった。 ページの遷移を行うために_SessionStateを使ってるので単純にはキャッシュできないっぽい。 データをコンテナに込めてしまっているが、ほんとはどこかからダウンロードするようにしたい。(データサーバを用意するのがめんどくさかった。) 今後やってみたいこと 機械学習使ったインタラクティブなアプリを作れそう。パラメータ変更、学習、推論までおそらく全部実装できる。 参考文献 https://docs.streamlit.io/en/stable/index.html https://discuss.streamlit.io/t/streamlit-deployment-guide-wiki/5099 https://github.com/ash2shukla/streamlit-heroku
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python | range() vs np.arange()

range(start, stop[, step]) -> range object >>> range(0,5) range(0, 5) >>> c = [i for i in range(0,5,2)] >>> c [0, 2, 4] arange([start,] stop[, step,], dtype=None) -> ndarray >>> np.arange(3,7,2) array([3, 5])
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

tf-idfの計算結果が合わない...scikit-learnはどのようにtf-idfを計算しているか

はじめに Speech and Language Processingの第6章で説明されるtf-idf scikit-learnのTfidfVectorizer の計算結果が合わず、その原因を探りました。 目次 使用するデータ tf-idfの計算方法の確認 tf (term frequency) idf (inverse document frequency) tf-idf scikit-learnで計算 scikit-learnでの実装 参考 使用するデータ 東京外国語大学言語モジュールのベトナム語の例文から簡単な文を5つ使用します。 Tôi là sinh viên. Tôi là người Nhật. Chị có phải là người Việt không? Vâng, tôi là người Việt. Không, tôi không phải là người Việt. 今回は、記号(.,?)をなくし、すべて小文字にし、半角スペースで区切ったものを「単語」とします。 (実際は "sinh viên = 生徒" など、半角スペースを区切りにすると実際の単語がバラバラになってしまいますが、今回は無視します。) [['tôi', 'là', 'sinh', 'viên'], ['tôi', 'là', 'người', 'nhật'], ['chị', 'có', 'phải', 'là', 'người', 'việt', 'không'], ['vâng', 'tôi', 'là', 'người', 'việt'], ['không', 'tôi', 'không', 'phải', 'là', 'người', 'việt']] 以降、以下の3単語に注目してtf-idfを計算していきます。 là:5文すべてに出てくる chị:全体で1回しか出てこない không:5番目の文に2回出てくる tf-idfの計算方法の確認 Speech and Language Processingの第6章のP.11-13の説明を簡単にまとめ、今回のデータを計算します。 tf (term frequency) document(d)内での単語(t)の出現回数を数えたものです。 今回で言えば、documentは文に相当します。 tf_{t,d} = count(t,d) 多くの場合、対数を取ってから使用します。 その際、$\log_{10} 0$とならないように1を足します。 tf_{t,d} = \log_{10} (count(t,d) + 1) もしくは、$count(t,d)$が0かどうかで場合分けします。 tf_{t,d} = \begin{cases} 1 + \log_{10} count(t,d) & if\ count(t,d) > 0 \\ 0 & otherwise \end{cases} 今回のデータで2つ目の式を計算すると、以下のようになります。 ($d1$は1番目の文を表します。) \begin{align} tf_{là,d1} & = \log_{10} (count(là,d1) + 1) = \log_{10} (1 + 1) \approx 0.301 \\ tf_{chị,d3} & = \log_{10} (count(chị,d3) + 1) = \log_{10} (1 + 1) \approx 0.301 \\ tf_{không,d5} & = \log_{10} (count(không,d5) + 1) = \log_{10} (2 + 1) \approx 0.477 \end{align} idf (inverse document frequency) まず、df (document frequency)は、単語(t)が出現するdocument数を数えたものです。 今回のデータでは以下のようになります。 \begin{align} df_{là} & = 5 \\ df_{chị} & = 1 \\ df_{không} & = 2 \end{align} idf (inverse document frequency)は、全体のducument数をdfで割ったものです。 よって、document固有の単語に対して値がより大きくなります。 idf_{t} = \frac{N_{document}}{df_{t}} こちらも、多くの場合$N_{document}$が大きくなるため、対数を取って使用します。 idf_{t} = \log_{10} \frac{N_{document}}{df_{t}} 今回のデータでは以下のようになります。 \begin{align} idf_{là} & = \log_{10} \frac{5}{5} = \log_{10} 1 = 0 \\ idf_{chị} & = \log_{10} \frac{5}{1} = \log_{10} 5 \approx 0.700 \\ idf_{không} & = \log_{10} \frac{5}{2} = \log_{10} 2.5 \approx 0.398 \end{align} tf-idf tf-idfで重みづけされた値(w)は以下の式で求められます。 w_{t,d} = tf_{t,d} \times idf_{t} 今回のデータでは以下のようになります。 \begin{align} w_{là,d1} & = tf_{là,d1} \times idf_{là} = 0.301 \times 0 = 0 \\ w_{chị,d3} & = tf_{chị,d3} \times idf_{chị} = 0.301 \times 0.700 \approx 0.211 \\ w_{không,d5} & = tf_{không,d5} \times idf_{không} = 0.477 \times 0.398 \approx 0.190 \end{align} 計算結果から、以下のことが分かります。 すべての文に出現するlàは0になった 1つの文にしか出現しないchịは、idfが大きくなるため値が最大になった khôngは5番目の文に2度出現するが、3番目の文にも現れるため、結局値が抑制された scikit-learnで計算 同じことを、scikit-learnのTfidfVectorizerを用いて行います。 from sklearn.feature_extraction.text import TfidfVectorizer corpus = [ 'Tôi là sinh viên.', 'Tôi là người Nhật.', 'Chị có phải là người Việt không?', 'Vâng, tôi là người Việt.', 'Không, tôi không phải là người Việt.', ] tfidf = TfidfVectorizer() result = tfidf.fit_transform(corpus).toarray() vocab = tfidf.get_feature_names() print(f'là: {result[1-1][vocab.index("là")]:.3f}') print(f'chị: {result[3-1][vocab.index("chị")]:.3f}') print(f'không: {result[5-1][vocab.index("không")]:.3f}') là: 0.299 chị: 0.483 không: 0.755 あれ、結果が全然違う...? scikit-learnでの実装 scikit-learnのTfidfVectorizerにおいて、今回気になる引数を調べた結果が以下の通りです。 引数 型・値 デフォルト 説明 lowercase bool True tokenize前にlowercaseにするかを指定する。 token_pattern str r'(?u)\b\w\w+\b' tokenize時の正規表現を指定する。(デフォルトは2文字以上のアルファベット) norm {'l1', 'l2'} 'l2' tf-idfの結果をnormalizeする方法を指定する。'l1': documentごとにL1ノルムで割る'l2': documentごとにL2ノルムで割るFalse/None/0: 何もしない use_idf bool True tfにidfを掛けるかを指定する。True: $tf_{t,d} \times idf_{t}$False: $tf_{t,d}$ smooth_idf bool True idfを計算方法を指定する。True: $\log_{e} (\frac{N_{document} + 1}{df_{t} + 1}) + 1$False: $\log_{e} (\frac{N_{document}}{df_{t}}) + 1$ sublinear_tf bool False tfの計算方法を指定する。True: $1 + \log_{e} count(t,d)$False: $count(t,d)$ 以上より、TfidfVectorizerのデフォルトでの計算式は以下の通りになることが分かりました。 (vocabは全単語のユニークな集合を表します。) \begin{align} w_{t,d} & = l2\_normalize_{d}(tf_{t,d} \times idf_{t}) \\ & = \frac{tf_{t,d} \times idf_{t}}{\sqrt{\sum_{v \in vocab} (tf_{v,d} \times idf_{v})^{2}}} \\ tf_{t,d} \times idf_{t} & = count(t,d) \times (\log_{e} (\frac{N_{document} + 1}{df_{t} + 1}) + 1) \end{align} これをもとに、もう一度値の計算を行います。 \begin{align} w_{là,d1} & = l2\_normalize_{d1} (1 \times (\log_{e} (\frac{5 + 1}{5 + 1}) + 1)) \\ & = \frac{1 \times 1}{3.347...} \approx 0.299 \\ w_{chị,d3} & = l2\_normalize_{d3} (1 \times (\log_{e} (\frac{5 + 1}{1 + 1}) + 1))\\ & = \frac{1 \times 2.098...}{4.349...} \approx 0.483 \\ w_{không,d5} & = l2\_normalize_{d5} (2 \times (\log_{e} (\frac{5 + 1}{2 + 1}) + 1)) \\ & = \frac{2 \times 1.693...}{4.483...} \approx 0.755 \end{align} 解決! 参考 sklearn.feature_extraction.text.TfidfVectorizer TfidfVectorizerのソースコード document frequencyの計算箇所 inverse document frequencyの計算箇所
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

tf-idfの計算結果が合わない

はじめに Speech and Language Processingの第6章で説明されるtf-idf scikit-learnのTfidfVectorizer の計算結果が合わず、その原因を探りました。 目次 使用するデータ tf-idfの計算方法の確認 tf (term frequency) idf (inverse document frequency) tf-idf scikit-learnで計算 scikit-learnでの実装 参考 使用するデータ 東京外国語大学言語モジュールのベトナム語の例文から簡単な文を5つ使用します。 Tôi là sinh viên. Tôi là người Nhật. Chị có phải là người Việt không? Vâng, tôi là người Việt. Không, tôi không phải là người Việt. 今回は、記号(.,?)をなくし、すべて小文字にし、半角スペースで区切ったものを「単語」とします。 (実際は "sinh viên = 生徒" など、半角スペースを区切りにすると実際の単語がバラバラになってしまいますが、今回は無視します。) [['tôi', 'là', 'sinh', 'viên'], ['tôi', 'là', 'người', 'nhật'], ['chị', 'có', 'phải', 'là', 'người', 'việt', 'không'], ['vâng', 'tôi', 'là', 'người', 'việt'], ['không', 'tôi', 'không', 'phải', 'là', 'người', 'việt']] 以降、以下の3単語に注目してtf-idfを計算していきます。 là:5文すべてに出てくる chị:全体で1回しか出てこない không:5番目の文で2回出てくる tf-idfの計算方法の確認 Speech and Language Processingの第6章のP.11-13の説明を簡単にまとめ、今回のデータで計算します。 tf (term frequency) document(d)内での単語(t)の出現回数を数えたものです。 今回で言えば、documentは文に相当します。 tf_{t,d} = count(t,d) 多くの場合、対数を取ってから使用します。 その際、$\log_{10} 0$とならないように1を足します。 tf_{t,d} = \log_{10} (count(t,d) + 1) もしくは、$count(t,d)$が0かどうかで場合分けします。 tf_{t,d} = \begin{cases} 1 + \log_{10} count(t,d) & if\ count(t,d) > 0 \\ 0 & otherwise \end{cases} 今回のデータで2つ目の式を計算すると、以下のようになります。 ($d1$は1番目の文を表します。) \begin{align} tf_{là,d1} & = \log_{10} (count(là,d1) + 1) = \log_{10} (1 + 1) \approx 0.301 \\ tf_{chị,d3} & = \log_{10} (count(chị,d3) + 1) = \log_{10} (1 + 1) \approx 0.301 \\ tf_{không,d5} & = \log_{10} (count(không,d5) + 1) = \log_{10} (2 + 1) \approx 0.477 \end{align} idf (inverse document frequency) まず、df (document frequency)は、単語(t)が出現するdocument数を数えたものです。 今回のデータでは以下のようになります。 \begin{align} df_{là} & = 5 \\ df_{chị} & = 1 \\ df_{không} & = 2 \end{align} idf (inverse document frequency)は、全体のducument数をdfで割ったものです。 よって、document固有の単語に対して値がより大きくなります。 idf_{t} = \frac{N_{document}}{df_{t}} こちらも、多くの場合$N_{document}$が大きくなるため、対数を取って使用します。 idf_{t} = \log_{10} \frac{N_{document}}{df_{t}} 今回のデータでは以下のようになります。 \begin{align} idf_{là} & = \log_{10} \frac{5}{5} = \log_{10} 1 = 0 \\ idf_{chị} & = \log_{10} \frac{5}{1} = \log_{10} 5 \approx 0.700 \\ idf_{không} & = \log_{10} \frac{5}{2} = \log_{10} 2.5 \approx 0.398 \end{align} tf-idf tf-idfで重みづけされた値(w)は以下の式で求められます。 w_{t,d} = tf_{t,d} \times idf_{t} 今回のデータでは以下のようになります。 \begin{align} w_{là,d1} & = tf_{là,d1} \times idf_{là} = 0.301 \times 0 = 0 \\ w_{chị,d3} & = tf_{chị,d3} \times idf_{chị} = 0.301 \times 0.700 \approx 0.211 \\ w_{không,d5} & = tf_{không,d5} \times idf_{không} = 0.477 \times 0.398 \approx 0.190 \end{align} 計算結果から、以下のことが分かります。 すべての文に出現するlàは0になった 1つの文にしか出現しないchịは、idfが大きくなるため値が最大になった khôngは5番目の文に2度出現するが、3番目の文にも現れるため、結局値が抑制された scikit-learnで計算 同じことを、scikit-learnのTfidfVectorizerを用いて行います。 from sklearn.feature_extraction.text import TfidfVectorizer corpus = [ 'Tôi là sinh viên.', 'Tôi là người Nhật.', 'Chị có phải là người Việt không?', 'Vâng, tôi là người Việt.', 'Không, tôi không phải là người Việt.', ] tfidf = TfidfVectorizer() result = tfidf.fit_transform(corpus).toarray() vocab = tfidf.get_feature_names() print(f'là: {result[1-1][vocab.index("là")]:.3f}') print(f'chị: {result[3-1][vocab.index("chị")]:.3f}') print(f'không: {result[5-1][vocab.index("không")]:.3f}') là: 0.299 chị: 0.483 không: 0.755 あれ、結果が全然違う...? scikit-learnでの実装 scikit-learnのTfidfVectorizerにおいて、今回気になる引数を調べた結果が以下の通りです。 引数 型・値 デフォルト 説明 lowercase bool True tokenize前にlowercaseにするかを指定する。 token_pattern str r'(?u)\b\w\w+\b' tokenize時の正規表現を指定する。(デフォルトは2文字以上のアルファベット) norm {'l1', 'l2'} 'l2' tf-idfの結果をnormalizeする方法を指定する。'l1': documentごとにL1ノルムで割る'l2': documentごとにL2ノルムで割るFalse/None/0: 何もしない use_idf bool True tfにidfを掛けるかを指定する。True: $tf_{t,d} \times idf_{t}$False: $tf_{t,d}$ smooth_idf bool True idfを計算方法を指定する。True: $\log_{e} (\frac{N_{document} + 1}{df_{t} + 1}) + 1$False: $\log_{e} (\frac{N_{document}}{df_{t}}) + 1$ sublinear_tf bool False tfの計算方法を指定する。True: $1 + \log_{e} count(t,d)$False: $count(t,d)$ 以上より、TfidfVectorizerのデフォルトでの計算式は以下の通りになることが分かりました。 (vocabは全単語のユニークな集合を表します。) \begin{align} w_{t,d} & = l2\_normalize_{d}(tf_{t,d} \times idf_{t}) \\ & = \frac{tf_{t,d} \times idf_{t}}{\sqrt{\sum_{v \in vocab} (tf_{v,d} \times idf_{v})^{2}}} \\ tf_{t,d} \times idf_{t} & = count(t,d) \times (\log_{e} (\frac{N_{document} + 1}{df_{t} + 1}) + 1) \end{align} これをもとに、もう一度値の計算を行います。 \begin{align} w_{là,d1} & = l2\_normalize_{d1} (1 \times (\log_{e} (\frac{5 + 1}{5 + 1}) + 1)) \\ & = \frac{1 \times 1}{3.347...} \approx 0.299 \\ w_{chị,d3} & = l2\_normalize_{d3} (1 \times (\log_{e} (\frac{5 + 1}{1 + 1}) + 1))\\ & = \frac{1 \times 2.098...}{4.349...} \approx 0.483 \\ w_{không,d5} & = l2\_normalize_{d5} (2 \times (\log_{e} (\frac{5 + 1}{2 + 1}) + 1)) \\ & = \frac{2 \times 1.693...}{4.483...} \approx 0.755 \end{align} 計算結果が合ったので、これで解決! 参考 sklearn.feature_extraction.text.TfidfVectorizer TfidfVectorizerのソースコード document frequencyの計算箇所 inverse document frequencyの計算箇所
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【QNAP】QNAPのNASにPython環境を構築

はじめに 自宅でQNAPを使用しているのですが、勉強がてらPythonを常時動かす環境が欲しいと思い構築してみました。 備忘録として記事を残します。 確認環境 QNAP:TS-230 ファーム:4.5.3 手順 ①QNAP側でPythonをインストールする  App Centerより、Pythonをインストール  ※おそらくApp CenterでインストールしなくてもPython2系は使用できる可能性あり  (この確認を行った際はApp CenterでPython3系をインストールした後だったので未確認) ②QNAP側でSSH接続を許可する  コントロールパネル→ネットワークとファイルサービス→Telnet/SSHより、「SSH接続を許可する」をチェック ③SSH接続ソフトでQNAPに接続する  TeraTerm等の任意のソフトで接続する ④接続後、以下のメニューが出てくるので、「Q」を押下する +-------------------------------------------------------------------------+ | Console Management - Main menu | | | | 1: Show network settings | | 2: System event logs | | 3: Reset to factory default (password required) | | 4: Activate/ deactivate a license | | 5: App management | | 6: Reboot in Rescue mode (w/o configured disk) | | 7: Reboot in Maintenance Mode | | Q: Quit (return to normal shell environment) | | | +-------------------------------------------------------------------------+ さらに確認してくるので「Y」を押下する +-------------------------------------------------------------------------+ | Main > Quit | | | | Are you sure you want to exit the console menu and return to normal | | shell environment? (Y/N) | | | +-------------------------------------------------------------------------+ ⑥インストールされているPythonバージョンの確認コマンドを実行し、インストールされていることを確認する Python2系 python --version Python3系 python3 --version 最後に 実際にスクリプトを動かす際は以下のページを参考にしてください。 TS-220のcronでPythonスクリプトを実行 参考にしたサイト QNAPのNASにPython3/numpy/pandas環境を構築する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AtCoder Beginner Contest 178 C問題

AtCoderを始めましたが、ABCのA・B問題はほぼ解ける、C問題は運が良ければ解けるというレベルです。 まずはC問題を難なく解けるというの目標に、まずは過去問のC問題までをどんどんやっていってます。 自力では解けなかった問題を、解説を見て、理解した内容の整理とその結果のコードを書いていきたいと思います。 問題 長さ N の整数の列 A_1,A_2,…,A_N であって以下の条件をすべて満たすものはいくつありますか。 ・0 < A_i < 9 ・A_i=0 なる i が存在する。 ・A_i=9 なる i が存在する。 ただし、答えはとても大きくなる可能性があるので、10^9+7 で割った余りを出力してください。 解けなかった原因 総当たりでは、計算量がかかりすぎるがので、それ以外の方法が必要 解説を見て理解した内容 包除原理を適用して計算する 長さNの整列の組み合わせは、10のN乗 i=0が存在しない組み合わせは、9のN乗 i=9が存在しない組み合わせは、9のN乗 i=0とi=9両方が存在しない組み合わせは、8のN乗 10のN乗(1) - 9のN乗(2) - 10のN乗(3) + 8のN乗(4) で組合せ数が求まる ACしたコード N = int(input().strip()) print( (10**N - 9**N - 9**N +8**N) % (10**9+7) )
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ビットコイン関連ツイートをネガポジ判定して投資家心理を可視化する

ビットコインなどについて、人々がどのように思っているのかをツイートから可視化したいと思います。 やりたいこと Twitter APIからビットコイン関連ツイートを取得 ツイートを形態素解析して、ネガポジ判定 Word Cloudで可視化 画像をツイート ライブラリ import pandas as pd from pandas import DataFrame import json from janome.tokenizer import Tokenizer from requests_oauthlib import OAuth1Session from wordcloud import WordCloud import emoji import re import csv Twitter APIからビットコイン関連ツイートを取得 Twitter APIの利用方法については、参考サイトなどを参照ください。 関数search_wordのwordに検索したい単語、countに取得するツイート数を指定して(APIのデータ取得回数には制限があるので注意)、該当ツイートを取得します。 下記プログラムでは、jsonファイルに保存したキーを読み込んでいます。 keysfile = 'keys.json' signature = '#TweetFromPython' ##################### Twitter API ##################### def create_oauth_session(oauth_key_dict): oauth = OAuth1Session( oauth_key_dict['consumer_key'], oauth_key_dict['consumer_secret'], oauth_key_dict['access_token'], oauth_key_dict['access_token_secret'] ) return oauth def search_tweet(search_word, count, oauth): url = 'https://api.twitter.com/1.1/search/tweets.json' params = { 'q': search_word, 'count' : count, 'result_type' : 'recent', 'exclude': 'retweets', 'lang' : 'ja' } responce = oauth.get(url, params=params) if responce.status_code != 200: print("Error code: %d" %(responce.status_code)) return None tweets = json.loads(responce.text) return tweets #### キーを取得 keys = json.load(open(keysfile)) twitter = create_oauth_session(keys) search_word = 'ビットコイン' search_count = 200 search = search_tweet(search_word, search_count, twitter) # 検索結果 df_search = DataFrame.from_dict(search['statuses']) # DataFrameに変換 tweets = df_search['text'].tolist() # textカラムがツイート文 ツイートを形態素解析 形態素解析のための前処理として、絵文字やURLを除去します。 emoji.UNICODE_EMOJIはアップデートされて、言語情報も含まれるようになったので、'en'を指定しています。(以前は、emoji.UNICODE_EMOJIだけで大丈夫でした) URLは正規表現を使って除去しています。 このままだと、ツイッター特有の文字(#、@など)が含まれますが、後のWordCloudでは1文字のアルファベットや記号は無視されるようなので、ここではスルーします。 関数get_wakachiでは、必要な単語だけ分かち書き(単語の間にスペース)に変換します。まず、必要な品詞の単語か識別して、無意味な単語を除外します。さらに、今回は、検索ワード自体も必要ないので除去します。 # 絵文字除去 def remove_emoji(text): return ''.join(c for c in text if c not in emoji.UNICODE_EMOJI['en']) # URL除去 def remove_url(text): return re.sub(r'https?://[\w/:%#\$&\?\(\)~\.=\+\-]+', '', text) # 形態素解析のための前処理 def normalize_tweets(tweets): normalized = [] for tweet in tweets: text = tweet text = remove_emoji(text) text = remove_url(text) normalized.append(text) return normalized # 必要な単語だけ分かち書きに変換 def get_wakachi(list_text, word, hinshi=['名詞', '形容詞']): remove_words = ['こと', 'よう', 'そう', 'これ', 'それ', 'もの', 'ここ', 'さん', 'ちゃん', 'ところ', 'とこ', 'の', 'ん', word] # 無意味な単語と検索ワードのリスト t = Tokenizer() wakachi = '' for text in list_text: malist = t.tokenize(text) for w in malist: word = w.surface part = w.part_of_speech hit = False for h in hinshi: hit = hit or (h in part) if not hit: continue if word not in remove_words: wakachi += word + ' ' return wakachi tweets = normalize_tweets(tweets) # 形態素解析のための前処理 wakachi = get_wakachi(tweets, search_word) # 分かち書きに変換 Word Cloudでネガポジを可視化 分かち書きの文字列を使ってWordCloudで可視化しますが、このままだと、単語の意味に関係なく色が付きます。そこで、単語をネガポジ判定して、ネガティブとポジティブで色分けしてみたいと思います。 ネガポジ判定 日本語評価極性辞書をダウンロードして、この辞書から単語のネガポジ判定をします。この辞書には単語とそのネガポジ(ポジティブ=p、ネガティブ=n、どちらでもない=e)が格納されています。 ダウンロード ! curl http://www.cl.ecei.tohoku.ac.jp/resources/sent_lex/pn.csv.m3.120408.trim > pn.csv WordCloudには、自作の色を返す関数を設定できるので、get_pn_color関数の中でネガポジ判定して色を決めます。単語が辞書に含まれていなければ、e。含まれていれば、その判定結果を返し、判定結果によって色を決めています。色は、ポジティブ=青、ネガティブ=赤、どちらでもない=緑としています。 word_cloudはWordCloudを作成して保存する関数で、wordsに分かち書きを、image_fileに保存するファイル名を、numに表示する頻出単語の最大数を指定しています。 # Initialize Negative-Positive Dictionary pn_dic = {} fp = open('pn.csv', 'rt', encoding='utf-8') # ネガポジ辞書を読み込む reader = csv.reader(fp, delimiter='\t') for i, row in enumerate(reader): # Pythonの辞書型に変換 name = row[0] result = row[1] pn_dic[name] = result # 色を返す関数 def get_pn_color(word, font_size, **kwargs): r, g, b = 0, 0, 0 pn = 'e' if word in pn_dic: pn = pn_dic[word] if pn == 'p': b = 255 elif pn == 'n': r = 255 else: g = 255 return (r, g, b) # Word Cloud def word_cloud(words, image_file, num, font_path='C:/Windows/Fonts/MSGOTHIC.TTC'): #日本語フォントを指定 wordcloud = WordCloud( background_color='white', color_func=get_pn_color, max_words=num, font_path=font_path, width=800, height=400).generate(words) wordcloud.to_file(image_file) return True image_file = 'word_cloud.jpg' trend_num = 100 word_cloud(wakachi, image_file, trend_num) 画像をツイート 最後に、保存した画像をツイートします。 def tweet_image(oauth, text, image_file): url_media = "https://upload.twitter.com/1.1/media/upload.json" url_text = "https://api.twitter.com/1.1/statuses/update.json" files = {"media" : open(image_file, 'rb')} req_media = oauth.post(url_media, files = files) if req_media.status_code != 200: print ('media upload failed: %s', req_media.text) exit() media_id = json.loads(req_media.text)['media_id'] print ("Media ID: %d" % media_id) params = {'status': text + '\n' + signature, 'media_ids': [media_id]} req = oauth.post(url_text, params) if req.status_code == 200: print('tweet succeed!') else: print('tweet failed') # ツイート文 tweet_text = 'search word: {}\nsearch tweets num: {}\ntrend words num: {}'.format(search_word, search_count, trend_num) # ツイート tweet_image(twitter, tweet_text, image_file) 利益や暴落などの単語が正しく色分けされていることがわかります。これで、ビットコイン関連ツイートのネガポジを可視化することができました。 課題 ネガポジの辞書に含まれない単語が多いため全体的に緑になっていまっています。ガチホなどの特有の単語は別でネガポジ辞書を用意した方がいいです。また、暴騰はネガティブですし、コインがポジティブ、取引がネガティブに分類されているのも紛らわしいかもしれません。 今回の検索ワード「ビットコイン」は、「ビット」と「コイン」に単語が分けられているので、WordCloudに出てきてしまっています。 APIにデータ取得の上限があるので、大量のツイートから可視化するのは難しいかもしれません。 まとめ ビットコイン関連ツイートをネガポジ判定して可視化することで、投資家心理の一部を見ることができました。 参考サイト Twitter API Word Cloud 形態素解析 ネガポジ判定
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Symbolブロックチェーンで複数人が同時に送金するトランザクションをPythonで作成する

今回はSymbolのアグリゲートトランザクションを利用して、複数人が同時に送金するトランザクションを作成してみます。 前半はブロックチェーン外で署名を集めてからネットワークにアナウンスするオフライン署名の方法を紹介します。 前回のこの記事を先にお読みください。 起案者アカウント準備 alice from binascii import unhexlify from symbolchain.core.CryptoTypes import PrivateKey from symbolchain.core.sym.KeyPair import KeyPair from symbolchain.core.facade.SymFacade import SymFacade facade = SymFacade('public_test') b = unhexlify("896E43895B908AF5847ECCB2645543751D94BD87E71058B003417FED5123****") alicePrikey = PrivateKey(b) aliceKeypair = KeyPair(alicePrikey) alicePubkey = aliceKeypair.public_key aliceAddress = facade.network.public_key_to_address(alicePubkey) str(aliceAddress) トランザクションの起案者となるAliceアカウントを秘密鍵から作成します。 連署アカウント準備 bob bobPrikey = PrivateKey.random() bobKeypair = SymFacade.KeyPair(bobPrikey) strBobPubkey = str(bobKeypair.public_key) strBobAddress = str(facade.network.public_key_to_address(bobKeypair.public_key)) トランザクションを連署するアカウントBobを新規に作成します。AliceがBobの秘密鍵を知ることはできません。周知された公開鍵とアドレス(strBobPubkey,strBobAddress)を使って、Aliceはトランザクションを組み立てます。 トランザクション作成 alice from symbolchain.core.CryptoTypes import PublicKey bobPubkey = PublicKey(unhexlify(strBobPubkey)) bobAddress = SymFacade.Address(strBobAddress) msg = 'test' bobTx = facade.transaction_factory.create_embedded({ 'type': 'transfer', 'signer_public_key': bobPubkey, 'recipient_address': aliceAddress, 'message': bytes(1) + msg.encode('utf8') }) aliceTx = facade.transaction_factory.create_embedded({ 'type': 'transfer', 'signer_public_key': alicePubkey, 'recipient_address': bobAddress, 'message': bytes(1) + msg.encode('utf8') }) from symbolchain.core.sym.MerkleHashBuilder import MerkleHashBuilder from symbolchain.core.CryptoTypes import Hash256 import sha3 hash_builder = MerkleHashBuilder() hash_builder.update(Hash256(sha3.sha3_256(aliceTx.serialize()).digest())) hash_builder.update(Hash256(sha3.sha3_256(bobTx.serialize()).digest())) merkle_hash = hash_builder.final() import datetime deadline = (int((datetime.datetime.today() + datetime.timedelta(hours=2)).timestamp()) - 1616694977) * 1000 aggregate = facade.transaction_factory.create({ 'type': 'aggregateComplete', 'signer_public_key': alicePubkey, 'fee': 1000000, 'deadline': deadline, 'transactions_hash': merkle_hash, 'transactions': [aliceTx,bobTx] }) signature = facade.sign_transaction(aliceKeypair, aggregate) aggregate.signature = signature.bytes from binascii import hexlify hash = facade.hash_transaction(aggregate).bytes hexlifiedHash = hexlify(hash) print(hexlifiedHash) 起案者のAliceがトランザクションを作成します。ネットワーク手数料はAliceが全て支払います。 Aliceの署名が必要なaliceTxとBobの署名が必要なbobTxの2種類を集約させ、署名します。その後、トランザクションをハッシュ値(hexlifiedHash)をBobに通知し署名をオフラインで促します。 連署者署名 bob hexlifiedSignedHash = str(bobKeypair.sign(unhexlify(hexlifiedHash))) print(hexlifiedSignedHash) 連署者Bobはトランザクションではなく、トランザクションハッシュに対して署名を行います。 署名結果(hexlifiedSignedHash)をAliceにオフライン(ネットワーク外)で返送します。 署名結合とネットワークへのアナウンス alice cosignature = (0, bobPubkey.bytes, unhexlify(hexlifiedSignedHash)) aggregate.cosignatures.append(cosignature) from binascii import hexlify payload = {"payload": hexlify(aggregate.serialize()).decode('utf8').upper()} import json json = json.dumps(payload) headers = {'Content-type': 'application/json'} import http.client conn = http.client.HTTPConnection("sym-test-01.opening-line.jp",3000) conn.request("PUT", "/transactions", json,headers) response = conn.getresponse() print(response.status, response.reason) Bobから署名を受け取ったAliceはトランザクションに連署を組み込み、ネットワークへアナウンスします。 確認 hash = facade.hash_transaction(aggregate) print('https://sym-test-01.opening-line.jp:3001/transactionStatus/' + str(hash)) 以上です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Djangoをつかってウェブに字を表示させる

プロジェクトの立ち上げ https://qiita.com/on97-nakamatsu-mayumi/items/e01f6653bc0b347e3716 アプリ追加 https://qiita.com/on97-nakamatsu-mayumi/items/afda1e6b9fe72c5551e6 の方法は上記 python、Django初心者の勉強用メモです ウェブページの追加方法 1.templatesフォルダにウェブページのhtmlファイルを追加 2.views.pyにhtmlをユーザーに返す「ビュー」を追加 3.urls.pyでビューとURLを結びつける まず、websitのフォルダーの中にtemplatesフォルダをつくる そして、その中に「index.html」のファイルを作成 index.htmlの中に記述 そしてviews.pyにhtmlをユーザーに返す「ビュー」を追加 最初に書いてある中身は全部けして 以下のように記述 そして、今度はurls.pyでビューとURLを結びつける urls.pyのファイルが無い場合は、アプリの下に作成 そしてプロジェクトにあるurls.pyの中身をコピーしてはりつける 貼り付けた一番上の行は不要なので削除 そして以下のように記述 3行目の方は、さっき記述したviewsファイルの中のIndexView, classを呼び出し 6行目は ''はトップページ という意味 ''にアクセスしたらIndexViewを表示する という意味 これでアプリ自体は完成だが、最後にプロジェクト自体にもこのurlを教えないといけないので プロジェクトのurls.pyに記述 17行目に ,include 22行目に、トップページにアクセスしたらwebsite.urlsに飛べと命令してます。 サーバー立ち上げてみたらエラーがでたので以下の部分を修正 そしてサーバーたちあげて トップページアクセス なんとか表示できました!! 初めてやりましたが何とか表示できました〜!! よかったぁ〜!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Jupyterで作業効率化】英文をピリオドで改行し行番号を付与する【Google翻訳活用効率化】

目次 背景 必要なライブラリのインストール コード 使い方 実行例 背景 自己学習のために英語論文を読もうと思っても英語の壁に阻まれている方が多いかと思います。(かくいう私もそうです。) Google翻訳を活用しようと思っても改行が正しくされていないと中々上手く翻訳されません。 正規表現を使って置換しようとしても結構面倒くさいです。 また、翻訳の精度が上がってきたとはいえ、時々怪ししい日本語訳があります。 この場合、多くの方は英文と見比べているかと思いますが、長い文章の場合、英文と日本語訳の対応付けに時間がかかります。 そこで、英文をピリオドで改行し行番号を付与するツールを作成してみました。 必要なライブラリのインストール Jupyter notebookで実行してみるのが一番手っ取り早いかと思います。 pip install jupyterlab pip install pyperclip コード ''' 必要に応じてメンテしてください。 ''' import pyperclip import os def to_1_line_of_text(_str): ''' 不要な文字コードを削除して1行のテキストに変換する ''' _str = _str.replace(os.linesep, " ") _str = _str.replace("\x02", "") _str = _str.replace("\r", "") _str = _str.replace(" ", " ") return _str def new_line(_str): ''' 改行の対象となる文字列を探して改行する 対象:ピリオド、中黒 ''' _str = _str.replace(".", "." + os.linesep) _str = _str.replace("•", os.linesep + "•") return _str def adjust(_str): ''' 綺麗にする ''' # 行頭の空白を削除 _str = _str.replace(os.linesep + " ", os.linesep) # 空白行を削除 _str = _str.replace(os.linesep + os.linesep, os.linesep) # 本来改行されたくない文字を戻す # "e.g." _str = _str.replace("e." + os.linesep + "g." + os.linesep, "e.g.") return _str def add_line_numer(_str, _start_number): ''' 行番号を付与する _start_number: 開始番号 ''' _str2clip = "" i = _start_number for txt in _str.split(os.linesep): i += 1 if len(txt) > 0: _str2clip += str(i) + ":" + txt + os.linesep return _str2clip # クリップボードの値を取得 clip_str = pyperclip.paste() # 加工 str2clip = to_1_line_of_text(clip_str) str2clip = new_line(str2clip) str2clip = adjust(str2clip) str2clip = add_line_numer(str2clip, 0) # クリップボードにコピー pyperclip.copy(str2clip) print("== 元テキスト ==") print(clip_str) print("== 加工後テキスト ==") print(str2clip) 使い方 コピー&ペーストの途中で本コードを実行します。 論文などから英文テキストをコピー(ctrl+C) Jupyter notebookなどを使用してコードを実行(コード内でクリップボードに勝手にコピーされます) Google翻訳などにペースト(ctrl+V) 実行例 A Survey on Data Collection for Machine Learning: a Big Data - AI Integration PerspectiveのAbstractをコピーしてJupyter notebookで実行してみます。 実行結果は下記のようになります。"."(ピリオド)で改行され、行番号が付与されているのが解ります。 == 元テキスト == Data collection is a major bottleneck in machine learning and an active research topic in multiple communities. There are largely two reasons data collection has recently become a critical issue. First, as machine learning is becoming more widely-used, we are seeing new applications that do not necessarily have enough labeled data. Second, unlike traditional machine learning, deep learning techniques automatically generate features, which saves feature engineering costs, but in return may require larger amounts of labeled data. Interestingly, recent research in data collection comes not only from the machine learning, natural language, and computer vision communities, but also from the data management community due to the importance of handling large amounts of data. In this survey, we perform a comprehensive study of data collection from a data management point of view. Data collection largely consists of data acquisition, data labeling, and improvement of existing data or models. We provide a research landscape of these operations, provide guidelines on which technique to use when, and identify interesting research challenges. The integration of machine learning and data management for data collection is part of a larger trend of Big data and Artificial Intelligence (AI) integration and opens many opportunities for new research. == 加工後テキスト == 1:Data collection is a major bottleneck in machine learning and an active research topic in multiple communities. 2:There are largely two reasons data collection has recently become a critical issue. 3:First, as machine learning is becoming more widely-used, we are seeing new applications that do not necessarily have enough labeled data. 4:Second, unlike traditional machine learning, deep learning techniques automatically generate features, which saves feature engineering costs, but in return may require larger amounts of labeled data. 5:Interestingly, recent research in data collection comes not only from the machine learning, natural language, and computer vision communities, but also from the data management community due to the importance of handling large amounts of data. 6:In this survey, we perform a comprehensive study of data collection from a data management point of view. 7:Data collection largely consists of data acquisition, data labeling, and improvement of existing data or models. 8:We provide a research landscape of these operations, provide guidelines on which technique to use when, and identify interesting research challenges. 9:The integration of machine learning and data management for data collection is part of a larger trend of Big data and Artificial Intelligence (AI) integration and opens many opportunities for new research. Google翻訳結果 元テキストと加工後テキストのGoogle翻訳結果です。 加工後テキストの方が日本語として解りやすいかと思います。 また、行番号が採番されているので元の英文の対応付けも簡単です。(実はこっちの方が重要だったり) データ収集は、機械学習の主要なボトルネックであり、複数のコミュニティで活発な研究トピックです。がある データ収集が最近重大な問題になっている主な2つの理由。まず、機械学習がより広く使用されるようになるにつれて、私たちは 必ずしも十分なラベル付きデータがない新しいアプリケーションが見られます。第二に、従来の機械学習とは異なり、深い 学習手法は自動的に機能を生成し、機能エンジニアリングのコストを節約しますが、その見返りとして、より多くの金額が必要になる場合があります ラベル付けされたデータの。興味深いことに、データ収集に関する最近の研究は、機械学習、自然言語、および コンピュータビジョンコミュニティだけでなく、大量のデータを処理することの重要性のためにデータ管理コミュニティからも。 この調査では、データ管理の観点からデータ収集の包括的な調査を行います。主にデータ収集 データの取得、データのラベル付け、および既存のデータまたはモデルの改善で構成されます。これらの研究風景を提供します 運用、いつ使用する手法に関するガイドラインを提供し、興味深い研究課題を特定します。の統合 データ収集のための機械学習とデータ管理は、ビッグデータと人工知能(AI)統合のより大きなトレンドの一部です そして新しい研究のための多くの機会を開きます。 1:データ収集は、機械学習の主要なボトルネックであり、複数のコミュニティで活発な研究トピックです。 2:データ収集が最近重大な問題になっている主な理由は2つあります。 3:まず、機械学習がより広く使用されるようになるにつれて、必ずしも十分なラベル付きデータがない新しいアプリケーションが見られます。 4:第2に、従来の機械学習とは異なり、深層学習手法は自動的に特徴を生成し、特徴エンジニアリングのコストを節約しますが、その見返りとして、大量のラベル付きデータが必要になる場合があります。 5:興味深いことに、データ収集に関する最近の研究は、機械学習、自然言語、コンピュータービジョンのコミュニティだけでなく、大量のデータを処理することの重要性から、データ管理のコミュニティからも得られています。 6:本調査では、データ管理の観点からデータ収集の総合的な調査を行います。 7:データ収集は、主にデータの取得、データのラベル付け、および既存のデータまたはモデルの改善で構成されます。 8:これらの操作の調査状況を提供し、いつどの手法を使用するかについてのガイドラインを提供し、興味深い調査の課題を特定します。 9:データ収集のための機械学習とデータ管理の統合は、ビッグデータと人工知能(AI)統合のより大きなトレンドの一部であり、新しい研究の多くの機会を開きます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Strategyパターン Python実装 メモ

Pythonとデザインパターンの学習記録。今回はStrategyパターンについてメモする。 Strategy パターンとは 「戦略」(アルゴリズムなど)の切り替えや追加を簡単に行うためのデザインパターン。 戦略処理を別クラスとして作成することで、戦略を変更したい場合に、利用する戦略クラスを変更するという方法で対応する。 メソッド中にアルゴリズムをべた書きするよりも柔軟でメンテナンスしやすい設計となる。 クラス図と用語 Strategy:特定の処理を抽象化したクラス(抽象戦略) ConcreteStrategy : 具体的な処理を行うクラス(具体戦略) Context:Strategyの利用者 サンプルプログラム ID生成処理を行うAPIに適用する。 クエリパラメータの有無でID生成用Strategyを切り替える。 ディレクトリ構成 Project │ app.py │ │ L_ api │ __init__.py │ ├─views │ sample.py │ __init__.py │ L_ strategy L_ IDgenerator.py L_ IDStrategy.py L_ __init__.py 実装 app.py from api import app if __name__ == '__main__': app.run() api/__init__.py from flask import Flask from .views.sample import sample_router def create_app(): app = Flask(__name__) app.register_blueprint(sample_router, url_prefix='/api') return app app = create_app() api/views/sample.py APIコントローラ from flask import Flask, Blueprint, request import json from .strategy.IDStrategy import IDStrategy from .strategy.IDStrategy import FixedIDStrategy, RandomIDStrategy from .strategy.IDgenerator import IDgenerator # Routing Settings sample_router = Blueprint('sample_router', __name__) app = Flask(__name__) @sample_router.route("/sample", methods=['GET']) def get(): query = request.args.get('q') id = "" # クエリパラメータ未指定の場合、固定のIDを取得する if query is not None: generator = IDgenerator(FixedIDStrategy()) id = generator.generateID() # クエリパラメータ指定ありの場合、ランダムのIDを取得する else: generator = IDgenerator(RandomIDStrategy()) id = generator.generateID() res_body = { "id": id } return json.loads(json.dumps(res_body)) api/views/strategy/IDStrategy.py Strategy:抽象、具体戦略(ランダム、固定ID生成)定義 import random # ID生成処理を抽象化したクラス(抽象戦略 Strategy) class IDStrategy: def generateID(self): raise 'Abstract Method Called' # ランダム生成したIDを返却するクラス(具体戦略 ConcreteStrategy) class RandomIDStrategy(IDStrategy): def generateID(self): chars = '0123456789abcdefghijklmnopqrstuvwxyz' return ''.join([random.choice(chars) for _ in range(16)]) # 固定IDを返却するクラス(具体戦略 ConcreteStrategy) class FixedIDStrategy(IDStrategy): def generateID(self): return '0123abcd4567efgh' api/views/strategy/IDgenerator.py Context:ID生成Strategyを呼び出す。 # コンテキスト(Context):ストラテジーの利用者 class IDgenerator: def __init__(self, IDStrategy): self.IDStrategy = IDStrategy def generateID(self): return self.IDStrategy.generateID() 動作確認 ランダムID生成戦略の呼び出し(クエリパラメータ指定なし) リクエスト GET /api/sample HTTP/1.1 Host: localhost:5000 レスポンス { "id": "1arh3j2jba8x2fix" } 固定ID生成戦略の呼び出し(クエリパラメータ指定あり) リクエスト GET /api/sample?q=test HTTP/1.1 Host: localhost:5000 レスポンス { "id": "0123abcd4567efgh" } 参考情報 Strategyパターン Pythonでデザインパターン Strategyパターン
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Djangoのアプリの追加の仕方

Djangoプロジェクトには最低1つのアプリが必要。これは、Django 特有の仕組み 1.英数字とアンダースコア(_)でアプリ名を決める (例: website) 2.python manage.py startapp website 3.django_website/settings.py を編集してwebsiteアプリを登録 アプリは、プロジェクト内の1つの機能だと思えばOK。 シンプルなプロジェクトではアプリ1つで大丈夫です。 自分で作ったアプリは毎回登録が必要。 以下みたいに追加、シングルでもダブルでもどっちでも良い。 今回は、シングルクォーテーション 1つのプロジェクトには複数のアプリを追加できます。 プロジェクトは全体設定以外ほとんど触りません! メインはアプリです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む