メモ_Pandasより速いpolars

Pythonでデータ処理を行う際の標準的なライブラリともいわれるPandasですが、最近、より高速なライブラリとして「polars」というのが、よく利用されているそうです。

使い方は簡単。試しにやってみました。

 

インストール

おなじみのpipで。最初は実験用の仮想環境に切り替えて入れてみる。

pip install polars
比較

10億までの素数の一覧データ(約5084万行)のcsv(約553MB)を読み込んでdfをprintする、という簡単なコードで処理時間を比較してみた。


    
## pandasの場合    
import pandas as pd
import time

start_time = time.time()

df = pd.read_csv('primes_up_to_1000000000.csv')

print(df)

end_time = time.time()

# 計算にかかった時間を表示
execution_time = end_time - start_time
print("計算にかかった時間:", execution_time, "秒")


## polarsの場合
import polars as pl
import time

start_time = time.time()

df = pl.read_csv('primes_up_to_1000000000.csv')

print(df)

end_time = time.time()

# 計算にかかった時間を表示
execution_time = end_time - start_time
print("計算にかかった時間:", execution_time, "秒")

 

結果

pandasだと7.7906458377838135 秒だったのが、polarsだと 0.48952651023864746 秒 となりました。かなり速い。


他にも巨大な行列データをいろいろ弄る処理で比較してみると、概ね10倍くらいの差がありますね。下記により詳細なベンチマークなどもあるので参考までに。

Database-like ops benchmark

メモ_XserverVPSで無料SSL(Let's Encrypt)を設定する方法

XserverVPSで無料SSL(Let's Encrypt)を設定する方法についてのメモ。

VPS管理画面で「SSL証明書」というのがあったので、ここから「追加申し込み」をするのかなーと思って(Let's Encryptもメニューにあったので)申し込んだけど、何も起きず何日か待ちぼうけを食らっていたので、ちゃんとマニュアルを読んだら、手動で設定する方法が、とても丁寧にのっていた。。。→手順はこちら

 

手順の通りで何もトラブルなく完了できたけど、最後のnginxのconf設定だけ自分の環境に合わせて変更したので、そのメモ。

nginx + Flask  / 5000番->443リダイレクトでSSL有効化

Flaskで構築したアプリをwaitressで5000番ポートで起動していて、nginxでリバースプロキシさせて、wwwありと無しの両方ともに HTTTPS になるように動かしたい。

内容としては、最初の server ブロックがポート 80 でのリクエストを 443 の HTTPS にリダイレクトし、2つ目の server ブロックが実際の HTTPS 通信を処理して、Flask アプリケーションへのリバースプロキシを実行する。server_name ディレクティブには、マイドメイン.com と www.マイドメイン.com の両方が含まれている。

マイドメインのところは、実際に設定したいドメイン名が入る。confファイルは /etc/nginx/conf.d/ 配下にあるものは全てインクルードされるので、管理しやすい名称(アプリ名.conf とか)であればok。


server {
    server_name マイドメイン.com www.マイドメイン.com;

    # ポート 80 へのリクエストを 443 にリダイレクト
    listen 80;
    return 301 https://$host$request_uri;
}

server {
    server_name マイドメイン.com www.マイドメイン.com;

    # HTTPS の設定
    listen 443 ssl;
    ssl_certificate /etc/letsencrypt/live/マイドメイン/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/マイドメイン/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    location / {
        proxy_pass http://localhost:5000/;
    }
}
    

メモ_Xserver-VPSで接続許可ポートが自由に設定できるようになった

Xserver-VPSVPSパネルで接続許可ポートが自由に設定できるようになった。

今までは、あらかじめ決められた設定(SSH、Web、mailなど)のon/off、もしくは全部開ける設定しかなかったので、別途ufwとかで設定する必要があったけど、パネル側で簡単に指定ポートへの接続許可を自由に設定できるようになった。

また、許可する送信元IPアドレスも指定できるようになったので、VPNとかと合わせて開発中のサーバを、よりセキュアに運用できるようになる。便利。

 

メモ_XserverVPSでPython-WebアプリをFlask+waitressで実行するまでの手順

XserverVPSでPythonで書いたWebアプリをFlask+waitressで実行するまでの手順のメモです。

手順は以下の通りです。OSセットアップ直後の環境でスタートします。OSは Ubuntu 22にしています。

 

手順

  1. sshでログイン。apt-get update を実行
  2. apt install python3.10-venv を実行
  3. venvで仮想環境を構築して、仮想環境をアクティブにする。
  4. 仮想環境で必要なライブラリなどをセットアップ。Flask 、waitressをインストール
  5. Flaskアプリ用のフォルダを作成してコード群をup
  6. 稼働テスト
手順1:

まずはSSHでインストールしてapt-get update します。インストール直後だと古いライブラリがあり、venvインストールでエラーになったりします。

 

手順2:

OSセットアップ直後だとvenvが入ってないので、まずはvenvをインストールします。

apt install python3.10-venv
手順3:

インストールできたら、以下のコマンドで仮想環境を作ります。yourvenvのところは実際の仮想環境名になります。

source ./yourvenv/bin/activate

Xserverの場合、sshでログインするとデフォルトが「/root」フォルダになり、そのまま作業していくとrootフォルダ以下にいろいろと展開されていくので、気になる人は適当なディレクトリ(例:/home/username/***)を作って、そちらに展開しましょう。

手順4:

無事に仮想環境がアクティブになると、コンソールの表示が以下のようになります。

(仮想環境名) root@IPアドレス # 

この状態だとPythonのライブラリなどが何も入っていません。確かめたい人は「pip freeze」とかで確認しましょう。

必要最低限のライブラリをpipでインストールしていきます。とりあえず、今回は Flask と waitress の二つだけあればOKです。


pip install flask
pip install waitress
手順5:

flaskアプリを設置するフォルダを作成して、そこにテスト用のコードをアップします。scpコマンドないしsftpとかでfileをサーバにアップロードします。WindowsだとRloginというターミナルソフトがsftpも使えるので楽です。

テスト用に用意したコードとディレクトリ構造は以下の通りです。全部、app.pyに書いても良いのですが、少し込み入った検証を行うため、あらかじめroutesをわけて、templatesフォルダも設置しています。__init__.py も忘れずに設置します。


/app/app.py
/app/__init__.py

/app/routes/index_routes.py
/app/routes/__init__.py

/app/templates/index.html

各コードは以下の通り。


# /app/app.py
from flask import Flask
from flask import render_template, Blueprint
from waitress import serve

from routes.index_routes import index_bp

app = Flask(__name__)


# Blueprintを登録します。
app.register_blueprint(index_bp)


if __name__ == '__main__':
#    app.run('0.0.0.0', port=5000)
    serve(app, host='0.0.0.0', port=5000)

# /app/routes/index_routes.py
from flask import render_template, Blueprint

index_bp = Blueprint('index', __name__)

@index_bp.route('/')
def index():
    return render_template('index.html')

/app/templates/index.html は、「test waitress」とだけ表示したhtmlにしています。

手順6:

python3 app.py を実行して、 http://ip:5000/ でアクセスして、無事に「test waitress」が表示されていれば成功です。

ちなみに、OSセットアップ直後だと、apacheもnginxもインストールされておらず、httpd が走っていないため、waitress をそのままwebサーバにして、80番ポートで公開も出来ます。app.pyの最後をport=80 とするだけです。

apacheないしnginxを挟むのが本番運用としては適切かとは思いますが、手軽にWebアプリを公開したいだけであれば、Python+Flask+waitressだけでも稼働します。

FlaskアプリをWaitressで起動する際、ターミナルを閉じるとアプリも終了してしまいますので、ターミナルを閉じても稼働させつづけるには、nohupコマンドを使用するか、systemd にきちんと登録して自動起動するようにしておきます。

nohup python server.py &
参考:

Waitress — Flask Documentation (2.2.x) (msiz07-flask-docs-ja.readthedocs.io)

こじつけ算を求めるPythonコード

吉凶数に続いて、任意の西暦年月日の数字の組み合わせで、縁起の良い数字あるいは悪い数字との関係性を探索するコード。単なるこじつけなので「こじつけ算」とでも呼ぼう。

コード:


from itertools import itertools

def decompose_number(number):
    return [int(digit) for digit in str(number)]

def calculate_combinations(numbers):
    num_length = len(numbers)
    all_results = []

    for combination in product(['+', '*'], repeat=num_length - 1):
        expression = [str(numbers[i]) + combination[i] for i in range(num_length - 1)] + [str(numbers[-1])]
        expression_str = ''.join(expression)
        result = eval(expression_str)
        all_results.append((expression_str, result))

    return all_results

def find_matching_expressions(A, B):
    decomposed = decompose_number(A)
    results = calculate_combinations(decomposed)
    
    matching_expressions = []
    for idx, (expression, result) in enumerate(results, start=1):
        if result == B:
            matching_expressions.append(f"result_{idx}: {expression} = {result}")

    return matching_expressions, results

# 標準入力から数字Aと数字Bを取得
A = int(input("数字Aを入力してください: "))
B = int(input("数字Bを入力してください: "))

matching_expressions, all_results = find_matching_expressions(A, B)

# AとBが一致する計算式を表示または「一致無し」を表示
if matching_expressions:
    print("AとBが一致する計算式:")
    for expression in matching_expressions:
        print(expression)
else:
    print("一致無し")

# 全ての組み合わせを表示
print("\n組み合わせ一覧:")
for idx, (expression, result) in enumerate(all_results, start=1):
    print(f"result_{idx}: {expression} = {result}")

結果

数字Aに西暦年月日を、数字Bにはこじつけたい数字を入れると、一致するバターンがあれば表示して、なければ「一致無し」と出る。ついでに全組み合わせも表示する。引き算、割り算を考慮すると複雑になるので、加算と乗算のみ。0の扱いも課題だけど、とりあえずそのまま計算。

例えば、数字A = 20231119(2023年11月19日)、数字B=18(6+6+6で、いわゆる獣の数字で、縁起悪い)だと、以下のような組み合わせが該当する。

result_2: 2+0+2+3+1+1+1*9 = 18
result_3: 2+0+2+3+1+1*1+9 = 18
result_5: 2+0+2+3+1*1+1+9 = 18
result_9: 2+0+2+3*1+1+1+9 = 18
result_20: 2+0+2*3+1+1*1*9 = 18
result_22: 2+0+2*3+1*1+1*9 = 18
result_23: 2+0+2*3+1*1*1+9 = 18
result_26: 2+0+2*3*1+1+1*9 = 18
result_27: 2+0+2*3*1+1*1+9 = 18
result_29: 2+0+2*3*1*1+1+9 = 18
result_81: 2*0+2*3+1+1+1+9 = 18    

さらに目標とする「こじつけ算」に一致する組み合わせが出てくるまで任意の範囲を虱潰しで探索するとか、年月日時分秒((YYYYMMDDhhddss)まで含めるとか、いろいろ拡張すれば使い勝手(?)が良くなりそう。面倒くさいけど。

吉凶数(西暦年月日の各桁数を合計した数字)を計算するpythonコード

西暦年月日の各桁数を合計した数字を吉凶数というらしいです。完全にオカルトですが、そうはいっても、縁起の悪い数字は避けたかったり、逆に何か大事な数字を決める際は、一応、良いとされる数字にしてみたかったり。

 

ということで、暇つぶしに吉凶数を計算するpythonコード。(計算してくれるWebサイト/アプリなどもありますが)

 

吉凶数計算

超シンプルに。


# 数字入力
number = input("数字を入力:")

# 各桁を足す
total = sum(int(digit) for digit in number)

# 結果表示
print(f"{number} -> 各桁の合計は {total} ")
    

例えば、自分の生まれた生年月日とかを入れてみます。下記はサンプルで、私の実年齢ではありません。

吉凶数の出現回数のカウント

吉凶数の出現回数をカウントするコード。西暦年月日で開始と終了を指定する。


from datetime import datetime, timedelta
from collections import Counter

start_date_str = input("開始日(YYYY-MM-DD)を入力:")
end_date_str = input("終了日(YYYY-MM-DD)を入力:")

start_date = datetime.strptime(start_date_str, "%Y-%m-%d")
end_date = datetime.strptime(end_date_str, "%Y-%m-%d")

totals = []

current_date = start_date
while current_date <= end_date:
    date_str = current_date.strftime("%Y%m%d")
    
    total = sum(int(digit) for digit in date_str)
    totals.append(total)

    current_date += timedelta(days=1)

count_totals = Counter(totals)


print("吉凶数と出現回数:")
for total, count in sorted(count_totals.items()):
    print(f"{total}: {count}回")

結果は以下の通り。西暦1年1月1日から2100年12月31日まで。

3: 16回
4: 80回
5: 248回
6: 574回
7: 1112回
8: 1923回
9: 3069回
10: 4631回
11: 6680回
12: 9282回
13: 12446回
14: 16108回
15: 20163回
16: 24470回
17: 28887回
18: 33236回
19: 37328回
20: 40948回
21: 43872回
22: 45898回
23: 46907回
24: 46866回
25: 45822回
26: 43851回
27: 41065回
28: 37605回
29: 33648回
30: 29396回
31: 25072回
32: 20883回
33: 16985回
34: 13470回
35: 10390回
36: 7775回
37: 5630回
38: 3937回
39: 2656回
40: 1727回
41: 1078回
42: 638回
43: 351回
44: 175回
45: 76回
46: 27回
47: 7回
48: 1回
csvファイルに出力

Excelとかスプレッドシートで扱いたいのでcsvにも出力


from datetime import datetime, timedelta
from collections import Counter
import csv


start_date_str = input("開始日(YYYY-MM-DD):")
end_date_str = input("終了日(YYYY-MM-DD):")

start_date = datetime.strptime(start_date_str, "%Y-%m-%d")
end_date = datetime.strptime(end_date_str, "%Y-%m-%d")

totals = []

current_date = start_date
while current_date <= end_date:
    date_str = current_date.strftime("%Y%m%d")
    
    total = sum(int(digit) for digit in date_str)
    totals.append(total)

    current_date += timedelta(days=1)

count_totals = Counter(totals)

# 出現回数と合計数のCSVファイル生成
with open('count_totals.csv', 'w', newline='') as file:
    writer = csv.writer(file)
    writer.writerow(['出現回数', '合計数'])
    for total, count in count_totals.items():
        writer.writerow([count, total])

# 西暦年月日と合計数のcsv生成
with open('date_totals.csv', 'w', newline='') as file:
    writer = csv.writer(file)
    writer.writerow(['西暦年月日', '合計数'])
    current_date = start_date
    for total in totals:
        date_str = current_date.strftime("%Y-%m-%d")
        writer.writerow([date_str, total])
        current_date += timedelta(days=1)            

あとは調べたい吉凶数から逆算して年月日を探す。西暦1年から2100年だと76万件(707009)もあるので、Excelでも重いので19000年~2023年とかで。

メモ_XserverVPSでOSやアプリケーションを再インストール_試しにDjangoでログインするまで

XserverVPSでは、「VPS管理」というコントールパネルから、OSやアプリケーションを再インストールができる。試しにDjangoでやってみた。

 

手順1: VPS管理からVPSパネルを開いてOS再インストールを選択

「電源操作」というところで、シャットダウンしないと「OS再インストール」のメニューが出てこないので注意。

 

手順2: インストールするメニューを選ぶ

デフォルトは「OS」のメニューが開くので、Ubuntu22を選択。そのあと、アプリケーションも開く。今はやりのGPT系のイメージから、定番のLeravelやRails、ゲームサーバなどもあるらしい。

 

手順3: インストールはすぐ終わるので電源操作から起動する

イメージをコピーしているだけのようで、あっという間に完了する。起動したら完了。これだけで使える状態になっている。

 

手順4: SSHでログインして表示されるDjangoアカウント情報をメモする

ここで一つ注意事項。ログイン直後の画面に、Djangoやデータベース(MySQL/MariaDB)のUser、PW、database名が表示される。

ここを見逃したまま操作していくとサーバのRoot/PWでDBに入れなくて、「あれ、どうやってDBにログインするんだ?」となった。。。アカウント情報を適当なところにコピペして保存しておこう。

 

手順5: Django administration 画面を確認。コンソールでDjango superuserを作成。

特に何もすることなく、IPアドレスないし紐づけたドメイン名からDjango administration 画面が見られます。

ただし、このままだとログインできないので、はじめにSSHのコンソールで、Djangoのフォルダ(例:/home/django/sample/)に移動してmanage.py を実行して、Djangoのスーパーユーザを登録します。

cd /home/django/sample/
python3 manage.py createsuperuser

上記を実行して、登録したuserとpasswordで以下の画面からログインできれば成功。