20200702のPythonに関する記事は29件です。

anacondaをインストールした後PATHを通すのに躓いた

pythonの勉強のためanaconda3をインストールして、pythonを実行しようとしたら躓いた話。

anaconda3はインストール時にPATHを通すかどうか聞かれるがチェックを入れ忘れたままインストールしてしまったので、手動でPATHを設定しなければならなくなりました。

Windows10ならPATHの設定は以下の手順でできます
・検索ボックスで「環境変数を編集」で検索
・「Path」を選択→「編集」
・「新規」を押してインストールしたディレクトリを追加
 自分は「E:\Apps\anaconda3\」にインストールしたため、ここを追加しました
・ついでにpip.exeのある「E:\Apps\anaconda3\Scripts」も追加

以上でPATHが通ったため、コマンドラインで「python -V」でPATHが通ったか確認。
うまくいっていればインストールしたpythonのバージョンが表示されるはずが、なぜか「Microsoft Store」のpythonのインストールページに飛ばされる...

なぜだ...

「環境変数を編集」を見てもちゃんと正しくパスが追加されているし、再起動も試したが効果なし...

Microsoft StoreからインストールしろというMicrosoftのいやらしい販売戦略かとも思ったりしつつ四苦八苦して、ようやく原因がわかりました。

「環境変数を編集」のPathの編集画面で、pythonのパスより上に「%USERPROFILE%\AppData\Local\Microsoft\WindowsApps」があったのでした。
環境変数は上から順に適用されるようで、anaconda3フォルダのpython.exeよりもMicrosoft Storeのpythonの検索が先に実行されてしまっていたようでした。

ということで、追加した2つのパスを上へ移動して、コマンドラインで「python -V」を実行したところ、無事にpythonのバージョンが表示されました。

anacondaのPATHの設定について書いてあるぺージは結構あったのですが、パスの順番について触れているところはなかったので、同じ状況に陥った人がいたら役に立ってほしいと思いました。

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

anacondaをインストールした後PATHを通すのに躓いた話

pythonの勉強のためanaconda3をインストールして、pythonを実行しようとしたら躓いた話。

anaconda3はインストール時にPATHを通すかどうか聞かれるがチェックを入れ忘れたままインストールしてしまったので、手動でPATHを設定しなければならなくなりました。

PATHの通し方(Windows10)

Windows10ならPATHの設定は以下の手順でできます
・検索ボックスで「環境変数を編集」で検索
・「Path」を選択→「編集」
・「新規」を押してインストールしたディレクトリを追加
 自分は「E:\Apps\anaconda3\」にインストールしたため、ここを追加しました
・ついでにpip.exeのある「E:\Apps\anaconda3\Scripts」も追加

PATHを通した結果...

以上でPATHが通ったため、コマンドラインで「python -V」でPATHが通ったか確認。
うまくいっていればインストールしたpythonのバージョンが表示されるはずが、なぜか「Microsoft Store」のpythonのインストールページに飛ばされる...

なぜだ...

「環境変数を編集」を見てもちゃんと正しくパスが追加されているし、再起動も試したが効果なし...

解決策

Microsoft StoreからインストールしろというMicrosoftのいやらしい販売戦略かとも思ったりしつつ四苦八苦して、ようやく原因がわかりました。

「環境変数を編集」のPathの編集画面で、pythonのパスより上に「%USERPROFILE%\AppData\Local\Microsoft\WindowsApps」があったのでした。
環境変数は上から順に適用されるようで、anaconda3フォルダのpython.exeよりもMicrosoft Storeのpythonの検索が先に実行されてしまっていたようでした。

ということで、追加した2つのパスを上へ移動して、コマンドラインで「python -V」を実行したところ、無事にpythonのバージョンが表示されました。

基本的だけど見落としがち

anacondaのPATHの設定について書いてあるぺージは結構あったのですが、パスの順番について触れているところはなかったので、同じ状況に陥った人がいたら役に立ってほしいと思いました。

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

AzureMachineLeaningを使ってJupyterlabを立ち上げる方法

簡単に

  • AzureMachineLeaningにてJupyterlabを立ち上げる手順をまとめた。
  • 比較的簡単にJupyterlab環境が構築できる。
  • コンペで分析環境として使用する観点から見ると、更に簡単にjupyterlab環境を立ち上げられると、より嬉しい。

はじめに

Kaggleなどの分析コンペに参加する際、「取り合えず今すぐ分析できる環境が欲しい!」と皆さん考えるかと思います。そんなとき、クラウド上の分析環境は、

  • ハードウェアが必要ない
  • PCとネットがあればどこでも使える
  • スペックが簡単に変えられる
  • 最悪、変なことをしてしまっても再度作り直せば良いため気軽に環境をいじれる。

というメリットがあり、更にその分析環境を簡単に用意できたらとっても魅力的かと思います。

強力なクラウド環境の一つであるAzureに関して、Kaggleの「M5 Forecasting - Accuracy」にAzureを使って挑戦しました。AzureMachineLeaningを使い、Jupyterlab環境を構築する手順とその感想を記載します。

手順は公式の説明をベースに作成しています。

またJupyterlabの立ち上げという意味ではAzure Notebooksの方が便利かもしれません。(今回の記事では触れません。)

Jupyterlabの立ち上げ方(2020/7/2)

  1. Azureにログインし、画面上部の検索欄から「MachineLearning」と検索します。image.png

  2. サービスの中に「Machine Leaning」という項目が現れるため、クリックします。image.png

  3. 下記画面にて画面中央部の「Azure Machine Leaningの作成」をクリックします。image.png

  4. 下記のような画面が現れます。変更する必要があるのは、下記2点のみです。image.png

  5. ①リソースグループの「新規作成」をクリックします。

  6. リソースグループの名前を聞かれるため、好きな名前を入力し、「OK」をクリックします。

  7. ②ワークスペース名に関しても同様に、好きな名前をつけます。image.png

  8. 画面左下の「確認および作成」をクリックします。

  9. 画面上部に「検証に成功しました」と表示されたら、画面左下の「作成」をクリックします。

  10. 数分待つと下記のような画面になるため、「リソースに移動」をクリック。

  11. 下記のような画面が表示されるため「今すぐ起動する」をクリック。image.png

  12. 下記画面ノートブックの「今すぐ開始」をクリック。image.png

  13. 下記画面のマイファイルについて、下記赤枠のアップロードボタンを用いて、ipynbファイルをアップロードします。今回は「Azure_test.ipynb」をアップロードします。

  14. アップロードしたファイルをクリックすると、下記画像のような画面になるため、コンピューティングの右側の「…」をクリックし、「新しいコンピューティング」をクリックします。(一番初めはコンピューティングの右枠の中に、コンピューティングが存在しない旨が記載されているかと思います。)image.png

  15. 下記画面が表示されるため、「コンピューティング名」「仮想マシンの種類」「仮想マシンのサイズ」を選択し、「作成」をクリックします。スペックを変更したい場合はここの設定を変更しましょう。!

  16. 数分待つとコンピューティングが「実行中」になるため、「Jupyter」をクリックし、「JupyterLab」で編集をクリック。image.png

  17. Jupyterlabが立ち上がります。後は分析を楽しみましょう!image.png

改善点

冒頭にも書きましたが、分析者は「可能な限り簡単に分析環境が手に入ること」に興味があると考えます。その観点でいうと、

  • ワークスペースの作成が必要
  • AzureMachineLeaningStudioの起動が必要
  • コンピューティングの作成が必要

と三段階踏む必要があるのは「可能な限り簡単に」とは言い切れないと思います。より簡単に構築できると、更に嬉しいです。

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

matplotlibで線のグラデーション

image.png

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt

x = np.linspace(0, 5, 100)
N = 21
cmap = plt.get_cmap('jet',N)

fig = plt.figure(figsize=(8,6))
ax1 = fig.add_axes([0.10,0.10,0.70,0.85])

for i,n in enumerate(np.linspace(0,2,N)):
    y = np.sin(x)*x**n
    ax1.plot(x,y,c=cmap(i))

plt.xlabel('x')
plt.ylabel('y')

norm = mpl.colors.Normalize(vmin=0,vmax=2)
sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
sm.set_array([])
plt.colorbar(sm, ticks=np.linspace(0,2,N), 
             boundaries=np.arange(-0.05,2.1,.1))


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

Kaggle~住宅価格予測②~

はじめに

前回、線形回帰にて実装したが今回は非線形を用いての実装してみた。

引き続きこちらの記事を参考にデータ前処理を実装した。
「データ前処理」- Kaggle人気チュートリアル

モデルを作成

① 線形回帰(LinearRegression)
② Ridge回帰(Ridge)
③ サポートベクターマシン回帰(SVR)
④ ランダムフォレスト回帰(RandomForestRegressor)
こちらの4つについてモデルを作成した。

# 説明変数と目的変数
x = df_train[['OverallQual', 'YearBuilt', 'TotalBsmtSF', 'GrLivArea']]
y = df_train['SalePrice']

# モジュールをインポートする
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
# 訓練データとテストデータとに分ける
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=42)

平均二乗誤差を算出する関数を作成する

def calc_model(model):
    # モデルを学習させる
    model.fit(X_train, y_train)
    # X_testに対する予測値
    pred_y = model.predict(X_test)
    # 平均二乗誤差を出す
    score = mean_squared_error(y_test, pred_y)
    return score

線形回帰

# 線形回帰のとき
from sklearn.linear_model import LinearRegression
# モデルを構築
lr = LinearRegression()
# 平均二乗誤差を算出
lr_score = calc_model(lr)
lr_score
# >>>出力
0.02824050462867693

Ridge回帰

# Ridge回帰のとき
from sklearn.linear_model import Ridge
# モデルを構築
ridge = Ridge()
# 平均二乗誤差を算出
ridge_score = calc_model(ridge)
ridge_score
# >>>出力
0.028202963714955512

サポートベクターマシン回帰

# サポートベクターマシン回帰のとき
from sklearn.svm import SVR
# モデルを構築
svr = SVR()
# 平均二乗誤差を算出
svr_score = calc_model(svr)
svr_score
# >>>出力
0.08767857928794534

ランダムフォレスト回帰

# ランダムフォレスト回帰のとき
from sklearn.ensemble import RandomForestRegressor
forest = RandomForestRegressor()
# 平均二乗誤差を算出
forest_score = calc_model(forest)
forest_score
# >>>出力
0.03268455739481754

結果として非線形回帰の平均二乗誤差は大きく出た。

テストデータの前処理

欠損値の有無

# テストデータの前処理
# Idの値を抜き出す
df_test_index = df_test['Id']
# 欠損値の確認
df_test = df_test[['OverallQual', 'YearBuilt', 'TotalBsmtSF', 'GrLivArea']]
df_test.isnull().sum()
# >>>出力
OverallQual    0
YearBuilt      0
TotalBsmtSF    1
GrLivArea      0
dtype: int64

TotalBsmtSFの欠損値を平均値で補完する。

# 欠損値を平均値で補完する
df_test['TotalBsmtSF'] = df_test['TotalBsmtSF'].fillna(df_test['TotalBsmtSF'].mean())
# 欠損値を確認する
df_test.isnull().sum()
# >>>出力
OverallQual    0
YearBuilt      0
TotalBsmtSF    0
GrLivArea      0
dtype: int64

欠損値はなくなった。

CSVファイルへ出力

# モデルを当てはめる
pred_y = ridge.predict(df_test)

# データフレームの作成
submission = pd.DataFrame({'Id': df_test_index,
                          'SalePrice': np.exp(pred_y)})
# CSVファイルに出力
submission.to_csv('submission.csv', index=False)

結果は、0.17184と結果は伸びず。

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

ゼロから始めるLeetCode Day74 「12. Integer to Roman」

概要

海外ではエンジニアの面接においてコーディングテストというものが行われるらしく、多くの場合、特定の関数やクラスをお題に沿って実装するという物がメインである。

どうやら多くのエンジニアはその対策としてLeetCodeなるサイトで対策を行うようだ。

早い話が本場でも行われているようなコーディングテストに耐えうるようなアルゴリズム力を鍛えるサイトであり、海外のテックカンパニーでのキャリアを積みたい方にとっては避けては通れない道である。

と、仰々しく書いてみましたが、私は今のところそういった面接を受ける予定はありません。

ただ、ITエンジニアとして人並みのアルゴリズム力くらいは持っておいた方がいいだろうということで不定期に問題を解いてその時に考えたやり方をメモ的に書いていこうかと思います。

Leetcode

Python3で解いています。

ゼロから始めるLeetCode 目次

前回
ゼロから始めるLeetCode Day73 「1491. Average Salary Excluding the Minimum and Maximum Salary」

今はTop 100 Liked QuestionsのMediumを優先的に解いています。
Easyは全て解いたので気になる方は目次の方へどうぞ。

Twitterやってます。

技術ブログ始めました!!
技術はLeetCode、Django、Nuxt、あたりについて書くと思います。こちらの方が更新は早いので、よければブクマよろしくお願いいたします!

問題

12. Integer to Roman
難易度はMedium。

なんかBadの方が多いので嫌な予感がしてました・・・

ローマ数字は7つの異なる記号で表されます。I、V、X、L、C、D、Mの7つの異なる記号で表されます。
この問題では、以下のように変換されています。

Symbol       Value
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

例えば、2はローマ数字でIIと書かれていますが、これは単に2つの1を足しただけです。12はXIIと書かれていますが、これは単にX + IIです。二十七という数字は、XXVIIと書かれていますが、これはXX + V + IIです。

ローマ数字は通常、左から右に大きい方から小さい方へと書かれています。しかし、4という数字はIIIIではありません。その代わり、4という数字はIVと書かれています。1は5の前にあるので、それを引くと4になります。9という数字も同じ原理で、IXと書かれています。引き算を使う例は6つあります。

I は V (5) と X (10) の前に置くと 4 と 9 になります。
X は L (50) と C (100) の前に置くと 40 と 90 になります。
C を D (500) と M (1000) の前に置くと 400 と 900 になります。

整数が与えられた時に以上の法則に則ってローマ数字に変換するアルゴリズムを設計してください、という問題です。

なお、入力は1から3999までの範囲内であることが確定しています。

Example 1:
Input: 3
Output: "III"

Example 2:
Input: 4
Output: "IV"

Example 3:
Input: 9
Output: "IX"

Example 4:
Input: 58
Output: "LVIII"
Explanation: L = 50, V = 5, III = 3.

Example 5:
Input: 1994
Output: "MCMXCIV"
Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.

解法

class Solution:
    def intToRoman(self, num: int) -> str:
        nums = (1000,900,500,400,100,90,50,40,10,9,5,4,1)
        roman = ("M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I")
        ans = ""
        while num != 0:
            for i, j in enumerate(nums):
                if num >= j:
                    num -= j
                    ans += roman[i]
                    break
        return ans
# Runtime: 52 ms, faster than 60.03% of Python3 online submissions for Integer to Roman.
# Memory Usage: 13.9 MB, less than 33.48% of Python3 online submissions for Integer to Roman.

numsromanでそれぞれの値を保持しておき、0になるまでfor文を回し、その中で値がj以上の場合にのみj分減らし、romanのインデックスをansに加える、というものです。

numsromanの値が一致しているのでインデックスをそのまま使いまわせる、という訳ですね。
今思えば辞書を使った方がスッキリかけそうな気がしないでもないですね。

なお、discussの中には力技で以下のような回答をしていらっしゃる方もいます。

class Solution(object):
    def intToRoman(self, num):
        """
        :type num: int
        :rtype: str
        """
        result = []
        if num>=1000:
            times = num/1000
            result.append(times*'M')
            num = num%1000
        if num>=900:
            result.append('CM')
            num -=900
        if num>=500 and num<900:
            result.append('D')
            num -= 500
        if num>=400 and num<500:
            result.append('CD')
            num-=400
        if num >=100 and num<400:
            times = num/100
            result.append(times *'C')
            num = num%100
        if num >=90 and num<100:
            result.append('XC')
            num-=90
        if num >=50 and num<90:
            result.append('L')
            num-=50
        if num>=40 and num<50:
            result.append('XL')
            num-=40
        if num>=10 and num<40:
            times = num/10
            result.append(times*'X')
            num %= 10
        if num==9:
            result.append('IX')
            num-=9
        if num>=5 and num<9:
            result.append('V')
            num-=5
        if num==4:
            result.append('IV')
            num-=4
        if num>=1 and num<=3:
            result.append(num*'I')
            num-=num
        return ''.join(result)        
# Runtime: 20 ms, faster than 99.65% of Python online submissions for Integer to Roman.
# Memory Usage: 12.7 MB, less than 65.50% of Python online submissions for Integer to Roman.

https://leetcode.com/problems/integer-to-roman/discuss/715614/Clean-easy-and-fast-Python-Solution

Python3ではなくPythonでの提出です。

解いてみて何となくBadの数が多い理由が分かったような気がします・・・

では今回はここまで。お疲れ様でした。

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

[Python]PylanceのVS Code拡張機能をさっそく使ってみた。

VS Codeなどで使えるPylanceという拡張機能がリリースされていたので早速使ってみました。

参考 : 型ヒントでPython開発を加速 ~Microsoft、VS Code向けの拡張機能「Pylance」を発表

(大雑把に)どんな拡張機能?

  • マイクロソフト製のPythonの拡張機能です。
  • Python拡張機能に入っているようなPythonの入力補完周りが有効になります。これはまあ大半のVS Code使ってPythonのコード書いている方はPythonの拡張機能入れていらっしゃるでしょうからそこまでは大きく変わりません。
  • 以前書いたPythonの型チェック用のPyrightと同じように、コードを書きつつ型のミスや補完が効きづらい箇所で型アノテーションをすることで補完が効くようになってくれます(内部でPyrightが使われています)。
  • importが足りない箇所のエラーのチェックと、足りないimportをコードに挿入してくれる選択肢を出してくれます。
  • この記事を書いている2020-07-02時点ではまだPreview版です。

インストール方法

VS Codeの拡張機能のページでpylanceなどと検索してインストールするだけです。

image.png

ただし、私の場合はPyrightの拡張機能を事前に入れたままだったのですが、競合したのかPylanceをインストールしたらエラーが出るようになりました。Pyrightの拡張機能を無効化した後にVS Codeを再起動したらエラーが無くなりました。

型チェックを有効化する

デフォルトだと型チェックの機能が無効になっています。有効化するにはVS Codeの設定画面を開いて、「python.analysis.typeCheckingMode」を検索して、設定をbasicもしくはstrictに切り替えます。

image.png

basicは型アノテーションがしてある箇所で正しいかどうかがチェックされるといった具合の少し緩い感じのチェックのようです。

strictは型アノテーションなどがしていない箇所自体もエラーになったりするようです。最初からstrictであれば問題ありませんが、途中から型アノテーションをはじめてstrict設定をすると既存コードでエラーがたくさん出てきてちょっと辛い感じではあります:sweat:

importエラー時に該当するimportを挿入する

Pyrightなどに無かった?機能として、Pythonコードでimportをし忘れていたといったときに、importをしてくれる機能がPylanceに追加になっています。

この機能、Pythonではない他の言語を使って仕事をしていた頃似たようなものを結構愛用していたので、使えるようになって嬉しい感じです!

importが足りないケースなどでは以下のようにVS Code上で赤い下線によるエラー表示になります。

image.png

その状態でカーソル位置をエラーになっている部分(画像ではnp)に合わせると、電球らしきアイコンが出てきます。

image.png

この状態でCtrl + .を押すか、電球アイコンをクリックすると挿入するimportのリストを表示してくれます。numpyとかとやらずにnpとかでもちゃっと認識してくれるのは賢い・・・!

image.png

該当のものを選択すると、import文が挿入されます。

image.png

また、この機能はマウスオーバー時に表示されるポップアップ上の「Quick Fix...」をクリックしても同様の機能が使えました。

image.png

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

Light CNNの実装(Python Keras)

はじめに

本記事ではLight CNN(LCNN)という深層学習モデルを実装したのでまとめさせていただきました。
最初にLCNNとその特徴であるMax Feature Mapping (MFM)という技術について説明した後、実装と評価をしていきます。
コードは全てpython、LCNNの実装はTensorflow, Kerasを使って行います。
なお、LCNNを実装するためのコードはGithubに載せてるので参考にしてください。
Github URL : https://github.com/ozora-ogino/LCNN

Light CNN

LCNNは2015年にSTC提案され、現在はSTCという機関により研究されている深層学習手法で画像分類や音声分類等の分野で使用されています。
LCNNは8層の畳み込み層から構成されており、各層における活性化関数でMax Feature Mappingと呼ばれるものを使っているのが大きな特徴となっています。

Max Feature Mapping

MFMについてはこちらに詳しくまとめたので参考にしてみてください。
元の論文も載せておきます。
"A Light CNN for Deep Face Representation with Noisy Labels
" (https://arxiv.org/pdf/1511.02683.pdf)

実装

GitHubに載せているものと同じコードになります。

lcnn.py
import tensorflow as tf
from keras.layers import Activation, Dense, BatchNormalization, MaxPool2D, Lambda, Input, Flatten, Dropout
from keras.layers.convolutional import Conv2D
from keras.models import Model
from keras.initializers import he_normal

#Custom layer
from .layers import Maxout


#function that return the stuck of Conv2D and MFM
def MaxOutConv2D(x, dim, kernel_size, strides, padding='same'):
    conv_out = Conv2D(dim, kernel_size=kernel_size, strides=strides, padding=padding)(x)
    mfm_out = Maxout(int(dim/2))(conv_out)
    return mfm_out


#function that return the stuck of FC and MFM
def MaxOutDense(x, dim):
    dense_out = Dense(dim)(x)
    mfm_out = Maxout(int(dim/2))(dense_out)
    return mfm_out

# this function helps to build LCNN. 
def build_lcnn(shape, n_label=2):
    """
    Auguments:
     shape (list) : 
      Input shape for LCNN. (Example : [128, 128, 1])
     n_label (int) : 
      Number of label that LCNN should predict.
    """

    input = Input(shape=shape)

    conv2d_1 = MaxOutConv2D(input, 64, kernel_size=5, strides=1, padding='same')
    maxpool_1 = MaxPool2D(pool_size=(2, 2), strides=(2,2))(conv2d_1)

    conv_2d_2 = MaxOutConv2D(maxpool_1, 64, kernel_size=1, strides=1, padding='same')
    batch_norm_2 = BatchNormalization()(conv_2d_2)

    conv2d_3 = MaxOutConv2D(batch_norm_2, 96, kernel_size=3, strides=1, padding='same')
    maxpool_3 = MaxPool2D(pool_size=(2, 2), strides=(2,2))(conv2d_3)
    batch_norm_3 = BatchNormalization()(maxpool_3)

    conv_2d_4 = MaxOutConv2D(batch_norm_3, 96, kernel_size=1, strides=1, padding='same')
    batch_norm_4 = BatchNormalization()(conv_2d_4)

    conv2d_5 = MaxOutConv2D(batch_norm_4, 128, kernel_size=3, strides=1, padding='same')
    maxpool_5 = MaxPool2D(pool_size=(2, 2), strides=(2,2))(conv2d_5)

    conv_2d_6 = MaxOutConv2D(maxpool_5, 128, kernel_size=1, strides=1, padding='same')
    batch_norm_6 = BatchNormalization()(conv_2d_6)

    conv_2d_7 = MaxOutConv2D(batch_norm_6, 64, kernel_size=3, strides=1, padding='same')
    batch_norm_7 = BatchNormalization()(conv_2d_7)

    conv_2d_8 = MaxOutConv2D(batch_norm_7, 64, kernel_size=1, strides=1, padding='same')
    batch_norm_8 = BatchNormalization()(conv_2d_8)

    conv_2d_9 = MaxOutConv2D(batch_norm_8, 64, kernel_size=3, strides=1, padding='same')
    maxpool_9 = MaxPool2D(pool_size=(2, 2), strides=(2,2))(conv_2d_9)
    flatten = Flatten()(maxpool_9)

    dense_10 = MaxOutDense(flatten, 160)
    batch_norm_10 = BatchNormalization()(dense_10)
    dropout_10 = Dropout(0.75)(batch_norm_10)

    output = Dense(n_label, activation='softmax')(dropout_10)

    return Model(inputs=input, outputs=output)

評価

実装したLCNNは音声認識コンペで使用されたモデルになりますが、簡単な画像認識でどの程度の性能が出るのかmnistとCIFAR10で試してみました。
モデルチューニング等は一切していませんがmnistでは99%、CIFAR10では75%程度の性能を示すことができました。

mnist

test_mint.py
import numpy as np
from keras.callbacks import EarlyStopping
from keras.utils import to_categorical
from keras.datasets import mnist

lr = 0.001
epochs = 10
batch_size =256

[x_train, y_train], [x_test, y_test] = mnist.load_data()
x_train = x_train / 255
x_train = x_train.reshape((x_train.shape[0], x_train.shape[1], x_train.shape[2], 1))
y_train = to_categorical(y_train)
input_shape = x_train.shape[1:]

lcnn = build_lcnn(input_shape, n_label=10)
lcnn.compile(optimizer=Adam(learning_rate=lr), loss='categorical_crossentropy', metrics=['accuracy'])
es = EarlyStopping(monitor='val_loss', patience=3, verbose=1)
history = lcnn.fit(x_train, y_train, epochs=epochs, batch_size=batch_size, validation_split=0.2, callbacks=[es])

x_test = x_test / 255
x_test = x_test.reshape((x_test.shape[0], x_test.shape[1], x_test.shape[2], 1))
y_test = to_categorical(y_test)

loss, acc = lcnn.evaluate(x_test, y_test)

print(f'Accuracy : {acc*100}') # Result --> Accuracy : 99.90999794006348
print(f'Loss : {loss}')# Result --> Loss : 0.04250425341885457

CIFAR10

test_cifar10.py
import numpy as np
from keras.callbacks import EarlyStopping
from keras.utils import to_categorical
from keras.datasets import cifar10

lr = 0.001
epochs = 100
batch_size =64

[x_train, y_train], [x_test, y_test] =cifar10.load_data()

x_train = x_train / 255
y_train = to_categorical(y_train)
input_shape = x_train.shape[1:]

lcnn = build_lcnn(input_shape, n_label=10)
lcnn.compile(optimizer=Adam(learning_rate=lr), loss='categorical_crossentropy', metrics=['accuracy'])
es = EarlyStopping(monitor='val_loss', patience=5 , verbose=1)
history = lcnn.fit(x_train, y_train, epochs=epochs, batch_size=batch_size, validation_split=0.2, callbacks=[es])


x_test = x_test / 255
y_test = to_categorical(y_test)

loss, acc = lcnn.evaluate(x_test, y_test)
print(f'Accuracy : {acc*100}') # Result --> Accuracy : 75.1200020313263
print(f'Loss : {loss}')# Result --> Loss : 1.2616282165050507

まとめ

LCNNという深層学習モデルを実装したのでまとめさせていただきました。
参考になれば幸いです。
Github URL : https://github.com/ozora-ogino/LCNN

Reference

"A Light CNN for Deep Face Representation with Noisy Labels"
"STC Antispoofing Systems for the ASVspoof2019 Challenge"
"Audio replay attack detection with deep learning frameworks"

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

回帰の評価指標、RMSE(平均平方二乗誤差)の落とし穴!

はじめに

 機械学習の回帰モデルの評価としてはRMSE(平均平方二乗誤差)がよく使われます。一方で、RMSEは外れ値に弱いということが紹介の中でよく書かれていますが気にせず使われている例が見られます。
 「それじゃあ一体どれくらい弱いのか?」というのを考えることでアンチパターンとして抑えておきましょう。
 先に結論を書くと「目安として、平均の10倍以上の値が存在する場合は気をつけて使用する必要がある。その場合は対数をとったRMSLEを使用するのが良い」となります。

①RMSE(平均平方二乗誤差)とはどんなもの?

まあ、名前のとおりです。誤差、つまり実際の値と予測値の差分を二乗した後に平均してルートを取るというものです。

\textrm{RMSE} = \sqrt{\frac{1}{N}\sum_{i=1}^{N}(y_{i}-\hat{y}_{i})^{2}}

計算式は偏差値にかなり近くて、偏差が誤差に変わっただけです。なので上手く使えば「このモデルはだいたいこれぐらいの誤差を出すんだろうな」というイメージが作れます。

②RMSEがおかしくなるときは? 値のスケールについて。

 RMSEは人気があって使う人が多いですが、外れ値が存在する場合に外れ値に値が引きずられやすいという欠点があります。
意外と気にしてない人が多いのではないでしょうか。
 誤差としての値しか計算に入らないので「10を20」と予測した場合の誤差と、「100を110」と予測した誤差が同じものとして評価されます。
 また、殆ど数十くらいのデータの中に「1,000を900」と予測する誤差があった場合に1つのデータだけ重要度がぜんぜん違うという扱いとなってしまいます。

import numpy as np
a = np.array([10]*100) # 誤差10を100個用意したと仮定
print(np.sqrt((a**2).mean())) # RMSEはもちろん10
a = np.append(a, [100]*1) # 101個目に100を追加
print(np.sqrt((a**2).mean())) # RMSEは14.07まで上昇!

 計算の際に二乗されるので10倍のスケールの誤差は指標上の重要度は100倍となります。もし平均的な誤差の100倍もの値が存在するとしたら、その重要度は平均的な誤差10,000倍、つまり10,000レコード分にもなってしまいます。
 そして機械学習では外れ値ほど予測が難しいので、外れ値が存在する場合必然的に評価が安定しなくなります。

 ③じゃあ評価指標はどうすればよいの?

 個人的には比率として考えられるRMSLEもしくはMAEがいいかなと思っています。機械学習モデルはまずオーダーを正しく当てるくらいで考えておくべきなのかなと。
 RMSLEはRMSEの対数をとったものです。yのlogを取ることでRMSLEにできます。こうしてRMSEとして扱って最後にexpにするのが使いやすいかなと考えます。
 MAEは平均する際に二乗ではなく絶対値をとったものです。こうすると誤差が増幅されることがないので外れ値に強くなります。ただ、モデル学習の際の損失係数として使いにくいです。
 もちろん「外れ値は殆どない」「大きな値のミスが問題だ」という場合はRMSEを使っても問題はないです。

④実例紹介

 最近のコンペだとProbSpaceさんの不動産取引価格予測コンペでRMSEが使われて、データの中に平均の100倍以上の値が紛れていて順位が大きく変動したというのがありました。「スケールの差によってどれくらいRMSEが変化するのか分析したトピック」(ログイン必要)もありますので興味があればご覧ください。
 実案件でも「RMSEは知っているけど外れ値の可能性を考えた場合にモデル評価に適切かまでは認識してなかった」というのを見たことがあります。

結論

 結論としては「スケールが違うデータが来る可能性がある場合はRMSEを使わない!RMSLEを使う!」に尽きると思います。RMSEしか見ないのは、分類でAccuracyしか見ないくらい危険だと思います。
 ちなみに上で上げたProbSpaceさんの不動産価格予測コンペですが、2020年8月11日締切で評価指標をRMSLEに変更して再度開催されています。前回参加した人の解法などがある状態から参加できるので初心者におすすめなコンペになっていると思います。アンチパターンの例としてあげて申し訳ない気分ですが、このように再度開いていただけるのは素晴らしく思っております。
 以上、評価指標は注意しておかないと大きな落とし穴にはまったり、逆に気をつけるだけでコンペで良い順位取れたりするので、気にしておいて損はないものだ、という話でした。

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

cumprodとcummaxについて

1 目的

cumprodとcummaxの使い方例を説明します。

2 内容

cumprod ・・・ 配列の全要素について累積積を計算します。
cummax ・・・ 配列の全要素から最大値を取り出します。

test.py
import numpy as np
import pandas as pd


dat = [
    ['2019-07-01',10],
    ['2019-07-02',12],
    ['2019-07-03',8],
    ['2019-07-04',14],
    ['2019-07-05',7],
    ['2019-07-08',3]
]
df0 = pd.DataFrame(dat,columns=["A","B"])

print(df0)

df1=df0['B'].pct_change()
df2=(1 + df1)
df3=(1 + df1).cumprod() #0番目からi番目の要素までの累積積を算出します。
df4=(1 + df1).cummax()  #0番目からi番目の要素の中で最大値を取り出します。
print(df1)
print(df2)
print(df3)
print(df4)
<df0:基本データ>
            A   B
0  2019-07-01  10
1  2019-07-02  12
2  2019-07-03   8
3  2019-07-04  14
4  2019-07-05   7
5  2019-07-08   3

df1: (df0['B']のi番目とi-1番目の変化率を計算する)
0         NaN
1    0.200000
2   -0.333333
3    0.750000
4   -0.500000
5   -0.571429
Name: B, dtype: float64

df2: (df1+1を計算する)
0         NaN
1    1.200000
2    0.666667
3    1.750000
4    0.500000
5    0.428571
Name: B, dtype: float64

df2: (cumprod() 累積積を計算する)

0    NaN
1    1.2
2    0.8  (=1.2×0.666667)
3    1.4   (=1.2×0.666667×1.75)
4    0.7   (=1.2×0.666667×1.75×0.5)
5    0.3   (=1.2×0.666667×1.75×0.5×0.428)
Name: B, dtype: float64

df3: (cummax() 要素の中から最大値を取り出す。)

0     NaN
1    1.20   (df2:要素1から要素1までの中での最大値)
2    1.20   (df2:要素1から要素2までの中での最大値)
3    1.75   (df2:要素1から要素3までの中での最大値)
4    1.75   (df2:要素1から要素4までの中での最大値)
5    1.75   (df2:要素1から要素5までの中での最大値)
Name: B, dtype: float64
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[光-Hikari-のPython]09章-01 クラス(オブジェクトの基礎)

[Python]09章-01 オブジェクトの基礎

今まで、文字列や数値、データ構造の分野ではリストやタプルなどに触れました。データ構造の個所で触れましたが、これらはオブジェクトと言いました。

さて、このオブジェクトとは何でしょう。まずはオブジェクトについて説明して少し掘り下げていきたいと思います。

オブジェクトとは

まずはPython Consoleにて以下のコードを入力して確認してみましょう。

>>> S = 'hello'
>>> type(S)
<class 'str'>

Sという変数に'hello'という文字列を代入しています。さて、次にtype()関数により、<class 'str'>が出力されています。
これは、S変数がが現在str型のオブジェクトであることを意味しています。

では、strオブジェクトの詳細を見てみましょう。以下のURLから閲覧できます。
https://docs.python.org/ja/3/library/stdtypes.html#text-sequence-type-str

マニュアルを見てみると、str型はテキストシーケンス型と書かれています。要するに文字列型のオブジェクトということです。

さて、マニュアルを少し下に送ると、「文字列メソッド」というものが出てきます。
例えば、一番最初にあるstr.capitalize()メソッドを実行してみましょう。
なお、このマニュアルにある、strはstr型のオブジェクトを表すので、今回実際に入力するときにはSという変数名となります。

>>> S
'hello'
>>> S.capitalize()
'Hello'

先頭のみ、大文字になったことが確認できたと思います。詳細はstr.capitalize()メソッドマニュアルを見てください。

また、ほかのメソッドも見てみましょう。str.replace()メソッドを実行してみましょう。

>>> S.replace('l', 'L')
'heLLo'

replaceメソッドにより、文字列中の文字を変更ができます。詳細はマニュアルを見てみましょう。

他にもいろいろなメソッドをマニュアルを見ながらやってみましょう。今後、マニュアルに書いてある内容は一部を除き、割愛していきたいと思います。

さて、このstr型だけではないですが、オブジェクトの型にはほかにもあります。以下のコマンドでいろいろな方を確認してみましょう。

以下はint型オブジェクトとなります。

>>> num1 = 100
>>> type(num1)
<class 'int'>

以下はfloat型オブジェクトとなります。

>>> num2 = 10.5
>>> type(num2)
<class 'float'>

以下はlist型オブジェクトとなります。

>>> ls = ['Japan', 'America', 'China']
>>> type(ls)
<class 'list'>

以下はtuple(タプル)型オブジェクトとなります。

>>> tp = (10, 20, 30)
>>> type(tp)
<class 'tuple'>

以下はdict(ディクショナリ)型オブジェクトとなります。

>>> dc = {'jp':'Japan','us':'America', 'ch':'Chine'}
>>> type(dc)
<class 'dict'>

これらそれぞれの型のオブジェクトにはメソッドを持ちます。実際に調べてみましょう。ほとんどは以下のURLに記載してあります。
https://docs.python.org/ja/3/library/stdtypes.html

<重要>
実は、あるデータとその振る舞い(メソッド)が一塊になっているものを一般にオブジェクトと言います。
例えば、

>>> ls = [1, 3, 3, 2, 1, 2, 2, 1, 1, 2]
>>> ls.count(2)
4

とすれば、lsはリスト型のオブジェクトであり、そのオブジェクトは「1, 3, 3, 2, 1, 2, 2, 1, 1, 2」というデータを持ち、count()というメソッドも持ちます

また、関数もオブジェクト(functionオブジェクト)と言えます。

def calc_func(x):
    print('関数内で実行します')
    f = (x ** 2) + (3 * x) + 4
    ##計算結果fを返す
    return f

print(type(calc_func))

【実行結果】
<class 'function'>

オリジナルのオブジェクト

先ほどはint型やstr型、そしてlist型などのオブジェクトがありましたが、実はオブジェクトは自分で作成することができます。
これについては次回触れていきたいと思います。

最後に

このオブジェクトの概念は非常に取り扱いの難しいものなので、最初は壁を感じるかと思います。ポイントは先ほどのURLにもあった、いろいろなマニュアルを読んでみることです。
最初は意味が分からなくても、読んでいくことで意味が分かってくるようになりますので、ポイントはマニュアルを見ながら実際に実行してみることです。

【目次リンク】へ戻る

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

VSCode + Python で, Jupyter notebook っぽいインラクティブ表示モードを使うメモ

背景

  • Jupyter-lab で matplotlib などでプロットのインラクティブ表示などを使っているが, VSCode でも似たようなのがほしい
  • .ipynb で VSCode で notebook モードにする手ははあるが, vim キーバインドが使えずつらい :cry:
  • 素の .py ファイル/プロジェクトでインタラクティブプロット表示とかしてほしい

方法

Working with the Python Interactive window
https://code.visualstudio.com/docs/python/jupyter-support-py

Python ファイルを作成し, #%% と打つだけで, notebook っぽい interactive mode いけました!
(#%% には, スペースがあってもなくてもどちらでもかまいせん)

jupyter 関連インストールされていなければ, インストールしますかポップアップ出してくれます!

Screenshot from 2020-07-02 18-03-31.png

Cell とかは VSCode 側でアノテーション表示されているものです.

いろいろ設定するとインライン表示もできるかも?

macOS だと, python や jupyter addon のインストール関連で注意しないとうまくうごかないかもです!

TODO

  • remote Jupyter と接続などアドバイスな機能を調べる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PDFをOCRしてDocumentsに変換する

はじめに

本記事は、Python(Google Colab環境)でのPDFのOCR処理(Google Documentsへ変換)について解説します。

Google DriveにはPDFをOCR処理してDocumentsファイルに変換してくれる機能が存在します。
Pythonコードでの処理方法について記載します。

  1. PDFからテキスト抽出を行う
  2. テキスト抽出にはGoogle DriveのOCR機能を用いる
  3. OCR処理によってGoogle Documentsへ変換し、テキスト抽出を行う
  4. Documentsに変換された際のファイル名の英字が全角になる問題への対処

特に、4のファイル名の全角問題については情報がなかったため、同じ問題に悩まされている・悩まされた方へナレッジとして共有したいなと考えました。

技術要素

ソースコード

今回の最終形のソースコードです。下記の流れで処理を行っています。

  1. 認証、DriveのServiceを取得
  2. 処理済みのPDFファイルはファイル名で重複チェックし対象から除外する
  3. 変換対象のPDFのリストを作成
  4. 対象のPDFファイルを変換

詳細については後述します。

def full_to_half(val):
  """
  全角を半角に変換する
  ※OCR後のファイル名に含まれる英字が全角になってしまう問題への対応
  """
  return val.translate(str.maketrans({chr(0xFF01 + i): chr(0x21 + i) for i in range(94)}))

import os
import glob
from google.colab import auth
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload

# 認証
auth.authenticate_user()
# Driveの操作をするためのServiceを取得
drive_service = build('drive', 'v3')

# Colab上でマウントしたローカルパス
input_path = 'drive/My Drive/PDF/INPUT' # 入力(PDF)のディレクトリパス
output_path = 'drive/My Drive/PDF/OUTPUT' # 出力先のディレクトリパス

#####
# 処理済みのPDFファイルはファイル名で重複チェックし対象から除外する
####
# 再帰的にファイルを取得
files_o = glob.glob(output_path, recursive=True)
exist_filenames = ['']
for root, dirs, files_o in os.walk(output_path):
    for filename in files_o:
        # 全角を半角に変換、拡張子を除去
        exist_filename = full_to_half(filename).replace('.gdoc', '')
        # 存在するファイル名を追加
        exist_filenames.append(exist_filename)

#####
# 変換対象のPDFのリストを作成
####
# 再帰的にファイルを取得
files = glob.glob(input_path, recursive=True)
pdf_infos = []
for root, dirs, files in os.walk(input_path):
    for filename in files:
      #print(filename)
      # 存在するファイル名は対象外
      if full_to_half(filename) in exist_filenames:
        #print('存在する')
        pass
      else:
        # 拡張子がPDF
        if filename[-4:] == '.PDF' or filename[-4:] == '.pdf':
          #print('存在しない')
          filepath = os.path.join(root, filename) # Colab上のローカルファイルパス
          pdf_infos.append({
                'path': filepath,
                'name': filename
            })

#print('ファイル数: ' + str(len(pdf_infos)))

# Google DocumentsファイルのMIMEタイプ
MIME_TYPE = 'application/vnd.google-apps.document'

#####
# 対象のPDFファイルを変換
####
for pdf_info in pdf_infos:
  pdf_path = pdf_info['path']

  #print(pdf_path)

  pdf_filename = pdf_info['name']
  # OCR後のファイル名
  #print(pdf_filename)

  # 全角の英字を半角に変換
  pdf_filename = full_to_half(pdf_filename)

  body = {
      'name': pdf_filename,
      'mimeType': MIME_TYPE,
      'parents': ['出力先のDriveディレクトリID']
  }
  try:
    media_body = MediaFileUpload(pdf_path, mimetype=MIME_TYPE, resumable=True)

    drive_service.files().create(
        body=body,
        media_body=media_body,
    ).execute()
  except:
    print('エラー: Documentsファイルの作成に失敗しました。')
    print(pdf_path)

下準備

上記のコードを実行する前に下準備を行います。

Google Driveのマウント

ColabではGoogle Driveを仮想的にローカルファイルシステムとして扱えるようにするマウントの機能を備えています。Driveを操作しても良いのですが、GoogleAPIクライアントだとWebAPI経由となり処理に時間がかかるためパフォーマンスが低下します。そのため、処理速度を上げるためにも、できるだけマウントした中で処理を行うようにします。

Colab上でDriveをマウントするには、ランタイムに接続を行い、下記のアイコンを押下します。

すると以下のコードが挿入されますので、これを実行してください。

from google.colab import drive
drive.mount('/content/drive')

表示されたURLをブラウザで開き、その先の認証コードをコピーしてテキストボックスに貼り付けます。

これでマウントは完了です。

GoogleAPIクライアントのインストール

Python用のGoogleAPIクライアントをインストールしておきます。

!pip install google-api-python-client

実装

先述したソースコードの実装について解説します。

1. 認証、DriveのServiceを取得

GoogleAPIクライアントでDriveを操作するためにServiceオブジェクトを取得します。

Colabのauthを使って認証を行い、GoogleAPIクライアントでDriveのServiceオブジェクトを取得します。

from google.colab import auth
from googleapiclient.discovery import build

# 認証
auth.authenticate_user()
# Driveの操作をするためのServiceを取得
drive_service = build('drive', 'v3')

2. 処理済みのPDFファイルはファイル名で重複チェックし対象から除外する

今回は1箇所に変換後のファイルを格納します。また、途中で終了した場合やPDFが追加された場合の再実行を可能とするために重複チェックを行います。

仮想ローカルのルートディレクトリ内を再帰的に探索し、変数exist_filenames(配列)に存在するファイル名を順に追加します。

# 再帰的にファイルを取得
files_o = glob.glob(output_path, recursive=True)
exist_filenames = ['']
for root, dirs, files_o in os.walk(output_path):
    for filename in files_o:
        # 全角を半角に変換、拡張子を除去
        exist_filename = full_to_half(filename).replace('.gdoc', '')
        # 存在するファイル名を追加
        exist_filenames.append(exist_filename)

3. 変換対象のPDFのリストを作成

実行時に変換対象とするPDFのリストを作成します。
2の処理で取得した対象外のファイルを一致する場合はスキップします。一致しないPDFファイルの場合は新規追加分なので、処理対象のPDFとして変数pdf_infos(配列)に追加します。

# 再帰的にファイルを取得
files = glob.glob(input_path, recursive=True)
pdf_infos = []
for root, dirs, files in os.walk(input_path):
    for filename in files:
      #print(filename)
      # 存在するファイル名は対象外
      if full_to_half(filename) in exist_filenames:
        #print('存在する')
        pass
      else:
        # 拡張子がPDF
        if filename[-4:] == '.PDF' or filename[-4:] == '.pdf':
          #print('存在しない')
          filepath = os.path.join(root, filename) # Colab上のローカルファイルパス
          pdf_infos.append({
                'path': filepath,
                'name': filename
            })

4. 対象のPDFファイルを変換

3までの処理で抽出したリストを元に、PDFファイルを変換して行きます。

Drive Serviceオブジェクトのfiles().create().execute()でDriveに新しいファイルを作成します。その際、MIMEタイプにDocumentsの値を指定すると、自動的にOCR処理されたDocumentsファイルに変換してくれます。

create()のbodyパラメータに変換後のファイル名、MIMEタイプ、親ディレクトリのIDを指定します。
media_bodyパラメータにはMediaFileUpdateでGoogleへアップロードしたPDFファイルを指定します。

for pdf_info in pdf_infos:
  pdf_path = pdf_info['path']

  #print(pdf_path)

  pdf_filename = pdf_info['name']
  # OCR後のファイル名
  #print(pdf_filename)

  # 全角の英字を半角に変換
  pdf_filename = full_to_half(pdf_filename)

  body = {
      'name': pdf_filename,
      'mimeType': MIME_TYPE,
      'parents': ['出力先のDriveディレクトリID']
  }
  try:
    media_body = MediaFileUpload(pdf_path, mimetype=MIME_TYPE, resumable=True)

    drive_service.files().create(
        body=body,
        media_body=media_body,
    ).execute()
  except:
    print('エラー: Documentsファイルの作成に失敗しました。')
    print(pdf_path)

変換後のファイル名の英字が全角になる問題への対処

PDFファイルをOCR変換して出来上がったDocumentsファイルは、英字が全角になってしまいます。
これを以下のコードで調査しました。

chars = [
  'm',  # Documentsファイルからコピーした文字
  'm'  # 直打ちで入力した文字
]

# 全角(変換後のファイル名)
print(hex(ord(chars[0])))
# 半角
print(hex(ord(chars[1])))

# 全角英字を半角英字へ変換
print(hex(ord(chars[0].translate(str.maketrans({chr(0xFF01 + i): chr(0x21 + i) for i in range(94)})))))

実行結果

0xff4d
0x6d
0x6d

上記の実行結果より、変換後のファイル名は全角であること、半角への変換が可能であることがわかりました。

変換はこちらの記事を参考にさせていただきました。
【Python】一行で全角と半角を相互変換する(英字+数字+記号) - Qiita

おわりに

以上で、PDFファイルのOCR変換が実装できました。
ご参考になれば幸いです。

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

Numpyのeinsumを使って3次元配列の掛け算

知り合いに簡単に3次元配列の掛け算をする方法を聞かれ、調べてみたらNumpyのライブラリにアインシュタインの縮約記号を用いたeinsumというのがありこれを使えば楽にできそうなのでやってみました。

1x2x5の3次元行列と2x3x5の三次元行列をまず適当に2つ作ります。

A = 
\left(
\begin{matrix}
a_0 & a_1
\end{matrix}
\right)
, a_0 = 
\left[
\begin{matrix}
0 & 1 & 1 & 0 & 0
\end{matrix}
\right]
, a_1 = 
\left[
\begin{matrix}
0 & 1 & 0 & 0 & 1
\end{matrix}
\right]
W = 
\left(
\begin{matrix}
w_0 & w_1 & w_2 \\
w_3 & w_4 & w_5
\end{matrix}
\right)
, w_0 = 
\left[
\begin{matrix}
0 & 1 & 2 & 3 & 4
\end{matrix}
\right]
, w_1 = 
\left[
\begin{matrix}
5 & 6 & 7 & 8 & 9
\end{matrix}
\right]
...

これをnumpyを使って作成すると、

A = np.array([[[0,1,1,0,0],
               [0,1,0,0,1]]])

W = np.arange(30).reshape(2,3,5)

で出来ます。

このAの行列の形状(1,2,5)をアインシュタインの縮約記号で(i, j, k)で表します。
同じようにWの行列の形状(2,3,5)を(j, l, k)で表します。

この2つの行列を掛け算すると、(1,3,5)の行列になるはずなのでeinsumを使った式はこうなります。

R = np.einsum("ijk,jlk -> ilk",A,W)

print(R)
print(R.shape)

実行するとRはこうなります。

[[[ 0 17  2  0 19]
  [ 0 27  7  0 24]
  [ 0 37 12  0 29]]]

(1,3,5)

無事、1x3x5の3次元行列の結果になりました。

参考(英語):
- https://stackoverflow.com/questions/26089893/understanding-numpys-einsum

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

djangoのよく使うコマンド まとめ(初学者)

はじめに

自分自身djangoに取り掛かるに当たって必要なコマンドを調べたのでここにまとめます。

コマンド

以下 Mac os/Linuxでのコマンドになります。
アプリケーションの作成

python manage.py startapp sample

サーバーの立ち上げ

python manage.py runserver

仮想環境の立ち上げ 有効化

python3 -m venv env
source env/bin/activate

migrationファイルの作成

python manage.py makemigrations

DB migrationの実行

python manage.py migrate

データベースの管理者ユーザーを作成

python manage.py createsuperuser

おわりに

上記がよく使うコマンドになります。参考になれば幸いです。

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

matplotlibのスタイルをダークテーマにしたい

matplotlibはデフォルトでは背景が真っ白で, 長時間見ていると目が痛くなるから黒くしたい. しかし, スタイルシートをわざわざ自作するのも億劫である. 調べてみるとプリセットのスタイルシートが使えるとのことなので, 使い方を簡単に書き留めておこうと思う.

import

import matplotlib.pyplot as plt

スタイルシート一覧

plt.style.available

利用可能なスタイルシート一覧を配列として取得できる.
配列の中身は以下の通り.

['bmh',
 'classic',
 'dark_background',
 'fast',
 'fivethirtyeight',
 'ggplot',
 'grayscale',
 'seaborn-bright',
 'seaborn-colorblind',
 'seaborn-dark-palette',
 'seaborn-dark',
 'seaborn-darkgrid',
 'seaborn-deep',
 'seaborn-muted',
 'seaborn-notebook',
 'seaborn-paper',
 'seaborn-pastel',
 'seaborn-poster',
 'seaborn-talk',
 'seaborn-ticks',
 'seaborn-white',
 'seaborn-whitegrid',
 'seaborn',
 'Solarize_Light2',
 'tableau-colorblind10',
 '_classic_test']

黒い方がかっこいいので, dark_backgroundあたりが良さそう.

スタイルを適用する

plt.style.use('dark_background')

最初にこの一行でスタイルを適用したら, 後はいつも通りにグラフを描いたり画像を表示したりするだけ.

サインカーブを描いてみる

こういうときはサインカーブと相場は決まっているので, さっそく描いて確かめてみる.

import numpy as np

x = np.linspace(0, 2*np.pi, 200)
y = np.sin(x)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x, y)

dark_sin.png

良いと思う.

がしかし, 若干黒すぎる気もする.
この画像のファイル名がdark_sin.pngで罪深すぎるのも少し気になる.

簡単な自作スタイルシート

自作のスタイルシートは作らないつもりだったが, 少しだけいじってみる.

スタイルシートが入っているフォルダはpythonのフォルダからLib/site-packages/matplotlib/mpl-data/stylelib/と下っていけば見つかる. その中にdark_background.mplstyleというファイルがあるので, それを開く. 内容は以下の通り.

dark_background.mplstyle
# Set black background default line colors to white.

lines.color: white
patch.edgecolor: white

text.color: white

axes.facecolor: black
axes.edgecolor: white
axes.labelcolor: white
axes.prop_cycle: cycler('color', ['8dd3c7', 'feffb3', 'bfbbd9', 'fa8174', '81b1d2', 'fdb462', 'b3de69', 'bc82bd', 'ccebc4', 'ffed6f'])

xtick.color: white
ytick.color: white

grid.color: white

figure.facecolor: black
figure.edgecolor: black

savefig.facecolor: black
savefig.edgecolor: black


見ての通り, それぞれの項目に色が割り振られてあるだけで, それほど難しくはない.
このファイルに登場するすべてのblackを別のもう少しマイルドな黒に置換すれば, 求めるスタイルシートになりそうだ.
カラーコード一覧を見て適当な色を選ぶ.
2e2e2eあたりがちょうど良さそうなので, すべてのblack2e2e2eに置換し, gray_background.mplstyleなどのファイル名で同じフォルダに保存する.

gray_background.mplstyle
# Set 2e2e2e background default line colors to white.

lines.color: white
patch.edgecolor: white

text.color: white

axes.facecolor: 2e2e2e
axes.edgecolor: white
axes.labelcolor: white
axes.prop_cycle: cycler('color', ['8dd3c7', 'feffb3', 'bfbbd9', 'fa8174', '81b1d2', 'fdb462', 'b3de69', 'bc82bd', 'ccebc4', 'ffed6f'])

xtick.color: white
ytick.color: white

grid.color: white

figure.facecolor: 2e2e2e
figure.edgecolor: 2e2e2e

savefig.facecolor: 2e2e2e
savefig.edgecolor: 2e2e2e


自作のスタイルを適用する

シェルを開きなおし, plt.style.availableで確認すると, gray_backgroundが新たに追加されている.
例のごとくサインカーブをプロットしてみる.

import numpy as np

x = np.linspace(0, 2*np.pi, 200)
y = np.sin(x)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x, y)

gray_sin.png

これでだいぶグレーになった.

このように自作スタイルを適用したい場合も, 基本的にはプリセットのスタイルシートを参考に, 自分好みにマイナーチェンジすれば, それほど労力はかからないだろう.

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

matplotlibをダークテーマにしたい

matplotlibはデフォルトでは下の画像のように背景が真っ白で, 長時間見ていると目が痛くなるから別の色に変更したい. しかし, スタイルシートをわざわざ自作するのも億劫である. 調べてみるとプリセットのスタイルシートが使えるとのことなので, 使い方を簡単に書き留めておこうと思う.

default_sin.png

import

import matplotlib.pyplot as plt

スタイルシート一覧

plt.style.available

利用可能なスタイルシート一覧を配列として取得できる.
配列の中身は以下の通り.

['bmh',
 'classic',
 'dark_background',
 'fast',
 'fivethirtyeight',
 'ggplot',
 'grayscale',
 'seaborn-bright',
 'seaborn-colorblind',
 'seaborn-dark-palette',
 'seaborn-dark',
 'seaborn-darkgrid',
 'seaborn-deep',
 'seaborn-muted',
 'seaborn-notebook',
 'seaborn-paper',
 'seaborn-pastel',
 'seaborn-poster',
 'seaborn-talk',
 'seaborn-ticks',
 'seaborn-white',
 'seaborn-whitegrid',
 'seaborn',
 'Solarize_Light2',
 'tableau-colorblind10',
 '_classic_test']

黒い方がかっこいいので, dark_backgroundあたりが良さそう.

スタイルを適用する

plt.style.use('dark_background')

最初にこの一行でスタイルを適用したら, 後はいつも通りにグラフを描いたり画像を表示したりするだけ.

サインカーブを描いてみる

こういうときはサインカーブと相場は決まっているので, さっそく描いて確かめてみる.

import numpy as np

x = np.linspace(0, 2*np.pi, 200)
y = np.sin(x)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x, y)

dark_sin.png

良いと思う.

がしかし, 少し黒すぎる気もする.
この画像のファイル名がdark_sin.pngで罪深すぎるのも若干気になる.

簡単な自作スタイルシート

自作のスタイルシートは作らないつもりだったが, 少しだけいじってみる.

スタイルシートが入っているフォルダはpythonのフォルダからLib/site-packages/matplotlib/mpl-data/stylelib/と下っていけば見つかる. その中にdark_background.mplstyleというファイルがあるので, それを開く. 内容は以下の通り.

dark_background.mplstyle
# Set black background default line colors to white.

lines.color: white
patch.edgecolor: white

text.color: white

axes.facecolor: black
axes.edgecolor: white
axes.labelcolor: white
axes.prop_cycle: cycler('color', ['8dd3c7', 'feffb3', 'bfbbd9', 'fa8174', '81b1d2', 'fdb462', 'b3de69', 'bc82bd', 'ccebc4', 'ffed6f'])

xtick.color: white
ytick.color: white

grid.color: white

figure.facecolor: black
figure.edgecolor: black

savefig.facecolor: black
savefig.edgecolor: black


見ての通り, それぞれの項目に色が割り振られてあるだけで, それほど難しくはない.
このファイルに登場するすべてのblackを別のもう少しマイルドな黒に置換すれば, 求めるスタイルシートになりそうだ.
カラーコード一覧を見て適当な色を選ぶ.
2e2e2eあたりがちょうど良さそうなので, このファイルをコピーし, すべてのblack2e2e2eに置換したものをgray_background.mplstyleなどのファイル名で同じフォルダに保存する.

gray_background.mplstyle
# Set 2e2e2e background default line colors to white.

lines.color: white
patch.edgecolor: white

text.color: white

axes.facecolor: 2e2e2e
axes.edgecolor: white
axes.labelcolor: white
axes.prop_cycle: cycler('color', ['8dd3c7', 'feffb3', 'bfbbd9', 'fa8174', '81b1d2', 'fdb462', 'b3de69', 'bc82bd', 'ccebc4', 'ffed6f'])

xtick.color: white
ytick.color: white

grid.color: white

figure.facecolor: 2e2e2e
figure.edgecolor: 2e2e2e

savefig.facecolor: 2e2e2e
savefig.edgecolor: 2e2e2e


自作のスタイルを適用する

シェルを開きなおし, plt.style.availableで確認すると, gray_backgroundが新たに追加されている.
例のごとくサインカーブをプロットしてみる.

import numpy as np

x = np.linspace(0, 2*np.pi, 200)
y = np.sin(x)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x, y)

gray_sin.png

これでだいぶグレーになった.

このように自作スタイルを適用したい場合も, 基本的にはプリセットのスタイルシートを参考に自分好みにマイナーチェンジしていけば, それほど労力はかからないだろう.

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

【Python】現在のディレクトリの確認,ディレクトリの移動

【Python】現在のディレクトリ(フォルダ)の確認,ディレクトリの移動

現在のディレクトリの確認

os.getcwd()で現在のディレクトリが取得できます。

import os

path = os.getcwd() # 現在のディレクトリ取得
print(path)

# C:\Users\hiro22

ディレクトリの移動

os.chdir(r'指定ディレクトリのパス')で指定ディレクトリに移動できます。
※ディレクトリの指定で「先頭にrをつけるか」,「(指定ディレクトリパス)\の部分の全てを\に変えるか」をしないとエラーになると思います。(特殊文字の認識の問題らしいです)

import os

os.chdir(r"C:\Users\hiro22\Desktop\test") # ディレクトリの移動 
path= os.getcwd() # 現在のディレクトリ取得
print(path)

# C:\Users\hiro22\Desktop\test
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

joblib,pickleでデータの保存&読み込み

joblib,pickleでデータの保存と読み込み

よく使うのでメモ用に残しておきます。

joblibおよびpickleは色んなデータをイイ感じに保存できるライブラリです。textとかcsvとかだけでなく、学習済みmodelの保存とかでも使えます。あと、読み込みとか書き出しの速度が速いような気がします。(ただメモリは結構使うみたいです)

基本的には、pickleよりjoblibを使う方がメモリ的によろしいみたいです。

import pandas as pd

arr = ['a','b','c','d','e']
df = pd.DataFrame({'data':arr})
df.head(5)

# data
#0  a
#1  b
#2  c
#3  d
#4  e

joblibでデータの保存 & 読み込み

import joblib

# データの保存
joblib.dump(df,'test_jb.pkl', compress=3)
# データの読み込み
load_df = joblib.load('test_jb.pkl')
load_df.head()

# data
#0  a
#1  b
#2  c
#3  d
#4  e

pickleでデータの保存 & 読み込み

import pandas as pd

# データの保存
df.to_pickle('test_pk.pkl')
# データの読み込み
load_df2 = pd.read_pickle('test_pk.pkl')
load_df2.head()

# data
#0  a
#1  b
#2  c
#3  d
#4  e

「data」の部分を「学習済みmodel」に変えれば、modelもそのまま保存できます。

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

NumPy配列の列を抽出する方法いろいろ

2次元配列の列を取り出す方法のいろいろ.

import

import numpy as np

配列の生成

まずは適当に5x4の配列を生成

a = np.arange(5*4).reshape([5, 4])
print(a)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]
#  [12 13 14 15]
#  [16 17 18 19]]

特定の1列を抽出する

# 2列目のみ
b = a[:, 2]
print(b)
# [ 2 6 10 14 18]

a[row, column]とすると, rowの部分で行の指定, columnの部分で列の指定を行う.
今回は列を取り出したいので, rowの部分は常に:とする. :のみ記述することで, 行に関しては特に指定しないという意味になる. つまりa[:, 2]は, 「すべての行から, インデックスが2の要素だけください」ということになる.

連続する複数の列を抽出する

1, 2列目や0~2列目など, 連続する複数の列を取り出す.

# 1, 2列目
b = a[:, 1:3]
print(b)
# [[ 1  2]
#  [ 5  6]
#  [ 9 10]
#  [13 14]
#  [17 18]]

1:3は1以上3未満を意味するため, 1~2列目が取り出せる.
1::3のように指定すれば, 1列目以上や3列目未満の列がすべて取得できる.

# 1列目~
b = a[:, 1:]
print(b)
# [[ 1  2  3]
#  [ 5  6  7]
#  [ 9 10 11]
#  [13 14 15]
#  [17 18 19]]

# 0~2列目
b = a[:, :3]
print(b)
# [[ 0  1  2]
#  [ 4  5  6]
#  [ 8  9 10]
#  [12 13 14]
#  [16 17 18]]

偶数列, 奇数列など

# 4x8の配列を生成
a = np.arange(4*8).reshape([4, 8])
# [[ 0  1  2  3  4  5  6  7]
#  [ 8  9 10 11 12 13 14 15]
#  [16 17 18 19 20 21 22 23]
#  [24 25 26 27 28 29 30 31]]

# 偶数列
b = a[:, ::2]
print(b)
# [[ 0  2  4  6]
#  [ 8 10 12 14]
#  [16 18 20 22]
#  [24 26 28 30]]

# 奇数列
b = a[:, 1::2]
print(b)
# [[ 1  3  5  7]
#  [ 9 11 13 15]
#  [17 19 21 23]
#  [25 27 29 31]]

このように, 基本的にリストの操作方法に則っているため, 倍数や逆順での取得も可能.

# 後ろから3の倍数の列
b = a[:, ::-3]
print(b)
# [[ 7  4  1]
#  [15 12  9]
#  [23 20 17]
#  [31 28 25]]

# 1列目以上7列目未満の一列飛ばし
b = a[:, 1:7:2]
print(b)
# [[ 1  3  5]
#  [ 9 11 13]
#  [17 19 21]
#  [25 27 29]]

不規則に複数の列を抽出する

個人的にはここからが本題.
1, 5, 6列などのように, 不規則に列を取り出したいときがある.
ひと手間増えるが, 列の数と同じ長さのフィルターを用意することで実現できる.

# インデックス1, 5, 6の値がTrue, それ以外がFalseの長さ8のリスト
f = [False, True, False, False, False, True, True, False]

b = a[:, f]
print(b)
# [[ 1  5  6]
#  [ 9 13 14]
#  [17 21 22]
#  [25 29 30]]

# boolean型の1x8の零行列を生成して, 欲しい列のインデックスの値だけTrueに変えるパターン
f = np.zeros(8, dtype=bool)
columns = [1, 5, 6]
f[columns] = True

b = a[:, f]
print(b)
# [[ 1  5  6]
#  [ 9 13 14]
#  [17 21 22]
#  [25 29 30]]

numpyで扱う配列は列の数が多い場合がほとんどだと思うので, 二つ目の方法がメインになってくると思う.
例ではnp.zerosを使用しているが, 状況によってはnp.onesで要素がすべてTrueの配列を作ってから, いらない列だけFalseに変える方が楽かもしれない.

おわりに

あまり話を広げすぎてもわかりづらいと思い, 今回は列のみに絞って解説したが, 列同様に行も指定することで特定の行の特定の列を取り出すこともできる. 3次元以上の場合もこれらの方法を応用することで, 欲しい要素を抽出できる.

一番最後に解説した零行列を作って列を取り出す方法は, 自分としては結構綺麗にできたと思うけど、他にもっと楽な方法がありそうな気もする.

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

Django~ブラウザに表示させてみよう~

はじめに

今回はDjnagoで「Hello world」をブラウザに表示させる手順を書いていきます。
Djangoを初めて触れる人は、下の記事に目を通してもらえるとスムーズに進められると思います。
PycharmでDjangoでアプリケーションを作成する手順~準備編~
Django~settings.py編~

プロジェクト全体のディレクトリやファイルは下記のようになっています。

Pycharmプロジェクト
      |
      |___djangoプロジェクトディレクトリ
      |
      |___djangoアプリケーションディレクトリ__templatesディレクトリ
      |
      |___manage.py
      |
      |___その他のファイル類

それではいきましょう!

プロジェクトの「urls.py」を編集

まずdjangoアプリケーションディレクトリにある、「urls.py」に移動します。
おそらくこんな感じのものが書かれているはずです。

from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
]

これを下のように追記してください。

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('app/', include('todo.urls')),
]
#ここでの「'app/'」はアプリケーション名を入れることが多いので、各自好きなものを入れてください。

「include」とすることで、URLの最後に「app/」と入力すると、アプリケーションの方の「urls.py」に飛んでくれます。
なぜ2つあるのかというと、プロジェクトとアプリケーションで「urls.py」を分けると、コードが見やすくなるためです。

アプリケーションの「urls.py」の編集

次にアプリケーションの「urls.py」に書き込んでいきます。

そもそも「urls.py」とはナンジャいという方もいると思います。
一言で言うと『ブラウザに表示したいものの材料が書かれている指示書』です。
お母さんから買い物を頼まれ、その時に渡された「何を買うかのメモ」とイメージしておいてください。

デフォルトでは用意されていないので、作っていない人は作っていきましょう。

#アプリケーションディレクトリに移動
cd アプリケーションディレクトリ名

#urls.pyファイルの作成
touch urls.py

これでOKです。

作ったばかりで中身は空っぽなので、早速書いていきましょう。

from django.urls import path
from .views import HomeView   #views.pyから「HomeView」クラスを読み込んでいる。

urlpatterns = [
    path('home/', HomeView.as_view())
]
#「home/」はURl部分に入力するもの。
#「HomeView.as_view()」は、YRL部分に「home/」と入力することでviews.pyの「HomeView」を呼び出す。

views.pyと言われてもなんのこっちゃという感じだと思うので、次の章で解説していきます。

「view.py」の編集

views.pyはurls.pyからの指示通りに必要な材料をかき集めてくる場所です。
お母さんから渡されたメモ通りに食材を買ってくる子供が「view.py」です。

早速追記していきましょう。
デフォルトでは下のように書かれているはずです。

from django.shortcuts import render

# Create your views here.

まずは。「# Create your views here.」この部分を削除して、次のように追記していきます。

from django.shortcuts import render
from django.views.generic import TemplateView #テンプレート表示に特化したもののインポート

class HomeView(TemplateView):     #さっきurls.pyに読み込んだ「HomeView」クラス
    template_name = 'home.html'   #利用するHTMLファイルの指定

「HTMLファイル」の編集

ではここからHTMLファイル編集していきましょう。
まずtemplatesディレクトリに移動します。

cd templates

templatesディレクトリの中に、HTMLファイルを作成していきます。

touch home.html   #〇〇.htmlと作成してください

作成すると中身は空っぽなので、書いていきましょう。
まず「!」とタブキーを同時に押します。
そうすると下のようなものが出てきます。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
</body>
</html>

これが出て来なかった場合はコピペしてください。
その後下のように追記+変更してください。

<!DOCTYPE html>
<html lang="ja">    #日本語に
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>Hello World</h1>   #追記
</body>
</html>

これで準備は万端です!

実行

では実行していきましょう!

python manage.py runserver
http://127.0.0.1:8000/」

と出てくると思うのでクリックするとブラウザに飛びます。
そこで「Hello World」と表示できていれば完璧です!

終わりに

今回は「Hello World」を表示させる手順を紹介しました。
まずは小さなことから経験してどんどん成長していきましょう!
これからもアウトプットとして記事を書いていくのでよければ見ていってください。

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

日本初の英語でのデータサイエンスのブートキャンプがローンチ

データは最新にして最大の資産だ

世界屈指のコーディングブートキャンプ Le Wagonは、高度な機械学習とデータサイエンスの9週間集中Pythonトレーニングを東京にて開講する事を正式に決定いたしました。 このコースは英語にて行われます。

2013年パリにてスタートしたLe Wagonは、世界でナンバー1のコーディングブートキャンプに選出され、現在では世界22ヵ国39都市における多くの学生から、最高のテック教育を提供するブートキャンプとして評価されています。東京では2016にスタートし、既に250人以上の生徒がフルタイム、もしくはパートタイムのウェブ開発コースを卒業しました。

日本に於いて増大するテック教育のニーズにお答えすると共に、現在に至るまでに培ってきた実績ある教育方法を活かして、Le Wagonは新たにデータサイエンスブートキャンプの開講を決定いたしました。長期・短期のコーディングブートキャンプに於いて世界最高峰であるLe Wagonがデータサイエンスの授業を提供するまでに、発足から7年も待ったのには理由があります。「Le Wagonが発足した2013年当時は、データの分野は十分に完成されていなかったのです。今日に於いてはこの職種はより整理され、求められるスキルも標準化されています」と元Googleのエンジニアであり、Le Wagonの3人の共同創業者の1人・最高技術責任者であるSebastien Saunierは述べています。

現在は合計7,500人の卒業生が存在し、Le Wagonは2023年までにデータサイエンスを習得した卒業生を7,000人輩出する事を目標としています。

64566217_1094494204085208_6678161377724465152_o.jpg
日本での第一回のデータサイエンスブートキャンプは2020年10月12日~12月11日を予定しています。このコースは英語にて行われます

絶大な需要のあるスキルセット

9週間にも及ぶ濃密な学習の後、参加者は非常に高度な技能を手に入れて卒業します。卒業する頃には、データの収集・保管・精査・探索・変換や、データ予測・高度な機械学習・深層学習モデルを習得している事になります。

プログラムを卒業してすぐに、ジュニアデータサイエンティストや、データアナリスト、データエンジニアとしてデータチームに所属して仕事をすることができるでしょう。

データサイエンティストブートキャンプについて https://www.lewagon.com/tokyo/data-science-course/full-time

データサイエンティストになる方法

この新しいブートキャンプは、今まで成功したLe Wagonの教育アプローチを踏襲したカリキュラムになっています。9週間のうち、90%の時間は実践的に本物のデータサイエンスプロジェクトに関わり、手を動かして学びます。これにより、データサイエンスのプロジェクトの立ち上げに必要なスキルを得ることができ、卒業直後から即戦力として就職しやすくなります。

このブートキャンプでは、データサイエンス基礎・機械学習・データエンジニアリング・深層学習・(そして、Le Wagonの御家芸である)擬似プロジェクトの5つに分かれたモジュールを、理論的な知識と業界標準のツールを習得しながら学ぶことができます。.

このコースに応募する際には数学とプログラミングの知識は必須です。ブートキャンプの応募者には、事前面接と40時間の予習課題があります。

このカリキュラムはデータアナリティクスとデータサイエンスのプロの教師陣によって行われます。

東京での最初のセッションの応募は既に始まっており、最初の9週間セッションは2020年10月12日にキックオフを迎えます。

カリキュラム概要

  • データサイエンスツール: Jupyter Notebook, Pandas, データ視覚化
  • データサイエンスにおける数学: 統計・確率・線形代数
  • 機械学習: 線形回帰, scikit-learn, 過剰適合
  • プロダクション環境の機械学習システム: Google Cloud Platform
  • ベストプラクティス: GitHub, データプロジェクトマネジメント
  • 深層学習: Keras, ニューラル・ネットワーク, コンピュータビジョン, 自然言語処理 (NLP)
  • 高度なデータサイエンスプロジェクト

Le Wagonについて

Le Wagonは5大陸39都市にて展開し、7,500名以上の卒業生を輩出した世界屈指のコーディングブートキャンプです。フランス、パリで2013年に創業以来、瞬く間に世界でNo.1の評価を受けるコーディングブートキャンプに成長しました。1,500人以上の卒業生が高評価のレビューをし、今日では世界で最も権威あるコーディングブートキャンプの一つに君臨しています。多岐にわたるコースやイベントを、高度なデジタル教育を求める個人や組織に行い、Le Wagonはコーディングを通して何万人もの人々の人生を変えるお手伝いをしてきました。
日本においては、Le Wagonは2016年に初めての9週間のフルタイムWeb開発コースを開講し、続いて24週間のパートタイムプログラムを2019年に開講しました。過去3年間で250人以上の受講者があり、卒業生は日本の大手テック企業にてWeb開発者やプロマネ、デザイナーとして仕事をしています。Le Wagon東京は2016年以来、150以上のイベントを開催し、4,000人以上のコミュニティを誇る、テックイベントの最大手でもあります。

Le Wagon 東京キャンパスについてもっと詳しく知りたい方はこちら:
https://www.lewagon.com/tokyo

2013年発足以来のLe Wagonの功績:

  • コーディングブートキャンプにおいて世界1位を獲得 (coursereport や Switchup)
  • 世界39都市で開催中
  • 300人以上のメンターと、500人以上のパートナー
  • 7,000人以上の人材輩出
  • 卒業生ネットワークの約30%が女性
  • 150社以上のスタートアップが卒業生によって設立
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

python dictとsorted関数について

pythonの勉強をしていると、sorted関数とはは避けて通れないものです。しかもよく忘れるので、メモっておきますね。ここは辞書に対してsorted関数を使っています。
気をつけるべきポイントはlambdaの後ろのyやxは別に何でもいいということです。例えば、lambda aaa:aaa[0]としても構わないのです。なぜなら、ここのyやxはただ前のlistの(例ではlistA, listB, listCのことです)中身なのですから。ここさえ押さえておけば大丈夫そうですよね。
以下の例を見てみてください。

listA = [3, 6, 1, 0, 10, 8, 9]
print(sorted(listA))
#结果1
#[0, 1, 3, 6, 8, 9, 10]

listB = ['g', 'e', 't', 'b', 'a']
print(sorted(listB))
print(sorted(listB, key=lambda y: y[0]))
#结果2
#['a', 'b', 'e', 'g', 't']
#['a', 'b', 'e', 'g', 't']
listC = [('e', 4), ('o', 2), ('!', 5), ('v', 3), ('l', 1)]
print(sorted(listC, key=lambda x: x[1]))
#结果3
#[('l', 1), ('o', 2), ('v', 3), ('e', 4), ('!', 5)]

sort、sortedの違いについて:
1. sortはリストの関数であるのに対し、sortedはlistのみならず、辞書dictなどのすべてのイテラブルに対して使えるのだ。
2. sortはもともとのリストを操作して、そのリストを変形させるのに対し、sortedはもともとの対象に手を加えず、新たにlistを作成してそれを戻すという作業の流れの違いはあるので、ご注意を。

さてさてまたね。

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

python dictとsortedメソッドについて

pythonの勉強をしていると、sortedメソッドとはは避けて通れないものです。しかもよく忘れるので、メモっておきますね。ここは辞書に対してsortedメソッドを使っています。
気をつけるべきポイントはlambda関数の後ろのyやxは別に何でもいいということです。例えば、lambda aaa:aaa[0]としても構わないのです。なぜなら、ここのyやxはただ前のlistの中のイテレーター(例ではlistA, listB, listCのことです)中身なのですから。ここさえ抑えておけば大丈夫そうですよね。
以下の例を見てみてください。

listA = [3, 6, 1, 0, 10, 8, 9]
print(sorted(listA))
#结果1
#[0, 1, 3, 6, 8, 9, 10]

listB = ['g', 'e', 't', 'b', 'a']
print(sorted(listB))
print(sorted(listB, key=lambda y: y[0]))
#结果2
#['a', 'b', 'e', 'g', 't']
#['a', 'b', 'e', 'g', 't']
listC = [('e', 4), ('o', 2), ('!', 5), ('v', 3), ('l', 1)]
print(sorted(listC, key=lambda x: x[1]))
#结果3
#[('l', 1), ('o', 2), ('v', 3), ('e', 4), ('!', 5)]

sort、sortedの違いについて:
1. sortはリストのメソッドであるのに対し、sortedはlistのみならず、辞書dictなどのすべてのイテレーター対象に対して使えるのだ。
2. sortはもともとのリストを操作して、そのリストを変形させるのに対し、sortedはもともとの対象に手を加えず、新たにlistやdictを作成してそれを戻すという作業の流れの違いはあるので、ご注意を。

さてさてまたね。

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

Jupyter Notebook メモ

Jupyter notebookの機能等について備忘録。

Markdownセルへの画像の挿入

挿入する画像を保存したうえで、パスとして指定。例えば、

<img src="plots/EMmanifold_SEpoincare.png" alt="Drawing" style="width: 600px;"/>

もしくは

![EMmanifold_SEpoincare.png](attachment:EMmanifold_SEpoincare.png)

前者でやると画像のサイズをpxで調節できるため便利。
image.png

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

PythonとSeleniumでGoogle Chromeを動かしてみる

PythonとSeleniumでGoogle Chromeを動かしてみる

サマリ

試した環境

  • OS: macOS Catalina 10.15.5
  • Python:3.8.0
  • Google Chrome:83.0.4103.116
  • webdriver:ChromeDriver 83.0.4103.39

インストール

Pythonのライブラリをインストール

pip install -U selenium

ブラウザドライバーをインストール

ドライバーは使っているブラウザバージョンに合わせて必要なものをDLします。
ブラウザをアップデートしていてもドライバーの最新版をインストールすればいいわけではありませんでした。
(よく見たらバージョンが違ったのでご注意を)
わたしはプログラムを実行するディレクトリと同じ場所に置きました。

vaivailx@MacBook-Pro-2 selenium_test % tree.
├── chromedriver
├── memo.md
└── sample.py

0 directories, 3 files
vaivailx@MacBook-Pro-2 selenium_test %

以下は同じMacでも人によって違うかも環境によるかも。ダウンロードしたものは実行できませんみたいな文言がでたらやってみてください。
ドライバーをDLして解凍したあと、「システム環境設定」の「セキュリティとプライバシー」を開いておく。
解凍したファイルを実行すると、「ダウンロードしたアプリケーションの実行許可」の項目に実行を許可するかどうか出てくるので許可する。

サンプルプログラムを実行

公式のチュートリアルにはdriverを置いている場所にパスを通せって書いています。

ただ、ドライバークラスのインスタンス生成時にドライバーを置いているパスを渡せばいけるようだったので、パス指定でやってみました。

from selenium import webdriver

browser = webdriver.Chrome(executable_path="./chromedriver")
browser.get('http://seleniumhq.org/')

動いた!

動作結果.png

seleniumでブラウザ操作するとき、chromeだと「Chromeは自動テスト ソフトウェアによって制御されています。」ってでるんですね。

知らなかった。

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

暇なので『RPAツール』を作る #2     開発環境編

はじめに

皆さん、お久しぶりです。enp(えん)と申します。トマトが好きです。
この記事は『RPAツール』を作ろうとする人の進捗報告になります。
RPAやRPAツールの作り方が書いてあるものではございませんので、ご了承ください。(もしかしたら、ソースは少しだけ載せるかもしれません。気分次第です)
今回はRPAツールの『開発環境』を『なぜ投稿が一ヶ月もかかってしまったのか』というところも交えてお話しできればと思います。
長くなりそうですが、お付き合いいただければ幸いです。誰かに話したいぐらい苦労しました。

開発環境って?

皆さん。

開発環境って知ってますか?

はい。普通そんなこと聞いたら殴られます。そのぐらい基本的な言葉です。
少なくともココはQiitaですからね。そんなこと説明しなくても分かる人が多いと思います。
ですが、今日からプログラミングへの道を進まれる方が見ているかもしれないので、少しだけお話しします。
初心者の皆さん。多分、この記事は何かの参考にならないと思います! 私も初心者同然なので。

さて、開発環境とは何か?
簡単に言えば、開発を行う上で必要なヤツ全部を指します。
ソフトウェアの開発なら、プログラミング言語やライブラリなどのことですね。テキストエディタやOS、PCのスペックなども含まれます。
では、開発環境が悪いとどうなってしまうのでしょうか?
一つの例ではありますが、開発がしにくかったり、開発したアプリが遅い原因になったりします。
ですので、開発環境はしっかりと考えましょう。

私の開発環境

前の項目では、開発環境についてお話ししました。この項目では私が構築した開発環境をお話しします。
私が構築したと言っていますが、大層な代物ではありません。

RPAツール開発環境

  • OS
    • Windows 10
  • プログラミング言語
    • Python
  • 使用するライブラリ
    • openpyxl
    • selenium
    • ChromeDriver
    • kivy
  • テキストエディタ
    • NeoVim

こんな感じです。CPUやメモリに関しては省かせて頂きました。
また、ライブラリの欄にライブラリでないものが載っているかもしれませんが、分類するのが面倒でした。
これからライブラリなどが増えるかもしれませんが、その時はご報告いたします。

そもそもAutomagica使わないの?

前の項目では私の開発環境をお話しました。この項目ではちょっと脱線します。
え? 脱線早くない? と思うかもしれませんが、ちょっと話しておきたいのでご了承ください。

RPAツールでPythonを使うと聞いて、もしかしたら『Automagica』を思い浮かべた方がいるかもしれません。
AutomagicaPythonでRPAが作れちゃうフリーのプラットフォームです。私が用いるseleniumなどもAutomagicaに入っています。
Automagicaを使えばGUIを出すことができますし、RPAを作ることができます。RPAツールを作ることだってできるかもしれません。
え? じゃあ、使えばいいじゃん。そう思いますよね? ですが、私は使いませんでした。
理由は自身のスキルアップのためです。
Automagicaを使うと、開発環境を整える作業が簡単に終わります。それは良いことなのですが、自分のスキルとしては身に付きません。なので、使いませんでした。
また、これからはなるべく難しい道を選んでいこうと考えておりますので、ご理解のほどよろしくお願いいたします。

ようやく開発環境を細かく紹介

前の項目では、Automagicaの存在について語りました。この項目ではようやく開発環境について選んだ理由をお話していきます。

ITEM.1 『OS:Windows 10』

理由として一番大きいのは、持ってたからです。また、会社にあるOSと言えばWindowsみたいな偏見から選びました。(Excelとか使う人以外はMacかもしれない)
しかし、実は最初Ubuntuで開発しようと考えていました。理由はWindowsでLinuxコマンドを使うには、Ubuntuを使うやり方が簡単だったからです。
では、なぜUbuntuを断念したのか? それはあとで話します。

ITEM.2 『プログラミング言語:Python』

選んだ理由はRPAツールを開発するうえで一番やりやすそうな言語だったからです。ブラウザやxlsxファイルを操作できるライブラリなどが簡単に見つかったので使うことにしました。
また、多く使われている言語なので触っておきたいという気持ちもありました。
家にパーフェクトPythonがあったからという理由も微レ存。

パーフェクトPython

ITEM.3 『使用するライブラリ:openpyxl、selenium、ChromeDriver』

この三つはブラウザを操作したり、xlsxファイルを操作するためのものです。
選んだ理由は単純で、検索結果で一番最初に出てきたヤツら詰め合わせセットです。
とりあえず入れてみた状態なので、不都合があれば随時追加・変更予定です。
(現時点でChromeの操作が遅いような気がします。他に良いものってあるのでしょうか?)

ITEM.4 『使用するライブラリ:Kivy』

KivyはGUIのライブラリです。選んだ理由はオープンソースライブラリだからです。
開発が終わった後のことを考えて、ライセンス的に一番問題がなさそうなものを選びました。
しかし、コイツが記事の投稿を一ヶ月も遅らせる元凶となるとは......。この話も後で!

ITEM.5 『テキストエディタ:NeoVim』

好きだから! CUIって良いですよね。
まぁ、テキストエディタからコマンドプロンプトやPowerShellへ移動する手間を省きたかったという理由もあります。
プログラムをコンパイル・実行するのは基本コマンドプロンプトやPowerShellで行います。
なので、なるべくコマンドプロンプトやPowerShellで動くテキストエディタが使いたかったのです。
VSCordなどは移動必要ないんですが......。こうなってくると好みの問題ですね。

以上で紹介は終わりです。激ショボですが、一応色々考えて環境を整えたつもりです。

立ちはだかる最大の壁『Kivy』

さて、開発環境の紹介も終わりました。しかし、忘れてはいけません。

『暇なので『RPAツール』を作る #1』は5月に投稿されております。一か月以上前です。

サボってたん? お前、サボってたん? そう言われても仕方がないでしょう。
ですが、私は声を高らかにして言いたい!

サボってたら余計暇になるわ!

コロナ禍で暇に拍車がかかっているというのに、サボっていては本末転倒です。暇すぎて昇天しちゃいます。
では私は一ヶ月の間、何をしていたのでしょうか?
実はUbuntuにKivyのインストールをひたすら繰り返していました
理由は簡単。Kivyに動く気配がなかったからです。
動かない理由も簡単です。実行したら以下のエラーを吐きます。

egl_rpi - ImportError: cannot import name bcm

そりゃ、必要なファイル読み込めねぇなら動かんわ。
他にもエラー文はありましたが、必要なファイルをインポートできなければいつまで経っても動きません。
そこで、まずは同じような状況に陥っている人がいないか調べてみました。
すると、以下のサイトに行き当たります。

"ImportError: cannot import name bcm" error with running basic kivy app in ubuntu 15.04

エラー内容もほぼ一緒です。なので、ここに書かれた内容を頑張って全部試しました。
SDL2関連の確認をし、cythonとkivyのバージョンも確認し、公式通りにインストールを行いました。
その他いろいろ試しましたが、全滅。
改善の兆しを一ミリも感じることなく全て失敗です。
この過程で、使っていたVimがぶっ壊れてNeoVimに移行するという事件も起きました。
潔く他のGUIライブラリへ移行しようとしましたが、これもまた全滅。
エラーのエレクトリカルパレードを見ている気分でした。エラーのエレクトリカルパレードなんて煽り以外のなにものでもありません。
どうやら、GUIライブラリの神様は私をお見捨てになられたようです。
悲しみを背負いPCを閉じようとしたその時、ふと私は気づきました。

Kivyってオープンソースやん

そうです。最大の長所を完全に忘れていました。
Kivyはディレクトリの構成からプログラムソースまですべて閲覧することができます。
そこで、私は自分のPCにあるKivyとオープンソースとして公開されているKivyを見比べることにしました。
そして、ようやく進展がありました。
kivy/lib/vidcore_liteにbcm.pyxとegl.pyxが存在しないということに気づいたのです。

そりゃ、参照してるヤツ無きゃエラーも出るわ

というわけで、足りないソースをGitHubから持ってきてコピー。意気揚々とサンプルコードを実行。

egl_rpi - ImportError: cannot import name bcm

嫌だぁぁぁぁぁぁぁぁっ!!!

追加したのに! 正しい所に正しいソースを追加したのに!
GUIライブラリの神様はそうそう甘くありませんでした。
どうやら、Ubuntuへ導入する際にコンパイルを同時に行っているらしく、後から追加しただけでは実行してくれない模様。
もちろん私のPCにあるkivyのwhlファイルをunzipコマンドで見ても中にbcm.pyxとegl.pyxはありません。
なんてこったい!
万策尽きるとはこのこと。完全に解決策を見失いました。
こうなってはもう方法は一つしかありません。

そう。他力本願です。

他人の力に頼らないとやってられません。疲れ果てミイラになります。
というわけで、友達にこれまでの経緯を話し助けを乞いました。
そして、友達が一言。

友達「Windowsじゃダメなの?」

私「え? 天才?」

この時の私にOSを変えるという発想は皆無でした。ですが、思うところもあります。
OS変えただけで本当に動くの?
少々疑いながらWindowsにKivyを導入し、サンプルコードを実行します。
Kivy's GUI

動いたぁぁぁぁぁぁぁぁっ!!!

その瞬間、私は流れるようにUbuntuを消しました

以上がこの一ヶ月に起こった出来事です。いやぁ、話せて満足
開発環境を整える作業でここまで躓くとは思っていませんでした。
ところで、なぜbcm.pyxとegl.pyxは消えてしまったのでしょうか?
想像の範疇を超えませんが、Kivyと戦っていた時に感じたのは以下の三つです。

  • 私が原因
    • Kivyのインストール中に私が操作を誤ってしまい消えてしまった。
  • 開発側が原因
    • LinuxのKivyだけインストールファイルの中にbcm.pyxとegl.pyxが入っていない。
  • Ubuntuが原因
    • 勝手にUbuntuがはじいていた。

Windowsでは普通に動いたので、以上のようなことが原因かもしれません。最有力は『私が原因』。
ですが、これだけははっきり言えます。
同じようなことが起きたら、諦めてOSを変えましょう。そっちの方が早い。

最後に

最後までお付き合い頂きありがとうございます。Kivyの話はどこまで読みましたか?
全部読んでいただけたら幸いです。本当に苦労しました。
ですが、今はまだスタートラインに立っただけです。開発すらやっていません。
これからが勝負です。頑張らなくては。
次の記事は『ライブラリと仲良くなる Part.1』という感じの内容になると思いますので、よろしくお願いいたします。
以上、enpがお送りいたしました。

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

globで複数のエクセルを一挙取得する(ボートレース機械学習予測結果 6月分の確認)

はじめに

※本記事のコード解説自体は、pythonプログラミング初心者向けとなっております。

ボートレース3連単予測サイト「きょう、ていの良い予想は当たるだろうか」では毎日のレース予想の的中率や回収率をつつみ隠さず公開しているのですが、月に一度は毎日の予想結果を1つにまとめておきたいなと思い、表題のような処理をしようと考えました。

私の状況

ボートレースの試合結果と機械学習による予想を整理し、"result_2020mmdd.csv" といった形式で毎日保存しています。月に一度はこれらのファイルをまとめて、結果を可視化したい..。

そして下図にあるような、ところどころ混ざっているresult_202006.. _test .csv のようなファイルはテスト用なので省きたい..。

image.png

コードはこんな感じ。

とてもシンプルです。

import pandas as pd
import glob

csv_files = glob.glob("predict/result/result_202006??.csv")
filelist = []
for file in csv_files:
    filelist.append(pd.read_csv(file))

df = pd.concat(filelist)

globでパス名を取得する際にresult_202006 ?? .csvとしています。1つの?で任意の一文字分を担当してくれます。

csv_filesにはいい感じにファイル+パス名が一式格納されています。
image.png

for文でひとつずつappendしていき、最後はDataFrame化して完成!です。

ちなみに6月の結果はどうだったのか..

先ほどつくったデータフレームを使って、結果を確認しました。
3連単的中率は設計通り10%を記録しましたが、回収率が80%強です..。(とはいっても、その他の無料予想を見ていると、現時点でも割と戦える感じかもしれない。)

image.png

まとめた後にpivot_tableで整理した結果がこちらです。
当たりやすい競艇場と全然あたらない競艇場がはっきりしているのが面白いです。 
今月は当たりやすい競艇場だけ買ってみようかな..

Site Hit Miss Payoff Return_ratio
丸亀 5 26 5480 176.77
蒲郡 3 21 3990 166.25
徳山 9 33 6800 161.9
琵琶湖 9 31 5810 145.25
浜名湖 8 43 6030 118.24
戸田 4 46 5470 109.4
江戸川 3 24 2740 101.48
鳴門 6 44 5060 101.2
常滑 4 38 4190 99.76
児島 5 58 6230 98.89
住之江 2 33 3340 95.43
福岡 2 14 1460 91.25
芦屋 6 46 4540 87.31
大村 8 51 4770 80.85
唐津 3 30 2600 78.79
尼崎 5 52 4270 74.91
宮島 5 36 2400 58.54
平和島 3 40 2510 58.37
多摩川 3 32 1850 52.86
下関 3 54 2760 48.42
三国 5 58 3030 48.1
若松 4 56 1780 29.67
桐生 1 47 1190 24.79
3 67 1290 18.43
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

nimとpythonを繋ぐ素敵なnimporter

さいつよのnim + pythonを繋ぐモジュール

nimporterというモジュールが感動的だったので紹介します。
いや、紹介自体はn番煎じかもだけど、あんま知られてないっぽいので。
https://github.com/Pebaz/Nimporter
要するに、nimの超高速コードをpythonでインタプリタっぽく動かす奴です。

公式の例を抜粋しますが、nimのコードを下記のように

import nimpy

proc add(a: int, b: int): int {.exportpy.} =
    return a + b

pythonのコードを下記のように

# Nimporter is needed prior to importing any Nim code
import nimporter, nim_math

print(nim_math.add(2, 4))  # 6

書けば、コンパイルが自動的になされてimportされます
いや、マジで実質インタプリタ言語じゃねえか!ってなります。

お約束の速さ比較

敢えておっそい再帰でフィボナッチ数列の計算をさせてみます。
nimのコードは下記。

fibnim.nim
import nimpy
proc fib(n: int): float {.exportpy.}=
    if n == 1:
        return 0
    elif n == 2:
        return 1
    else:
        return fib(n - 1) + fib(n - 2)

pythonの方は下記。

fibpy.py
def fib(n: int) -> float:    
    if n == 1:
        return 0.
    elif n == 2:
        return 1.
    else:
        return fib(n - 1) + fib(n - 2)

...にしても、クッソ似てますね。
この2つをpythonでimportして比べてみましょう。

import fibpy
import nimporter, fibnim
from time import time
cycle = 36
t = time()
print(fibnim.fib(cycle))
print('Time of nim is {} sec'.format(str(time() - t)))
t = time()
print(fibpy.fib(cycle))
print('Time of python is {} sec'.format(str(time() - t)))

>>> 9227465.0
>>> Time of nim is 0.026133298873901367 sec
>>> 9227465.0
>>> Time of python is 3.1436727046966553 sec

1回目はコンパイルの時間がかかるのですが、二回目以降は順当に100倍以上ですね。

そもそもcythonじゃダメなん?

ダメではない。むしろ筆頭候補。cythonも最近はかなり使いやすくなっていて
型ヒント付きpythonをpurepythonモードに食わせるとpythonから変更無しで移行できそうなレベルです。1

cythonize -i hoge.py

ってな感じでモジュールを作れるのだけれど、一旦bashに戻る必要があるのが面倒と言えば面倒でしょうか。
あと、cythonは一部でpythonを使う事があるので、
カツカツに最適化する時に意外と面倒…という時が無くもない気がします。


  1. 実際はチューニング頑張らないと速くならなかったりする 

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