20211012のPythonに関する記事は24件です。

データ分析で株価

 序論 株価の分析を自分の手でしてみたいな思って、本プロダクトを作りました。普通に株価のチャートとどのくらい似たものができるのか、世間一般の株価分析ツールがどうなっているのか気にしながら作っていきたいと思います。 内容 流れ 具体的にどのようなことをやっていくかというと、 1.データを収集する   ・ライブラリ=Pandas_datareade pandas 2.データを整形する   ・sort、rest_index   ・Columnsを再命名 3.基本統計量を出してみる   ・describe()→(参考)   ・変化率   ・グラフ書いてみる   ・終値の変化   ・ボラティリティ 4。将来を予想してみる   ・prophet   ・グラフ →見方、拡大方法   ・グラフトレンド→これいらないな という流れで作っていきます。 (使用するライブラリ) ・mathplotlib→グラフを書く ・pandas,numpy→データ整形用 ・pystan→分析用 ・fbporphet→機械学習用 ・pandas_datareader→株価取得用 ・datetime→日付取得用 ・cross_validation→検証用 最初にインポートしていきましょう。 stock.py import matplotlib.pyplot as plt import pandas as pd import pystan from fbprophet import Prophet from pandas_datareader import data from datetime import datetime コードの詳細 ではコードの中身を書いていきます。 ①データを収集する stock.py plt.style.use('fivethirtyeight') start_date="2011-04-01" today=datetime.today().strftime("%Y-%m-%d") print(f'{start_date}から{today}までの株価を取得します') ticker_symbol = "GOOG"#取得したい株価のコー土 まず最初にここで、株価を所得する期間、所得する株の種類を指定します。 stock.py #データを所得する関数を定義 def getMyStock(stock=ticker_symbol,start=start_date,end=today): df=data.DataReader(stock,'stooq',start,end) # print(df) df.sort_index(inplace=True)#並べ替え df.reset_index(inplace=True)#インデックスリセット df2=df.rename(columns={'Date':'ds','Close':"y"}) return df2 my_stock=getMyStock() print(my_stock) ここでデータを所得する一連の流れを、一気にやるために関数(getMystock)を定義します。どのような処理をするのかというと、 まず、(2行目)の data.DataReader(stock,"stocq",start,end) ここでは、dataと名前をつけたpandas_datareaderをつかって株価を所得します。 参考→Pandas_datareader公式ドキュメント、Pandas_datareaderを使ってデータ所得を試してみる それから(3-6行目)で所得したデータを整形します。 df.sort_index(inplace=True)#並べ替え df.reset_index(inplace=True)#インデックスリセット df2=df.rename(columns={'Date':'ds','Close':"y"}) 株価は所得してきた時点で降順になんでいるので、sort 関数を使って、株価を昇順に並び替えます。 それから、並べ替えた時にインデックスも一緒に変わってしまうのでreset_indexでインデックスをリセットして連番をつけます。 最後に、 関数を定義したので、関数を実行して実行結果を変数my_stockに代入します。print(my_stock)でどういうデータが入っているか確認します。 stock.py my_stock=getMyStock() print(my_stock) 出力結果↓ ここまでで、指定した株の指定の期間の株価を取ってくることができました!簡単だね!ライブラリって便利ですね! ②統計量を出してみる 基本統計量 では株価のデータも取得できたので基本統計量を出してみましょう。基本統計量とは、平均値中央値などを指します。 (データ).describe() で出すことができるので↓のコードで出してみましょう! stock.py my_stock.describe() #基本統計量 出力結果↓ その他統計量、グラフ   ・変化率   ・グラフ書いてみる   ・終値の変化   ・ボラティリティ について出してみましょう。 stock.py daily_rate_change=(my_stock["y"].pct_change(1))#一日あたりの変化率 pct_change ボラティリティ print(daily_rate_change) print(f"変化率の標準偏差stdは、\n{daily_rate_change.std()}") pct_change()を使うこと、で一つ前のデータとの変化率をとることができます。 daily_rate_change=(my_stock["y"].pct_change(1))# ↑はmy_stockのy列(終値)の変化率を取って変数daily_rate_changeに代入しています。ちなみにdaily_rate_changeに入っているデータは株価の変動=ボラティリティと呼ばれます。 それから、daily_rate_changeで標準偏差を求めています。 変な”f"があるのは、fストリングスを使っているからです。fストリングスについて グラフ①終値の変動 では、日経225とかでよく見る株価変動みたいなあれ、あれについて今回所得したデータでグラフ書いてみましょう。簡単です。一行でおわります。 stock.py #グラフ my_stock["y"].plot()#終値の変化、 my.stockの列の名前がYの列をとりだして、それを描写しているコードになります。 my.stockのデータ型はPandasDataframeなので、データの取り出し方はこちらを参考にして下さい。 ここまでで、 ・株価の基本統計量 ・終値の一日あたりの変化率=株価のボラティリティ ・変化率の標準偏差=株価の変動の大きさ をだすことができました。 グラフ②(ボラティリティの視覚化) 次に、株価のボラティリティ(終値の一日あたりの変化率)もせっかく出したで、株価がどれぐらい変化しているか視覚化してみましょう! stock.py plt.figure(figsize=(18,8)) plt.plot(daily_rate_change.index,daily_rate_change,lw=2) plt.title("volatility") plt.xlabel(f"{ticker_symbol}_data",fontsize=16) plt.ylabel("Daily_volatility") plt.legend(loc="upper right",fontsize=16) plt.show() ③株価の未来を予測してみましょう! 株価の未来を予測するためには、機械学習を使います。 いま所得した株価のデータを機械学習モデルに学習させて、未来の株価を予測します。今回使用するのはFaceBook様が出しているProphetというモデルになります。 機械学習に詳しくなくても、このモデルを使えばある程度の予測はできるの初心者におすすめです。 stock.py model=Prophet() #モデルを作る model.fit(my_stock) #モデルに学習させる future = model.make_future_dataframe(periods=365,freq='d')#モデルに365日分のデータフレーム作らせて、、future変数に入れる forecast = model.predict(future)#予想させる まず1行目ではprophetというインスタンスを作成して、変数modelに入れます。は????インスタンス????となると思いますが、ここでは機械学習モデルを呼び出して、変数Modelに入れていると理解していれば大丈夫です。 2行目では、先程所得してきた株価(my_stock)をモデルに学習させています。 3行目では、これから予想する未来の株価を入れるためのデータフレーム(箱)を作ります。 最後に4行目では、学習したモデルが、さっき作成したデータフレーム(箱)分だけ、未来を予測し、その結果をforcastに代入しています。 では、予測した株価がどうなっているのかグラフを書いてみましょう。 stock.py model.plot(forecast) model.plot(forecast)#モデル全体をPLOT 出力結果↓ 結果は上のようになります。 黒点が実測値,青線の実線が予測値,そして薄い青の塗りつぶしが80%信頼区間1を示します。 見にくい2021以降のものを拡大して見てみましょう。 stock.py plt.xlim(future.ds.iloc[-365-30], future.ds.iloc[-1])#位置区間を取り出してプロット plt.xlabel('Date') plt.ylabel('Average') plt.xlimでx軸の区間を指定しています。 plt.xlim(始点、終点)という書き方で、future.ds.iloc[-365-30]というのは予測したデータが入っているfutureのds列のうしろから[-365-30(=-395)]日分のデータをとってきてという意味になります。 出力結果↓ 1期間だけ指定して、グラフを書くことができましたね! トレンドについて(ちょい難) ここから少し専門的な内容に入りますが、株価がどのような周期で動いているのか調べるために、トレンド分析をしてみましょう! Prophetのモデルには、自前でトレンド分析をしてくれるツールがあるので超うれしいです。 トレンド(周期性)というのは、アイス業界の季節トレンドが一番わかり易いです。寒い時期(10月から5月)は売上が下がって、暑い時期(6-9月)で売上が上がりますよね。株にもいろいろな業界があるので、株価のトレンド(周期)があります。 それでは調べてみましょう。 stock.py model.plot_components(forecast)#トレンド分析、周期性 出力結果↓ このような結果になります。 一番上の図が株価全期で見たトレンド、今回の場合だと2020年以降株価が上がり続けているトレンドがありますね。 二番目の図は、週のトレンドです。今回の場合は平日(MONDAYーFriday)の株価が下がり、週末は上がっているトレンドです。 三番目の図は月のトレンドです。どのように解釈できますか?8月が株上昇のピークで10月に下落が来るトレンドになります。 検証 最後にこの推計がどのぐらい合ってるか、検証値を出していきましょう。cross_validationを使うことで図ることができます。 stock.py from fbprophet.diagnostics import cross_validation df_cv = cross_validation(model, initial='730 days', period='180 days', horizon = '365 days') df_cv 検証に使うライブラリをまず最初にインポートします。 それからcroos_valiationを用いて予測値がどれぐらい、実際の値とずれる可能性があるか、上限と下限を出します。 initialは訓練期間の初期値、horizonは予測する期間を表します。そしてperiodで指定した日数分ずつ、学習期間が延ばすことをデータがなくなるまで繰り返すといおう意味です。 出力結果は次のようになります。 yは実際の値、yhatは予測値、yhat_upperは予測上限、yhat_lowerは予測下限です。予測の誤差がわかるようになります! 以上で推計は終わりになります! コード全体 コード全文になります。 stock.py import matplotlib.pyplot as plt import pandas as pd import pystan from fbprophet import Prophet from pandas_datareader import data from datetime import datetime #基本情報 ここで入力を変える plt.style.use('fivethirtyeight') start_date="2011-04-01" #end="2021-09-30" って終わる日を指定してもいいけど today=datetime.today().strftime("%Y-%m-%d") print(f'{start_date}から{today}までの株価を取得します') ticker_symbol = "GOOG"#取得したい株価のコー土 #データを所得する関数を定義 def getMyStock(stock=ticker_symbol,start=start_date,end=today): df=data.DataReader(stock,'stooq',start,end) # print(df) df.sort_index(inplace=True)#並べ替え df.reset_index(inplace=True)#インデックスリセット df2=df.rename(columns={'Date':'ds','Close':"y"}) return df2 my_stock=getMyStock() print(my_stock) my_stock.describe() #基本統計量 daily_rate_change=(my_stock["y"].pct_change(1))#一日あたりの変化率 pct_change ボラティリティ print(daily_rate_change) print(f"変化率の標準偏差stdは、\n{daily_rate_change.std()}") #グラフ my_stock["y"].plot()#終値の変化、PANDASの行の取り出し方 #ボラリティの視覚化 plt.figure(figsize=(18,8)) plt.plot(daily_rate_change.index,daily_rate_change,lw=2) plt.title("volatility") plt.xlabel(f"{ticker_symbol}_data",fontsize=16) plt.ylabel("Daily_volatility") plt.legend(loc="upper right",fontsize=16) plt.show() #未来の株価を予想してみる model=Prophet() #モデルを作る model.fit(my_stock) #モデルに学習させる future = model.make_future_dataframe(periods=365,freq='d')#モデルに365日分のデータフレーム作らせて、、future変数に入れる forecast = model.predict(future)#予想させる model.plot(forecast) model.plot(forecast)#モデル全体をPLOT plt.xlim(future.ds.iloc[-365-30], future.ds.iloc[-1])#位置区間を取り出してプロット plt.xlabel('Date') plt.ylabel('Average') model.plot_components(forecast)#トレンド分析、周期性 from fbprophet.diagnostics import cross_validation df_cv = cross_validation(model, initial='730 days', period='180 days', horizon = '365 days') # initialは訓練期間の初期値、horizonは予測する期間を表します。そしてperiodで指定した日数分ずつ、学習期間が延ばすことをデータがなくなるまで繰り返します。 df_cv 感想 最初の初期値だけ変えれば、いろんな株のデータを分析することができます。また、データを株価からGDPや人口などの経済指標に変えることでレポートや卒論にも使えるなと思いました。 参考文献 ・pythonでGAFAの株価を分析してみよう! ・機械学習 株価分析 ・pythonで需要予測がしたい人がはじめに見る動画 ・pythonで株価分析 ・matplotlibのめっちゃまとめ ・相関性、相関係数とは?株価のデータをpythonで考察してみた ・【Python入門】datetimeで日付や時刻を扱う方法を解説! 作成 geeksalon たかぱん
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【2021.10.12】学び日記_Python

今日のインプット 合計:150分 - 通勤時にProgate(往復80分) - 風呂でPython入門の動画視聴(20分) - キノコードさんの動画 - 寝る前にProgate(50分) 学んだこと Pytyonの基本構造が「順次実行」「条件分岐」「繰り返し」であること Progateで何となく全てやってきていたが、基本構造として認識できていなかった やはり色んなルートで学習すると色んな角度でインプットできていいと思った Python等のプログラミング言語はエディターを通して使うことを知った 環境を色々整えて初めてまともに使える ソースコードの保存とかファイル分けとかどうやるんだろうと思っていたけど、何となく見えた 「for 変数名 in 辞書:」というfor文(繰り返し処理)   for fruit_key in fruits:     print(fruit_key + 'は' + fruits[fruit_key] + 'です') 変数名(furit_key:慣例では単数形)が先で、辞書名が後(fruits:関連では複数形) 要素を出力する際は辞書名[変数名]という書き方で、[変数名]を削除して実行してみたらエラーになった 「:」をを忘れない for文は慣れるしかない While文(繰り返し処理)  x = 1  while x <= 100:   print(x)   x += 1 無限ループにならないように気を付ける printの後、if文で条件を指定して、インデントしてbreakで止める手段もある if文で指定した条件を、インデントしてcontinueでスキップして、printする手段もある if文の復習(条件分岐)  if x == 60:    print('xは60です')  elif x<60 and x>20 :    print('xは20より大きく60より小さいです')  elif x<20 :    print('xは20より小さいです')  else :    print('xは60より大きいです') →エクセルのif関数にそっくりで覚えやすかった →「:」の使い方が分かった気がする。 →構文の中の処理を書くとき、字下げする時に「:」が必要、というルールなのではないか 疑問として残っていること ・繰り返し処理がどういう場面で使われているのか、普段使ってるツール等に当てはめて知りたい ・リストや辞書は、実務でも rist = [abc, def, ghq]のような書き方で使われているのか?  →DBと連携させたりしている? 1日の感想 もっとコード書いて慣れたい!! PC環境での勉強と通勤時のアプリでの勉強、予習復習みたいになって丁度いい 今日も充実した時間を過ごせた これまで修了したコース Progate Python 1 Progate SQL 1~4 Progate HTML&CSS 初級編
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【プログラミング勉強_開始1日目】学びの共有_Python

学んだことの共有 Pytyonの基本構造が「順次実行」「条件分岐」「繰り返し」であること Progateで何となく全てやってきていたが、基本構造として認識できていなかった やはり色んなルートで学習すると色んな角度でインプットできていいと思った Python等のプログラミング言語はエディターを通して使うことを知った 環境を色々整えて初めてまともに使える ソースコードの保存とかファイル分けとかどうやるんだろうと思っていたけど、何となく見えた 「for 変数名 in 辞書:」というfor文(繰り返し処理)   for fruit_key in fruits:     print(fruit_key + 'は' + fruits[fruit_key] + 'です') 変数名(furit_key:慣例では単数形)が先で、辞書名が後(fruits:関連では複数形) 要素を出力する際は辞書名[変数名]という書き方で、[変数名]を削除して実行してみたらエラーになった 「:」をを忘れない for文は慣れるしかない While文(繰り返し処理)  x = 1  while x <= 100:   print(x)   x += 1 無限ループにならないように気を付ける printの後、if文で条件を指定して、インデントしてbreakで止める手段もある if文で指定した条件を、インデントしてcontinueでスキップして、printする手段もある if文の復習(条件分岐)  if x == 60:    print('xは60です')  elif x<60 and x>20 :    print('xは20より大きく60より小さいです')  elif x<20 :    print('xは20より小さいです')  else :    print('xは60より大きいです') →エクセルのif関数にそっくりで覚えやすかった →「:」の使い方が分かった気がする。 →構文の中の処理を書くとき、字下げする時に「:」が必要、というルールなのではないか 疑問として残っていること ・繰り返し処理がどういう場面で使われているのか、普段使ってるツール等に当てはめて知りたい ・リストや辞書は、実務でも rist = [abc, def, ghq]のような書き方で使われているのか?  →DBと連携させたりしている? 今日のインプット方法 通勤時にProgate(往復80分) 風呂でPython入門の動画視聴(20分) - キノコードさんの動画 寝る前にProgate(50分) 合計:150分 これまで修了したコース Progate Python 1 Progate SQL 1~4 Progate HTML&CSS 初級編
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Educational Codeforces Round 115 B. Groups

題意 あなたは異なる曜日(月曜から金曜の5日間)の2日に授業をすることにします。 $2n$人の生徒がいます。それぞれの生徒は授業を受けられる日を1, 出られない日を0としてスケジュールを全員が提出しました。 あなたは各授業がn人ぴったりであるように授業のクラスを分けたいです。 各生徒は2つ授業両方には参加できません。 こう考えた 総当たりをします。各曜日を総当たりするには、 for i in range(5): for j in range(i+1, 5): # i と jの2つの曜日を選んだ とすればよいです。 さて、i,jを定めたとき、以下を求めることができます。 numboth: iもjも出席できるの学生 numi: iだけに参加できる学生 numj: jだけに参加できる学生 numng: 両方参加できない学生 この時、次のように順に考えます。 まず、合計の人数が$2n$で$n$人に分けたいのだから$numng$が1人以上いる場合、NGです。(絶対にn人に満たない授業ができてしまいます。) numiかnumjがnをよりも多い場合NGです。(もう片方の授業はn人未満になります) それ以外の場合、絶対に成立します。$numi+numj+numboth = 2n$なので、$numi + x = n$となる$0 \leq x \leq n$は必ず存在し、$numj + (numboth - x) = n$は明らかです。 この処理をすべてのi,jに対して行い、1つでもOKならYESです。すべてのi,jについて成り立たないならNOです。 実装 def do(): n = int(input()) // 2 dat = [] for i in range(2*n): dat.append(list(map(int, input().split()))) for i in range(5): for j in range(i+1, 5): cani = canj = canboth = canno = 0 for ind in range(2*n): if dat[ind][i] == dat[ind][j] == 1: canboth += 1 elif dat[ind][i] == 1: cani += 1 elif dat[ind][j] == 1: canj += 1 else: canno += 1 if canno > 0: continue if cani > n or canj > n: continue print("YES") return print("NO") q = int(input()) for _ in range(q): do()
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pythonで"""を実行しました。

公式サイトを探しています。 オリジナル """について Qiitaだと、薄い青色でした。(上記より) pycharmだと、ソースコード内で薄い緑色でした。 live.sympyだと """素敵。 """ Matrix([[3, 8], [15, 24]]) """ live.sympyでpprintを実行してみました。 >>> pprint(Matrix([[3, 8], [15, 24]])) ... [3 8 ] [ ] [15 24] 以上、簡単にメモしました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VM(VirtualBOX+Vagrant)上でchalice localを動かす

業務でchaliceを扱うことになりそうなので、動かせる環境を作ってみました。 バージョン ソフト バージョン VirtualBOX 6.1.222 Vagrant 2.2.16 VM構築 Vagrantfileに以下を指定してVM立ち上げ Vagrant.configure("2") do |config| config.vm.box = "centos/7" config.vm.network "private_network", ip: "192.168.33.10" config.vm.network :forwarded_port, guest: 8000, host: 8000 end ※chalice localのデフォルトポートが8000なので、ポートフォワーディングしておきます  IP指定(192.168.33.10:8000)でアクセスできまが、これ追記しておくとlocalhost:8000でアクセスできるようになります $ vagrant up VM内 準備 python3.8のインストール chaliceのインストール 参考:https://aws.github.io/chalice/quickstart.html 記事執筆時のバージョン $ python3 --version Python 3.8.11 $ chalice --version chalice 1.26.0, python 3.8.11, linux 3.10.0-1160.42.2.el7.x86_64 chaliceプロジェクトの作成 $ chalice new-project helloworld $ cd helloworld chaliceプロジェクトのローカル起動 $ chalice local --host=0.0.0.0 Serving on http://0.0.0.0:8000 ※--host=0.0.0.0を指定します ホスト(Windows)側からブラウザでアクセス http://localhost:8000にアクセス こんな感じで値が返ってきました! ちなみに、存在しないパスにアクセスすると403が返ってくるみたいです
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC188 C - ABC Tournament を解いた

文章の通りやってみた。 abc188c.py N = int(input()) A = list(map(int, input().split())) dic = {} for i in range(2**N): dic[A[i]] = i+1 lis = A[:] if N == 1: print(dic[min(lis)]) exit() while True: nums = [] for i in range(0,len(lis)-1, 2): nums.append(max(lis[i], lis[i+1])) lis = nums if len(lis) == 2: break print(dic[min(lis)])
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】退屈な Zoom / Meet を自動退出するデスクトップアプリを開発してみた

はじめに 新型コロナウイルスの影響で、昨年度から学校・企業にオンライン授業・会議が普及し始めました。 感染リスクを減らせるというメリットがある一方、 「なかなか集中できず眠くなってしまう」 という意見も……。 私もずっと同じ悩みを抱えていたので、上手くオンライン講義をサボれる方法を模索していました。 そこで思い付いたのが、オンライン会議の「自動退出」です! 第1弾(設計~テスト実行) 第2弾(アプリ化・配布~使用上の注意) 【全人類待望】寝落ちが合法に!? オンライン授業を自動退出してくれるアプリを作ってみた - YouTube 【歓喜】ついに、Zoom / Meet 自動退出アプリを無料配布します!!Z世代にふさわしい最強のオンライン攻略法とは…!? - YouTube 私の大学では Google Meet を使用することが多いですが、Zoom を普段利用している人も多いと思うので、両方に対応できるアプリを開発しました。 「デスクトップアプリだけ使ってみたい!」という人は ダウンロードページ ( SkiMee【自動退出支援アプリ】) をご覧ください。 ローカル環境で動くアプリを開発するのにそれほど時間はかからなかったのですが、exe 化のステップで2ヵ月以上詰まってしまったので、注意点も合わせて記事にできればと思います。 0. UI を観察しながら作戦を練る 【ポイント】オンライン会議(授業)は、決まった時間に終わらない! そこで今回は、参加者数をリアルタイムで監視して自動退出するプログラミングを考えます。 「 Web サイトから特定の情報(参加者数)だけを抽出する」という目標を達成するために真っ先に思いつくのはスクレイピングです。 しかし、リアルタイム(3秒に1回くらい)で参加者数を知りたい場合にスクレイピングを用いると、相手サーバーに大きな負荷がかかってしまうため、別の安全な方法を用います。 画像認識によって、参加者数を画面上のアイコンから読み取り、退出時は退出ボタンの位置をスクリーンから見つけ出して、自動でマウスを操作させる作戦を立てました。 (以下、Google Meet の UI を例に説明しますが、Zoom でも基本的な原理は同じです。) 1. 参加者数アイコンの位置を探り、キャプチャする PyAutoGUI というライブラリの画像認識は、一言で言うと「ハンパない」です。 あらかじめ保存しておいた参加者数アイコンの画像から、その位置を探し出して座標を取得してくれるのです。 さらに、認識した「?」の位置から、その右肩にある数字の範囲だけのスクリーンショットを撮って保存します。 pip install pyautogui import pyautogui as gui import cv2 # pip install cv2 # 保存したアイコン画像の座標(位置と大きさ)を取得 # オプションのconfidenceは、画面上の画像の位置を特定する精度を指定 X,Y,W,H = gui.locateOnScreen('{参加者数アイコン画像のパス}', confidence=0.6) # アイコン右肩の数字の範囲を指定してスクリーンショットを撮る cropped_img = gui.screenshot(region=(X+W/2,Y-2*H/3,W,2*H/3)) # 撮ったスクリーンショットを保存する cropped_img.save('.\\sankasha.png') 【参考にしたサイト】 PyAutoGUIで画像認識(locateOnScreen)【Python】 | ジコログ Screenshot Functions — PyAutoGUI documentation 2. OCR で画像から参加者数を読み取る Python と Tesseract OCR を使用して参加者数アイコンから数字を読み取ります。 Tesseract OCR とは Google が公開したオープンソースの文字認識エンジンです。 ※ Tesseract OCR は Python のモジュールではないため、通常の pip コマンドではなく、以下のサイトに沿ってインストールしてください。 Python+Tesseractによる画像処理でOCRを試してみた! – 株式会社ライトコード また、Pythonで Tesseract OCRを扱うためには、PyOCR というライブラリを使用します。 pip install pyocr import pyocr # 保存した参加者数の画像をグレースケールで読み込み img = cv2.imread('.\\sankasha.png', cv2.IMREAD_GRAYSCALE) # グレースケール画像の二値化(閾値処理) ret, img_thresh = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) # print(f"ret:{ret}") # 画像の色反転 img2 = cv2.bitwise_not(img_thresh) # 参加者数の画像を上書き保存 cv2.imwrite('.\\sankasha.png', img2) # PyOCR へ利用する OCR エンジンを Tesseract に指定する tools = pyocr.get_available_tools() if len(tools) == 0: print("No OCR tool found") sys.exit(1) tool = tools[0] # print("Will use tool '%s'" % (tool.get_name())) # 画像から数字を読み取る(文字列型であることに注意) str_num = tool.image_to_string( Image.open('.\\sankasha.png'), lang='eng', builder = pyocr.builders.TextBuilder(tesseract_layout = 6) ) # 読み取った参加者数を整数型に変換して出力 print(int(str_num)) 3. リアルタイムでグラフに描画する ステップ2を継続的に実行することにより、リアルタイムで参加者数を得ることができます。 今回は、人数の変化を折れ線グラフで可視化して、見ていて楽しいアプリを作ることにしました。 Python で GUI アプリケーションを作れるライブラリとして、「Tkinter」「Kivy」「PyQt」「wxPython」などがよく紹介されます。 この中で、標準ライブラリである Tkinter を一度は使ってみましたが、 Tkinterを使うのであればPySimpleGUIを使ってみたらという話 - Qiita という記事にすごく影響されて、結局 PySimpleGUI でアプリを作りました。 pip install pysimplegui グラフの描画には Matplotlib という定番のライブラリを使いました。 詳しいコードは、「全体コード」の章をご覧ください。 4. 退出条件を満たしたらボタンを押す 再び、PyAutoGUI というライブラリを使って、画像認識を行います。 あらかじめ保存しておいた退出ボタンの画像から、その位置を探し出して中心座標を取得します。 ボタンの中心までマウスを移動させ、(Google Meet が最前面でない場合も考慮して)ダブルクリックをさせれば退出完了です。 # 自分で設定した退出条件を満たしたら以下のコードを実行する # 保存した退出ボタン画像の中心座標を取得 X,Y = gui.locateCenterOnScreen('{退出ボタン画像のパス}', confidence=0.9) # 指定したスクリーン上の位置までマウスカーソルを移動させる gui.moveTo(X,Y) # 指定した位置をダブルクリックする gui.doubleClick(X,Y) (Zoom の場合はミーティング退出ボタンが2段階あるため、2段階目は Enter キーを押させることによって実現します) 【参考にしたサイト】 【自動化】Pythonでマウスとキーボードを操る - Qiita 5. 配布用にアプリを exe 化する(沼りポイント) Python コードを exe ファイル(実行ファイル)に変換します。 これによって、Python がインストールされていない PC でもデスクトップアプリを実行することができます。 しかし私は、この exe 化のステップを達成するのに2ヵ月以上かかってしまいました…。 通常であれば Pyinstaller で以下のように実行するだけで、Python コードを exe ファイルに変換できます。 pip install pyinstaller pyinstaller main.py しかし、完成した exe ファイルを実行しても、次のようなエラーが無限に出てくるはずです。 Running from container, but no tessdata found ! これは Tesseract OCR が pip install ではないので、通常の exe 化だけではユーザー自身に Tesseract をインストールさせる必要があるためです。 ユーザーに迷惑をかけないように、以下のサイトを参考にして2つの変更を加えます。 ① 環境変数 PATH に Tesseract OCR のパスを通す 【参考】 pythonとOCRでyoutube広告自動スキップツール作成 - Qiita os.environ["PATH"] += os.pathsep + os.path.dirname(os.path.abspath(__file__)) + os.sep + '{<フォルダ名> Tesseract (ここにTesseract-OCRの中身を丸ごと入れる)}' ② 配布用フォルダ dist 内のディレクトリ構造を変更する 【参考】 pyocr を使っていて pyinstaller でパッケージングすると WARNING が出てくる件について - Qiita この記事の摩訶不思議なディレクトリ構造がなければ、一歩も前に進めなかったところですが、少しだけ補足説明を付け足しておきます。 変更後の配布用フォルダのディレクトリ構造 ├─build │ └─main ├─dist │ └─main │ ├─data │ │ ├─configs │ │ ├─script │ │ ├─tessconfigs │ │ └─tessdata │ │ ├─configs │ │ ├─script │ │ └─tessconfigs │ ├─Tesseract │ │ ├─data │ │ │ ├─configs │ │ │ ├─script │ │ │ ├─tessconfigs │ │ │ └─tessdata │ │ │ ├─configs │ │ │ ├─script │ │ │ └─tessconfigs │ │ ├─doc │ │ └─tessdata │ : │ └─__pycache__ 依然として複雑であることに変わりはないので、分からないことがあったら連絡してください。 全体コード main.py import PySimpleGUI as sg import cv2 import pyocr import datetime import numpy as np import pyautogui as gui import matplotlib.pyplot as plt from matplotlib.ticker import MultipleLocator from PIL import Image from time import sleep import io import os import sys # Tesseract のモジュールを格納するフォルダ RESORSES_FOLDER_NAME = 'Tesseract' # Tesseract-OCRのパスを環境変数「PATH」へ追記する os.environ["PATH"] += os.pathsep + os.path.dirname(os.path.abspath(__file__)) + os.sep + RESORSES_FOLDER_NAME def resource_path(relative_path): if hasattr(sys, '_MEIPASS'): return os.path.join(sys._MEIPASS, relative_path) return os.path.join(os.path.abspath("."), relative_path) def ocr_binarized_image(image_path, threshold=0, threshold_type=cv2.THRESH_BINARY): img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) ret, img_thresh = cv2.threshold(img, threshold, 255, threshold_type) # print(f"ret:{ret}") img2 = cv2.bitwise_not(img_thresh) thresh_path = image_path cv2.imwrite(thresh_path, img2) tools = pyocr.get_available_tools() if len(tools) == 0: print("No OCR tool found") sys.exit(1) tool = tools[0] # print("Will use tool '%s'" % (tool.get_name())) str_num = tool.image_to_string( Image.open(thresh_path), lang='eng', builder = pyocr.builders.TextBuilder(tesseract_layout = 6) ) return int(str_num) # ボタン押下により会議を退出する関数 def leave_meeting(image_path, app): X,Y = gui.locateCenterOnScreen(image_path, confidence=0.9) gui.moveTo(X,Y) if app == 'Google Meet': gui.doubleClick(X,Y) elif app == 'Zoom': gui.click(X,Y) gui.press('enter') x = [] y = [] exit_cnt = 0 max_num = 0 def make_data_fig(): global x,y fig = plt.figure() ax = fig.add_subplot(111) ax.set_xlabel('Time') ax.set_ylabel('Number of People') ax.yaxis.set_major_locator(MultipleLocator(1)) ax.grid(color='black', linestyle=':', linewidth=0.3, alpha=0.5) ax.set_title('Real-Time Line Graph') ax.plot(x, y, marker='.') return fig def draw_plot_image(fig): item = io.BytesIO() plt.savefig(item, format='png') plt.clf() return item.getvalue() def display_main(participant_path, exit_path, alpha, app, denominator, times): global x,y,max_num,exit_cnt layout = [[sg.Checkbox('グラフ表示',key='-display-', default=True)], [sg.Image(filename='', key='-image-')], [sg.Text('繰り返し間隔(s):', size=(20,1)), sg.Slider((0,10), default_value=0, orientation='h', key='-delay-')], [sg.Button('終了'), sg.Button('ホーム')], ] window = sg.Window('SkiMee 【 リアルタイムビュー 】', layout=layout, font='メイリオ', alpha_channel=alpha, icon=resource_path('SkiMee.ico')) while True: event, values = window.read(timeout=0) if event in (None, '終了'): break elif event == 'ホーム': window.close() return True try: X,Y,W,H = gui.locateOnScreen(participant_path, confidence=0.8) if app == 'Google Meet': cropped_img = gui.screenshot(region=(X+W/2,Y-2*H/3,W,2*H/3)) elif app == 'Zoom': cropped_img = gui.screenshot(region=(X+W,Y,2*W/3,4*H/5)) cropped_img.save('.\\sankasha.png') num = ocr_binarized_image('.\\sankasha.png',127,cv2.THRESH_BINARY) if num: if num < max_num/denominator: exit_cnt += 1 elif exit_cnt > 0: exit_cnt = 0 max_num = max(num, max_num) x.append(datetime.datetime.now()) y.append(num) except Exception as e: print(e) if values['-display-']: fig_ = make_data_fig() fig_bytes = draw_plot_image(fig_) window['-image-'].update(data=fig_bytes) else: window['-image-'].update(filename='') if exit_cnt >= times: exit_cnt = 0 leave_meeting(exit_path, app) break sleep(values['-delay-']) window.close() # ステップ2. デザインテーマの設定 sg.theme('BlueMono') # ステップ3. ウィンドウの部品とレイアウト layout = [ [sg.Text('※ Zoom / Google Meet の「参加者数アイコン」と「退出ボタン」のスクリーンショットを撮ってアップロードしてください。')], [sg.Text('▶ 使用するオンライン会議アプリを選択:'), sg.Combo(('Google Meet', 'Zoom'), default_value='Google Meet', key='-app-'), sg.Button('更新', key='-refresh-')], [sg.Text('Google Meet の場合は、スクリーンショット時に Chrome のズームを 200% にするのがオススメです。', key='-caution-')], [sg.Text('▼ アップロード画像(1) 参加者数アイコン'), sg.Text('※ ファイルパスに日本語を含まないようにしてください', text_color='#ff0000')], [sg.Image(filename=resource_path('406-203.png'), size=(406,203), key='-img1-')], [sg.Input(), sg.FileBrowse('ファイルを選択', key='inputFilePath1')], [sg.Text('▼ アップロード画像(2) 退出ボタン'), sg.Text('※ ファイルパスに日本語を含まないようにしてください', text_color='#ff0000')], [sg.Image(filename=resource_path('239-203.png'), size=(239,203), key='-img2-')], [sg.Input(), sg.FileBrowse('ファイルを選択', key='inputFilePath2')], [sg.Text('▶ ウィンドウ不透明度(0=非表示,1=完全に表示):'), sg.Slider((0.0,1.0), default_value=1.0, resolution=0.1, orientation='h', key='-alpha-')], [sg.Text('▶ 自動退出する条件を選択:'), sg.Text('最大参加人数の'), sg.Combo(('1/2未満 ','1/3未満 '), default_value='1/2未満 ', key='-denominator-'), sg.Text('が'), sg.Combo(('1回連続 ','2回連続 ','3回連続 '), default_value='2回連続 ', key='-times-')], [sg.Button('はじめる', key='-start-')], ] # ステップ4. ウィンドウの生成 window = sg.Window('SkiMee 【 自動退出支援プログラム 】', layout=layout, font='メイリオ', icon=resource_path('SkiMee.ico')) # ステップ5. イベントループ while True: event, values = window.read() if event == '-refresh-': if values['-app-'] == 'Zoom': window['-caution-'].update('Zoom の場合は、全画面表示にするのがオススメです。') window['-img1-'].update(filename=resource_path('591-203.png')) window['-img2-'].update(filename=resource_path('332-203.png')) elif values['-app-'] == 'Google Meet': window['-caution-'].update('Google Meet の場合は、スクリーンショット時に Chrome のズームを 200% にするのがオススメです。') window['-img1-'].update(filename=resource_path('406-203.png')) window['-img2-'].update(filename=resource_path('239-203.png')) if event == sg.WIN_CLOSED: break elif event == "-start-": denominator = 2 if values['-denominator-'].startswith('1/2') else 3 times = 2 if values['-times-'].startswith('2') else 3 window.Hide() # アップロード画面を隠す # メイン画面を表示する main_return = display_main(values['inputFilePath1'], values['inputFilePath2'], values['-alpha-'], values['-app-'], denominator, times) # もしNoneが返ってきたらアップロード画面も終了させる if main_return is None: break elif main_return == True: window.UnHide() # アップロード画面を再表示する window.close() main.spec main.spec # -*- mode: python ; coding: utf-8 -*- block_cipher = None a = Analysis(['main.py'], pathex=['{main.py があるフォルダまでのパス}'], binaries=[], datas=[], hiddenimports=[], hookspath=[], hooksconfig={}, runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False) a.datas += [('239-203.png', '.\\239-203.png', 'DATA'), ('406-203.png', '.\\406-203.png', 'DATA'), ('332-203.png', '.\\332-203.png', 'DATA'), ('591-203.png', '.\\591-203.png', 'DATA'), ('SkiMee.ico', '.\\SkiMee.ico', 'DATA') ] pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE(pyz, a.scripts, [], exclude_binaries=True, name='main', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, console=True, icon='SkiMee.ico', disable_windowed_traceback=False, target_arch=None, codesign_identity=None, entitlements_file=None ) coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, upx_exclude=[], name='main') おわりに 初めて Python & PySimpleGUI でデスクトップアプリを作り、主に Tesseract-OCR 絡みで多数のエラーに悩まされましたが、なんとかリリースすることができました。 先人たちの知恵をかき集めて作ったアプリなので、よければ使ってみてください!! この記事が少しでも誰かのお役に立てれば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DeepL API の使用方法

auth_key と text, source_lang, target_lang を指定して GET or POST するだけ 参考: https://www.deepl.com/docs-api/introduction/ シェルスクリプト deepl.sh #!/bin/sh DEEPL_API_URL="https://api-free.deepl.com/v2/translate" YOUR_API_KEY="__DEEPL_API_KEY_HERE__" SOURCE_TEXT=" I'm a lumberjack and I'm OK. I sleep at night, I work during the day. He's a lumberjack and he's OK. He sleeps all night and he works all day. I cut down trees, I eat my lunch. I go to the lavatory. On Wednesdays I go shopping and have buttered scones for tea. " curl -s ${DEEPL_API_URL} \ -d "auth_key=${YOUR_API_KEY}" \ -d "text=${SOURCE_TEXT}" \ -d "source_lang=EN" \ -d "target_lang=JA" \ | jq .translations[].text Python deepl.py import requests DEEPL_API_URL = 'https://api-free.deepl.com/v2/translate' YOUR_API_KEY = '__DEEPL_API_KEY_HERE__' SOURCE_TEXT = """ I'm a lumberjack and I'm OK. I sleep at night, I work during the day. He's a lumberjack and he's OK. He sleeps all night and he works all day. I cut down trees, I eat my lunch. I go to the lavatory. On Wednesdays I go shopping and have buttered scones for tea. """ params = { "auth_key": YOUR_API_KEY, "text": SOURCE_TEXT, "source_lang": 'EN', "target_lang": 'JA' } request = requests.post(DEEPL_API_URL, data=params) result = request.json() print(result["translations"][0]["text"]) Node.js deepl.js const request = require('request'); const deepl_api_url = 'https://api-free.deepl.com/v2/translate' const your_api_key = '__DEEPL_API_KEY_HERE__'; const source_text = ` I'm a lumberjack and I'm OK. I sleep at night, I work during the day. He's a lumberjack and he's OK. He sleeps all night and he works all day. I cut down trees, I eat my lunch. I go to the lavatory. On Wednesdays I go shopping and have buttered scones for tea. `; const params = { url: deepl_api_url, method: 'POST', headers: { 'content-type': 'application/x-www-form-urlencoded' }, form: { auth_key: your_api_key, text: source_text, source_lang: 'EN', target_lang: 'JA' }, json: true } request.post(params, function(error, response, result){ console.log(result.translations[0].text); }); PHP deepl.php <?php $deepl_api_url = 'https://api-free.deepl.com/v2/translate'; $your_api_key = '__DEEPL_API_KEY_HERE__'; $source_text = " I'm a lumberjack and I'm OK. I sleep at night, I work during the day. He's a lumberjack and he's OK. He sleeps all night and he works all day. I cut down trees, I eat my lunch. I go to the lavatory. On Wednesdays I go shopping and have buttered scones for tea. "; $header = [ 'Content-Type: application/x-www-form-urlencoded', ]; $content = [ 'auth_key' => $your_api_key, 'text' => $source_text, 'source_lang' => 'EN', 'target_lang' => 'JA', ]; $params = [ 'http' => [ 'method' => 'POST', 'header' => implode("\r\n", $header), 'content' => http_build_query($content, '', '&'), ] ]; $request = file_get_contents( $deepl_api_url, false, stream_context_create($params) ); $result = json_decode($request); echo $result->translations[0]->text; 実行結果 私は木こりですが、大丈夫ですよ。 夜は寝て、昼は働く。 彼は木こりであり、彼はOKだ。 彼は夜も寝るし、昼も働く。 木を切って、お昼を食べて。 お手洗いにも行く。 水曜日には買い物に行き、紅茶にバター入りのスコーンを食べる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

OOFの予測値でConfident Learning (cleanlab) を使おう!

はじめに Confident Learningという手法を使うことで、分類タスクにおける、データセットの中の間違ったラベル(noisy label)のサンプルを検出することができる。詳しい解説が既ににあり、Confident Learningを実行するライブラリにcleanlabというのものあるので、ここでは機械学習で後付でcleanlabを使う小技の紹介をする。 cleanlab cleanlabはConfident Learningを実行できるライブラリで、scikit-learn like APIのモデルクラスをラップして使うことができる。 from sklearn.base import BaseEstimator class YourFavoriteModel(BaseEstimator): # Inherits sklearn base classifier def __init__(self, ): pass def fit(self, X, y, sample_weight=None): pass def predict(self, X): pass def predict_proba(self, X): pass def score(self, X, y, sample_weight=None): pass # Now you can use your model with `cleanlab`. Here's one example: from cleanlab.classification import LearningWithNoisyLabels lnl = LearningWithNoisyLabels(clf=YourFavoriteModel()) lnl.fit(train_data, train_labels_with_errors) ただ、これをPyTorchで実装するのはメンドクサイ。。。こちらにサンプルコードがあるが、既に学習を回している人が後からサンプルのようにcleanlab用に書き換えるのはツライ。 しかし! cross validationをしている方ならOOF(Out Of Fold)でtrainデータの予測値(正確には各ラベルの確率)を出力していると思われる。このOOFの値y_oofさえあれば、cleanlabのデータクリーニング部分は実行できるので、小技として紹介しよう。 train data に対するラベルのOOF予測確率y_oofは得られているとする。まず次のクラスを作る。 from sklearn.base import BaseEstimator class CleanModel(BaseEstimator): # Inherits sklearn base classifier def __init__(self): pass def fit(self, X, y, sample_weight = None): pass def predict(self, X): pass def predict_proba(self, X): pass def score(self, X, y, sample_weight = None): pass 上で作ったクラスをラップして、fitを実行する。 # 確率に規格化できてない場合は規格化する psx = softmax(y_oof, axis=1) # モデルをラップする clf = LearningWithNoisyLabels( clf=CleanModel(), prune_method='prune_by_class' # ここは自由に選ぶ ) clf.fit( X=np.arange(len(train_df)), # データのid s=train_df[y].values, # クラスラベルの ndarray, shape (n_samples, ) psx=psx, noise_matrix=None, inverse_noise_matrix=None, ) noise_mask変数にノイズラベルと推測されるサンプルのインデックスが格納されています。 cleaned_train_df = train_df.iloc[~clf.noise_mask] あとはこの新しいデータで再学習を実行すればOKです。再学習は自身の既存コードで実行すればよいです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】 開始終了、pipインストールメモ

バージョン確認 バージョン確認 python --version こんなのが出てくる(バージョンによって変わる) 結果 Microsoft Windows [Version 10.0.19042.1237] (c) Microsoft Corporation. All rights reserved. C:\XXXX\XXXX>python --version Python 3.8.10 C:\XXXX\XXXX>python --version Python 3.8.1> pipからのインストール pipからのインストール py -m -3.9 pip install BeautifulSoup py -m pip install BeautifulSoup pipのアップグレード pipのアップグレード py -m pip install --upgrade pip 開始 python コマンド終了 コマンド終了 >>>exit() >>>quit()
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

自然言語処理API

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Python] __repr__メソッドをカスタマイズする

インスタンスのprint表示をカスタマイズしたい 自分でクラスを作る。 class Dummy(): def __init__(self, argument, *args, **kwargs): # インスタンス変数 self.argument = argument self.arg1 = args[0] def fit(self): pass def predict(self): pass これをprintすると、、 print(instance) # <__main__.Dummy object at 0x7ff7177d8990> ななな、なんじゃこら。 こんなふうに引数を表示したい。。。 from sklearn.ensemble import RandomForestClassifier clf = RandomForestClassifier(max_depth=2, random_state=0) print(clf) # RandomForestClassifier(bootstrap=True, ccp_alpha=0.0, class_weight=None, # criterion='gini', max_depth=2, max_features='auto', # max_leaf_nodes=None, max_samples=None, # min_impurity_decrease=0.0, min_impurity_split=None, # min_samples_leaf=1, min_samples_split=2, # min_weight_fraction_leaf=0.0, n_estimators=100, # n_jobs=None, oob_score=False, random_state=0, verbose=0, # warm_start=False) Scikit-learn likeのAPIをつくるなら、sklearn.baseの配下のクラス(base.ClassifierMixin、base.RegressorMixin等)を継承すればよいが、自分でカスタムしたいという人もおられるだろう。そんなときは、特殊メソッドの__repr__を書き換えれば良い。 __repr__はオブジェクトの公式な文字列表現である。公式には、この表現を見れば元のオブジェクトを再生成できるように表示すべし、と書いてある。まさにscikit-learnのようにすべしということである。 class State: _defaults = {"A": 1, "B": 2} def __init__(self, argument, *args, **kwargs): # インスタンス変数 self.argument = argument self.arg1 = args[0] # クラス変数 self.__dict__.update(self._defaults) # キーワード引数 self.__dict__.update(kwargs) def __repr__(self): kws = [f"{key}={value!r}" for key, value in self.__dict__.items()] return "{}({})".format(type(self).__name__, ", ".join(kws)) def __eq__(self, other): return self.__dict__ == other.__dict__ # you might want to add some type checking here instance1 = State('a', 'b') print(instance1) # State(argument='a', arg1='b', A=1, B=2) インスタンス変数ではないが、表示したいものはself.__dict__に辞書で登録する。 インスタンス変数に後から追加したものも表示される。 instance1.name = 'name' print(instance1) # State(argument='a', arg1='b', A=1, B=2, name='name') 上の例では__eq__メソッドも実装してあるので、インスタンスの比較は引数の比較になるぞ。 instance1 = State('a', 'b') instance2 = State('a', 'b') instance3 = State('c', 'd') print(instance1 == instance2) # True print(instance1 == instance3) # False 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AI・機械学習入門】初心者のためのPythonライブラリ紹介

はじめに Python の紹介に入っていきますが、まずは Python の機械学習でよく使用されるライブラリを身近なものに例えてみます。 紹介する例えは、私が主観的に思う身近なものに例えています。厳密には異なる部分がありますので、ご注意ください。 また、今回のコードの紹介は、インポートと簡単な使用例に留めます。 各ライブラリの詳細については、別途記事にする予定ですので、お待ちいただけますと幸いです。 本記事の対象となる方 プログラミング初心者 機械学習・DeepLearningといったAI実装を学習しはじめた方 numpy, pandas, matplotlib, seaborn, scikit-learnをこれから使用する方 環境 Google Colabratory (以下、Colab) ライブラリのインポートについて これから紹介するライブラリは、インポートしてから使用可能になります。 import <ライブラリ名> as <略語> このようにして、インポートは行います。 as <略語> の箇所は、インポート後にそのライブラリを短い名称で呼び出すためにつけます。 普段使いしている略語にも、ボールペン・食パン・教科書などがあります。 正式名称は、ボールポイントペン・主食用パン・教科用図書です。誰もこんな呼び方していないですよね。 ライブラリも同じで、よく使うものは略語を設定して使っているという感覚を持ってもらえると大丈夫です。 Colabは、各ライブラリのインストール済みの環境になるので、インストールについては説明していません。 ローカル環境や仮想環境で実行する際は、事前にインストールしてからインポートを行わないとインポートエラーとなりますので、ご注意ください。 Numpy Numpy は 数値計算 を行うライブラリです。 例えると、行列計算が可能な関数電卓のようなものです。 numpy # numpyのインポート import numpy as np # numpy のバージョン np.__version__ 1.19.5 numpy使用例 # x, y という配列を作成 x = np.array([1, 1]) y = np.random.rand(2, 2) # x, y の掛け算 z = np.dot(x, y) # x, y, z の表示 print(f'x = {x}') print(f'y = {y}') print(f'z = {z}') # 実行結果 x = [1 1] y = [[0.17101494 0.69612195] [0.7879925 0.60866322]] z = [0.95900745 1.30478517] Pandas Pandas は データフレーム という構造を使い データの解析 を行うライブラリです。 例えると、Excel のシート のようなものです。 pandas # pandasのインポート import pandas as pd # pandas のバージョン pd.__version__ 1.1.5 pandas使用例 # df というデータフレームを作成 df = pd.DataFrame(np.random.randn(4, 4), index=["1行", "2行", "3行", "4行"], columns=["1列", "2列", "3列", "4列"]) # df の表示 df # 実行結果 1列 2列 3列 4列 1行 0.453633 -0.730396 -1.200269 0.217617 2行 1.538881 0.213172 1.007157 -1.410174 3行 -1.020639 -0.474193 1.134175 -0.583397 4行 -0.345173 -0.007356 -0.778200 -0.738700 Matplotlib Matplotlib は グラフの描画など データ可視化 のためのライブラリです。 例えると、Excel のグラフ のようなものです。 matplotlib # matplotlibのインポート import matplotlib # matplotlib のバージョン matplotlib.__version__ 3.2.2 matplotlib の中にある、pyplot が図形の描画を行う機能をもつので、別途インポートします。 matplotlib.pyplot # matplotlib.pyplot のインポート import matplotlib.pyplot as plt matplotlib使用例 # 横軸(x軸):x = 0 ~ 10 まで 0.1 区切り x = np.arange(0, 10, 0.1) # 縦軸(y軸):s = sin(x) s = np.sin(x) # 縦軸(y軸):c = cos(x) c = np.cos(x) # x軸, y軸 を設定 plt.plot(x, s, "r", label="sin") plt.plot(x, c, "b", label="cos") # 凡例の表示 plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left', borderaxespad=0, fontsize=14) # グラフの描画 plt.show() 実行結果 Seaborn Seaborn は Matplotlib と同様に、データ可視化 のためのライブラリです。 散布図やヒストグラムの表示によく使用されます。 seaborn # seabornのインポート import seaborn as sns # seaborn のバージョン sns.__version__ 0.11.2 seaborn使用例 # data にcar_crashesのデータを取り込む data = sns.load_dataset("car_crashes") # グラフの描画 sns.pairplot(data) 実行結果 Scikit-learn Scikit-learn は 機械学習アルゴリズムと、サンプルデータセットが用意されている 機械学習 のためのライブラリです。 例えると、機械学習における工具箱 のようなものです。 scikit-learn # scikit-learnのdatasetsからload_bostonをインポート from sklearn.datasets import load_boston # datasetにload_bostonのデータを格納 dataset = load_boston() # x, tにdatasetのdata, targetを格納 x = dataset.data t = dataset.target # pandasのデータフレームにx, tを格納 (見やすくするため) df_x = pd.DataFrame(x, columns=dataset.feature_names) df_t = pd.DataFrame(t) 実行結果 # df_xの表示 df_x # 実行結果 CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LSTAT 0 0.00632 18.0 2.31 0.0 0.538 6.575 65.2 4.0900 1.0 296.0 15.3 396.90 4.98 1 0.02731 0.0 7.07 0.0 0.469 6.421 78.9 4.9671 2.0 242.0 17.8 396.90 9.14 2 0.02729 0.0 7.07 0.0 0.469 7.185 61.1 4.9671 2.0 242.0 17.8 392.83 4.03 3 0.03237 0.0 2.18 0.0 0.458 6.998 45.8 6.0622 3.0 222.0 18.7 394.63 2.94 4 0.06905 0.0 2.18 0.0 0.458 7.147 54.2 6.0622 3.0 222.0 18.7 396.90 5.33 ... ... ... ... ... ... ... ... ... ... ... ... ... ... 501 0.06263 0.0 11.93 0.0 0.573 6.593 69.1 2.4786 1.0 273.0 21.0 391.99 9.67 502 0.04527 0.0 11.93 0.0 0.573 6.120 76.7 2.2875 1.0 273.0 21.0 396.90 9.08 503 0.06076 0.0 11.93 0.0 0.573 6.976 91.0 2.1675 1.0 273.0 21.0 396.90 5.64 504 0.10959 0.0 11.93 0.0 0.573 6.794 89.3 2.3889 1.0 273.0 21.0 393.45 6.48 505 0.04741 0.0 11.93 0.0 0.573 6.030 80.8 2.5050 1.0 273.0 21.0 396.90 7.88 506 rows × 13 columns # df_yの表示 df_y # 実行結果 0 0 24.0 1 21.6 2 34.7 3 33.4 4 36.2 ... ... 501 22.4 502 20.6 503 23.9 504 22.0 505 11.9 506 rows × 1 columns さいごに ここまで読んでいただき誠にありがとうございます。 今回は Python のライブラリについて簡単に紹介してみました。 次回は Python の型について説明したいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC195 C - Comma を解いた

右から数えて 1 つ目のコンマ 右から数えて 2 つ目のコンマ 右から数えて 3 つ目のコンマ 右から数えて 4 つ目のコンマ 右から数えて 5 つ目のコンマ と分けてカウントしてみた。 abc195c.py N = int(input()) cnt = 0 if len(str(N))>3: cnt += N-999 if len(str(N))>6: cnt += N-999999 if len(str(N))>9: cnt += N-999999999 if len(str(N))>12: cnt += N-999999999999 if len(str(N))>15: cnt += N-999999999999999 print(cnt)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LightGBMのカスタムメトリック

カスタムメトリックの作り方 LightGBMのScikit-learn APIの場合のカスタムメトリックとして、4クラス分類のときのF1スコアを作ってみます。 (y_true, y_pred)を引数に持つ関数を作ればよいです。次のような関数になります。 from sklearn.metrics import f1_score def f1(y_true, y_pred): N_LABELS = 4 # ラベルの数 y_pred_ = y_pred.reshape(N_LABELS, len(y_pred) // N_LABELS).argmax(axis=0) score = f1_score(y_true, y_pred_, average='macro') return 'f1', score, True 返り値は、メトリックの名前、スコアの値、値が大きいほうが良いか否か、です。3つ目の返り値はEarly stoppingなどに使用されます。 また、他クラス分類のように予測が複数列を持つ場合は、y_predが1列で渡されるため、reshapeする必要があるのですが、並び替えの向きが行方向をラベルにする必要があるので気を付ける必要があります。 カスタムメトリックはeval_metricに渡してあげれば使用できます。 params= { 'objective': 'multiclass', 'num_class':4, 'learning_rate': .01, 'max_depth': 6, 'n_estimators': 1000, 'colsample_bytree': .7, 'importance_type': 'gain', } clf = lgb.LGBMClassifier(**params) clf.fit(X_train, y_train, eval_set=[(X_valid, y_valid)], early_stopping_rounds=100, eval_metric=f1, verbose=verbose) ## 出力 # Training until validation scores don't improve for 100 rounds # [100] valid_0's multi_logloss: 0.103872 valid_0's f1: 0.92157 # [200] valid_0's multi_logloss: 0.0416318 valid_0's f1: 0.971213 # ... カスタムメトリックはあくまで参考値で、objectiveのみvalidationに使いたい場合はparamsに'first_metric_only': Trueを追加します。 逆にvalidationをカスタムメトリックのみで行いたい場合は、paramsに"metric" : "None"を追加すればOKです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

a = (1 and 2 or 3 and 4)を説明できますか?

目的 pythonのand/or演算子を掘り下げておきたい。 題材 and/or演算子が複数含まれている文。a = 1 and 2 or 3 and 4 タイトルでは()をつけたがなくても一緒。※括る場所を変えると結果は変わる。 ポイントは右辺の演算結果は何者か?なぜそうなるか。 先走って結論 a = 2 と同等です。 ポイント TrueやFalse以外の変数だってand/or演算子の処理ができる。 and/or演算子は結果としてTrueやFalseを返さない。(演算子の左右にそれ自体がいれば話は別) and/or演算子は左右のどちらかを選ぶ処理。 同時に and/or (またはnot)が含まれるとき、優先順位がある。 解説 and/or演算子 if money >= 1000 or points >= 1200 こんな感じの条件分岐はよく見るでしょう。現金1000以上さもなくばポイント1200以上の場合は、って意図です。 現金なくてもお買い物ができそうなケースに使えるif文です。 次のケースでは、財布を忘れずに持ってきていれば現金が1000以上かという判定を行います。 wallet and money >= 1000 ここまでは文章でスルッと理解できると思います。 それでは、現実的ではないケースですが。財布を所持していなかったら? pythonでは、wallet and money >= 1000の答えとしてwalletが残ります。 結果、「財布を持ってないよ」という情報のみが残ることになります。 ということで、pythonのand/or演算子の挙動ですが、 * or演算子は左がTruthyの変数なら左を、さもなくば右をそのまま返す * and演算子は左がTruthyの変数なら右を、一方でFalsyなら左をそのまま返す となっています。直感的ではなくなってくる部分ですがこれがルールです。 or演算子が日本語っぽい理解もできるんですが、and演算子はそういう理解がしづらいです印象です。 補足ですが、 TruthyとはFalsyではない変数と覚えた方がいいです。 中身のある変数とか、Trueになれる変数とか、bool関数を通してTrueになるやつらとか言われます。 Falsyとは、数値なら0、文字列型なら文字数0の空文字、配列や辞書などでは要素数0の空の変数が該当します。 中身の存在しない変数などと言われることもあります。 複数のand/or演算子 さてタイトルの1 and 2 or 3 and 4ですが、先程のルールだけで愚直に左から順に読むと、 1 and 2 →2 2 or 3 →2 2 and 4 →4 という演算が行われそうですが、python上で実行してみると結果は2です。 【理由・大事なルール】andとorが並列されているときは andの処理が優先。(notがあればさらにnotが優先) ※カッコで括ることで演算の順番を変更することは可能です。 ということで、正しい処理の順番は 1 and 2 →2 3 and 4 →4 2 or 4 →2 となっています。 最後に ここが初〜中級者から先に進む時のpython引っ掛かりポイントとして有名な点だと思います。 間違ったこと書いてる記事も複数見かけたので正しい知識を広めたいとの思いも込めて記事書きました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC203 C - Friends and Travel costs

約半年前、難解な問題文だと嘆き、悶絶しながらコードを書いていたころが懐かし良い。 abc203c.py N,K = map(int,input().split()) #与えられる Ai,Bi は昇順になっていないケースがある #以下で並び替え lis = [] for i in range(N): a,b = map(int,input().split()) lis.append([a,b]) lis.sort() #ソートしたリストを小さい順から確認していく plot = 0 ans = 0 for a,b in lis: target,charge = a,b #目的時と現在地が同じ場合は K だけチャージ if target == plot: K += charge else: #目的地と現在地の差が K 以下なら #給油ポイントに辿り着ける if target-plot <= K: K =K-(target-plot)+charge plot = target #たどり着けなかったら break else: break #現在地の plot と残りの手持ち金額 K だけ進める print(plot+K)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

激重 pyinstaller バイナリを軽くする

はじめに pyinstaller、とても便利です。なにせ配布が楽ですから。 ただ、出来上がったバイナリが重すぎです。これを(場合によっては)さくっと解決するために、この記事を書きました。なお、本記事では Windows で Anaconda 環境の例になります。 例 まずは pyinstaller でそのままバイナリ(exe)を作ってみましょう。 $ pyinstaller hogefuga.py --onefile なんと 287MB ありました。 とても気軽に配布できそうもありません。 ちなみに、hogefuga.py では、以下が import されています。 import bs4 import openpyxl import shutil import sys 対処 次に、以下のように --exclude-module オプションに numpy を指定して実行してみます。 $ pyinstaller <hogefuga.py> --onefile --exclude-module numpy 出来上がったバイナリは、81.9MB あります。だいぶ減りましたが、あと一声ほしいところです。 次は、さらに pandas も除外してみます。 $ pyinstaller <hogefuga.py> --onefile --exclude-module numpy --exclude-module pandas 14.6MB のバイナリができました。これなら、そこまで気を使う大きさではないかと思います。 fogefuga.py と同ディレクトリに fogefuga.spec なるファイルができています。 このファイルを覗いてみると、excludes に numpy と pandas が設定されているのがわかりますね。 # -*- mode: python ; coding: utf-8 -*- block_cipher = None a = Analysis(['hogefuga.py'], pathex=['D:\\hogefuga'], binaries=[], datas=[], hiddenimports=[], hookspath=[], runtime_hooks=[], excludes=['numpy', 'pandas'], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False) pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE(pyz, a.scripts, a.binaries, a.zipfiles, a.datas, [], name='hogefuga', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, upx_exclude=[], runtime_tmpdir=None, console=True ) おわりに いかがでしょうか。せっかく便利にバイナリまでできたのに、ファイル容量が激重だったら残念ですよね。 仕事もファイルも少しでもスリム化できたら幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC206 C - Swappable から学んだ

うーん。分からんので回答を見た。 なるほど。NG を数えるか。 勉強になりました。 abc206c.py N = int(input()) A = list(map(int,input().split())) dic = {} for i in range(N): if A[i] not in dic: dic[A[i]] = 0 dic[A[i]] += 1 num = 0 for i in dic.keys(): if dic[i] > 1: num += ( dic[i]*(dic[i]-1) )//2 print( (N*(N-1))//2 - num )
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC208 C - Fair Candy Distribution を解いてみた

辞書を使うと簡単かも。 abc208c.py N,K = map(int,input().split()) A = list(map(int,input().split())) dic = {} for i in range(N): dic[A[i]] = K//N A_ = sorted(A) for i in range(K%N): dic[A_[i]] += 1 for key in dic.keys(): print(dic[key])
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC200 C - Ringo's Favorite Numbers 2 を解いた

まともに全探索するとO(N^2)となるので無理。 確か、倍数を問う問題は、 その倍数で割った余りの集合から共通項の組み合わせで求められる気がする。 書いてみた。 abc200c.py N = int(input()) A = list(map(int,input().split())) A_ = list(map(lambda x:x%200,A)) #print(A) #print(A_) from collections import Counter KEYs = list(set(A_)) lis = Counter(A_) score = 0 for key in KEYs: if lis[key] > 1: score += ( lis[key]*(lis[key]-1) )//2 print(score) counter じゃなくても 辞書でも同じアプローチが出来る。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【線形代数】行列の乗法(積) in Python

機械学習では線形代数がよく使われています。 その中で、自分が間違えたことある行列の乗法について話したいと思います。 1. アダマール積 (Hadamard product) また要素ごとの積 (element-wise product)と呼ばれています。 同じサイズの行列$A$と行列$B$のアダマール積は$A\odot B$と書きます。 A=\begin{bmatrix} 3&4\\ 5&6 \end{bmatrix}, B=\begin{bmatrix} 1&2 \\ 3&4 \end{bmatrix} A\odot B= \begin{bmatrix} 3*1&4*2 \\ 5*3&6*4 \end{bmatrix}= \begin{bmatrix} 3&8 \\ 15&24 \end{bmatrix} numpy import numpy as np A = np.array([[3, 4], [5, 6]]) B = np.array([[1, 2], [3, 4]]) print(A * B) """ [[ 3 8] [15 24]] """ pytorch import torch A_pt = torch.tensor([[3, 4], [5, 6]]) B_pt = torch.tensor([[1, 2], [3, 4]]) print((A_pt * B_pt)) """ tensor([[ 3, 8], [15, 24]]) """ 2. 通常の行列の積 (dot product) サイズ$n×m$の行列$A$とサイズ$m×k$の行列$B$を計算する時に 1. $A\cdot B$ 2. $\lt A, B\gt$ 3. $\sum_{i=1}^{n} a_ib_i$ などの書き方があります。 A=\begin{bmatrix} 3&4 \\ 5&6 \end{bmatrix}, B=\begin{bmatrix} 1&2 \\ 3&4 \end{bmatrix} A\cdot B= \begin{bmatrix} 3*1+4*3&3*2+4*4 \\ 5*1+6*3&5*2+6*4 \end{bmatrix}= \begin{bmatrix} 15&22 \\ 23&34 \end{bmatrix} numpy import numpy as np A = np.array([[3, 4], [5, 6]]) B = np.array([[1, 2], [3, 4]]) print(np.dot(A, B)) """ [[15 22] [23 34]] """ pytorch import torch A_pt = torch.tensor([[3, 4], [5, 6]]) B_pt = torch.tensor([[1, 2], [3, 4]]) # print(torch.mm(A_pt, B_pt))も一緒です print(torch.matmul(A_pt, B_pt)) """ tensor([[15, 22], [23, 34]]) """ 以上、簡単にメモしました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

BlenderのPythonスクリプトでプロポーショナル編集したい時

 需要があるのがないのかわからない Blender Python スクリプト講座。日本語の情報がなかったので。あと検索範囲が足りないのかもしれないけど、英語でも古い情報しかなかったような......。  こういうグリッドを、  こうしたいと考えます。ランダムに 10 個頂点を選択して、上に持ち上げて波打った地面のようにするという作業です。 頂点の編集(基本)  基本的には、bpy.dataから頂点を編集するのが王道です。以下のようなスクリプトを考えてみます。 import bpy import random obj = bpy.context.object msh_name = obj.to_mesh().name msh = bpy.data.meshes[msh_name] vts = msh.vertices size = len(vts) for i in range(10): idx = random.randint(0,size-1) vts[idx].co.z += 1  これは、  このような絵面が生み出されます。プロポーショナル編集にしていないから当たり前です。 プロポーショナル in オブジェクトモード  次に、オブジェクトモードでプロポーショナル編集を有効にしてみます。 obj = bpy.context.object msh_name = obj.to_mesh().name msh = bpy.data.meshes[msh_name] vts = msh.vertices vts_size = len(vts) bpy.context.tool_settings.use_proportional_edit_objects = True #追加 for i in range(10): idx = random.randint(0,vts_size-1) vts[idx].co.z += 1  プロポーショナル編集マークはアクティブになりますが変化なしです。実はこれは、オブジェクトの拡大とか回転とかをプロポーショナルに伝播させるための機能で、頂点編集とは関係ないのでした。 編集モード  やはり編集モードで頂点を編集する必要があります。以下のようなコードに修正します。 import bpy import bmesh import random bpy.ops.object.mode_set(mode='EDIT', toggle=False) obj = bpy.context.object meshdata = bmesh.from_edit_mesh(obj.data) verts = meshdata.verts size = len(verts) bpy.context.tool_settings.use_proportional_edit = True for i in range(10): idx = random.randint(0,vts_size-1) verts[idx].select_set(True) bpy.ops.transform.translate(value=(0,0,.5)) verts[idx].select_set(False)  !?  それでもプロポーショナル編集は反映されません。マークは有効になっているのに。 結論  tool_settingsの設定は全く関係なく、translateの引数の中にプロポーショナル編集を使うことを明示する必要があります。 import bpy import random import bmesh bpy.ops.object.mode_set(mode='EDIT', toggle=False) obj = bpy.context.object meshdata = bmesh.from_edit_mesh(obj.data) verts = meshdata.verts size = len(verts) # bpy.context.tool_settings.use_proportional_edit = True #全くの無意味 for i in range(10): idx = random.randint(0,vts_size-1) verts[idx].select_set(True) bpy.ops.transform.translate(value=(0,0,.5),use_proportional_edit=True,proportional_size=0.5) verts[idx].select_set(False)  これでやっとスクリプトによるプロポーショナル編集ができました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む