Yuta NakataのBlog

Python / AWS / ITについて役立つ情報を発信します

【爆速Python】今すぐ使えるPythonを高速化する方法

背景

2024年6月24日に「爆速Python」が出版されました。

Pythonユーザーにとって、「高速化」は常に求められる処理であり、本書から今すぐ使えるテクニックを抽出しようと思います。

データ分析を高速化するテクニック

本書を通じて、ひとつだけ取り上げるとしたらPandas・データフレームの高速化です。

一番重要な考え方・思考法はベクトル化です(本書、7章を読むとよくわかります)。

テーマ

データフレームを使って、ループ処理を実装する

これをアマチュアからプロまでのコードの書き方が紹介されています。

レベル1

一行ずつ取り出す方法です。

PandasやNumpyの経験がないPython開発者が一般的に記述する方法

として本書では扱われています。

total = 0
roops = 0

for i in range(len(df)):
    row = df.iloc[i]
    total += row['count']
    roops += 1

print(total / roops)

レベル2

iterrows()メソッドを使った方法です。 レベル1よりは、多少の改善が見られます。

total = 0
roops = 0

for i, row in df.iterrows():
    total += row['count']
    roops += 1

prunt(total / roops) 

レベル3

itertuples()を使う方法です。 レベル2に酷似していますが、大きな改善が見られるようです。

total = 0
roops = 0

for row in df.itertuples():
    total += row.count
    roops += 1

print(total / roops)

レベル4

ベクトル化です。

df['count'].sum() / len(df)

datetime型について

datetimeが含まれているDataFrameについては、型を適切にdatatimeにすると、より早くなります。

その他

色々、目からウロコな内容でしたので、目次だけでも出しておきます

  • 並行性、並列性、非同期処理
  • ハイパフォーマンスなNumPy
  • Cythonを使って重要なコードを再実装する
  • ハイパフォーマンスなpandasとApache Arrow
  • GPUコンピューティングを使ったデータ分析
  • Daskを使ったビッグデータの分析

うるう年の計算はPythonに任せよう

サマリー

  • うるう年に伴う計算(日数計算や月合計時間の計算)は自前で書かない(calenderライブラリを使う)
  • うるう年の定義は正確には4年に1回ではないので、ロジックミスが起きる
  • 自前で作ると、コードの可読性が下がるので、レビューがしずらい

うるう年の定義

そもそもうるう年とは?

うるう年とは、一言で言うと、1年が366日となる年のことを指します。

この追加された1日は、2月29日として知られています。

定義

よく云われるうるう年は、4年に1回は間違いです。

正確には、

  • 西暦年号が4で割り切れる年は、うるう年
  • ただし、西暦年号が100で割り切れる年は、通常は平年です。
  • しかし、西暦年号が400で割り切れる年は、うるう年です。

です。

実は面倒な定義なのです。

うるう年の計算をしてみる

自前でコードを書いた場合

Pythonで上記のロジックを実装し、うるう年を計算するスクリプトを書いてみます。

def is_leap_year(year: int) -> bool:
    if year % 4 == 0:
        if year % 100 == 0:
            if year % 400 == 0:
                return True
            else:
                return False
        else:
            return True
    else:
        return False

3重ループとなっており、可読性が低下しています。

ライブラリを使った場合

calenderライブラリを使って計算してみます。

import calendar

year = 2000
calendar.isleap(year)

一行で書くことができました

まとめ

上記の例を見ればわかる通り、うるう年の計算を自前でしてはいけません

退屈なことはPythonに任せましょう。

【サンプルコード有】今日から始めるpytest

背景

Pythonユーザー初級〜中級者の方にとって、

書いたコードの正しさを効率的にテストしたい

と考えるのではないでしょうか。

Pythonには、テストフレームワークはいくつもありますが、pytestの人気が高いことは明らかです。

そこで、今回は今すぐ始められるpytestの使い方について紹介します。

サンプルコード

まずは、サンプルコードです。

github.com

以下のようなディレクトリ構成があるとします。

src/
┣ scripts/
┃  ┣ __init__.py
┃  ┗ main.py
┣ tests/
┃  ┣ __init__.py
┃  ┗ test_main.py
┗README.md

また、main.py

def f(x: int):
    if x < 0:
        return None
    return x** 2 + 2*x + 1


if __name__ == '__main__':
    result = f(4)
    print(f'resut is {result}')

今回は、def f()をテストしたいです。

このとき、pytestは下記のように書きます。

from scripts import main

# pytestを実行するには、関数の始まりの語句をtestにする必要があります
def test_f_pattern1():
    # 'assert'を使って、正しさをチェックできます
    assert main.f(1) == 4
    assert main.f(0) == 1
    assert main.f(-1) == None


def test_f_pattern2():
    assert main.f(1) != 1

pytestを実行するにあたって、大事なポイントは、

  • 実行コマンドは、pytest test_main.py -s -v
  • 関数名の始まりは、test_で始める
  • assertを使って、試験したい関数の計算結果が意図通りかを確認する
  • __init__.pyを書く

です。

まずは、cloneして雰囲気を掴んで貰えると嬉しいです。

更に知りたい方向け

testについてもっと知りたい方向けに名著が2つあるので、ご紹介します。

テスト駆動Python 第2版

完全にpytestの使い方に解説してくれている本です。 pytestの大体の機能はこれでOKです。

https://www.amazon.co.jp/%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95Python-%E7%AC%AC2%E7%89%88-Brian-Okken/dp/4798177458/ref=sr_1_1?adgrpid=140756830458&dib=eyJ2IjoiMSJ9.Qrwjs3RodEkYP1bOfix1WSPbrlOxrY8B8eo6VqoM4QeTvrzbi0MhFD2TQ7etw3dkNqgsYvC7m0_Ho0Zv1-uD-svLwXXlC9wwS-j7qOoLQM7ctACRF6gFeRsYNw3KcLudzDPpNBSlV44Zg3Vnn8bEikearDEGGbETaRGhovpes4EVN91fqaXoVEGgyxfOMwsC.sibNyqSqr2UWoFmKghq7lXeccGxE8PN4tS_Cc4z996M&dib_tag=se&hvadid=678960061884&hvdev=c&hvlocphy=1009253&hvnetw=g&hvqmt=e&hvrand=2670193312268713035&hvtargid=kwd-1718974312486&hydadcr=1794_13656998&jp-ad-ap=0&keywords=%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95python+%E7%AC%AC2%E7%89%88&qid=1718423648&sr=8-1

テスト駆動開発

テストに興味のある方は、テスト駆動開発がなにかにも興味があるのではないでしょうか? TDD(Test Driven Development)について学ぶのであればこちらがおすすめです。

https://www.amazon.co.jp/%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95%E9%96%8B%E7%99%BA-Kent-Beck/dp/4274217884/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1SPZS3CJDVLBR&dib=eyJ2IjoiMSJ9.Pk4ofweQS507cMVk6LHoAnB93GfG3b4np1OnUaykpcKzQssPEUezA05l1FpyMNuJVDIN_wZCGOHxOY5Cs6g4gPlToAkXaTMzV2oVOQUwm357ZE6AoyGV9-pn3xZt3ZQcqictisDFODmgWPxNoRc5VCtPX2IDvMSGL6fT42RBcx_6_RPiVkBvk00vTL6KMgjm6kjdM1OxbHvReMZcl3S2lLF0yRW6-civ3djS6qAE80-_9tCZ9SBkQLZzMuQc8cJDEXfwmwjXMxuw_hc3X0weCesOYP6U9qT7OMyR_qpdxfM.qoXCbJad2ayiIyR6ykiWwTzH9jcLuSMeEbctyqJpJgY&dib_tag=se&keywords=%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95%E9%96%8B%E7%99%BA&qid=1718423713&sprefix=%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95%E9%96%8B%E7%99%BA%2Caps%2C260&sr=8-1

【最速】Cartopy / Matplotlibで最速で日本語を使う方法

結論

フォントはこだわらない、だけど日本語は使いたいそこのあなたへ!

解決策1

import matplotlib.pyplot as plt
import cartopy.crs as ccrs


plt.rcParams["font.family"] = "Osaka" 
plt.title("これで日本語が使えるはずです")

上記でOKです。

もし、これでダメな場合、、、

解決策2

import matplotlib
 
fonts = set([f.name for f in matplotlib.font_manager.fontManager.ttflist])
print(fonts)

を使ってみてください。

あなたの環境で使えるフォントが出てきます。

その中で、明朝体など使えそうなフォントを選んでみてください。

選んだフォントで

plt.rcParams["font.family"] = "" 

で指定してあげてみてください。

これでも、ダメな場合、、、

解決策3

ライブラリをinstallして使います。

pip install japanize-matplotlib
import japanize_matplotlib

これでもOKです。

一般的なやり方

上記の方法の場合、外部ファイルのインストール等はせず、環境設定を変更することで日本語を有効化しました。

使いたいフォント等がある場合はどうでしょうか?

外部のフォントファイルをインストールします。

こちらの方法については、よくまとまっている記事がありますので、そちらを参照ください。

https://datumstudio.jp/blog/matplotlib%e3%81%ae%e6%97%a5%e6%9c%ac%e8%aa%9e%e6%96%87%e5%ad%97%e5%8c%96%e3%81%91%e3%82%92%e8%a7%a3%e6%b6%88%e3%81%99%e3%82%8bwindows%e7%b7%a8/

AWS Lambdaのランタイムサポートが終わるとどうなるか?

Lambdaのランタイムサポートが終わるとどうなる?

AWS Lambdaは、FaaS(Function as a Service)、サーバーレスサービスの実現において非常に重要な役割を担っています。

一方で、サポートするランタイムの変遷も早く、適宜Version Upを行っていく必要性が求められています。

そこで、今回はサポートが終わったLambdaのランタイムを使うとどうなるか?紹介していきます。

Lambdaのランタイム

近々(2024年4月現在)、サポートが終了されるランタイムは下記の通りです。

名前 廃止日
Node.js 16 2024 年 6 月 12 日
Python 3.8 2024 年 10 月 14 日
.NET 6 2024 年 11 月 12 日

サポートが終わるとどうなる?

  • セキュリティパッチの適用対象外になります。
  • 廃止から30日経過すると、関数の新規作成ができなくなります。
  • 廃止から60日経過すると、関数の更新と設定の変更ができなくなります。
  • 廃止後も、関数の実行はできます。

事前に情報を受け取るにはどうすればいいか?

  • AWS Health Dashboardから確認
  • メールを受け取る
  • AWS Trusted Advisorを確認

等があります。

非推奨のランタイムを確認する方法

下記のコマンドで一発です。

aws lambda list-functions --function-version ALL --region ap-northeast-1 --output text --query "Functions[?Runtime=='RUNTIME_IDENTIFIER'].FunctionArn" 

python3.12でnpm iをすると、エラーになる話

問題

npm iを叩くと以下のようなエラーに遭遇

npm WARN deprecated @npmcli/move-file@1.1.2: This functionality has been moved to @npmcli/fs
npm WARN deprecated stringify-package@1.0.1: This module is not used anymore, and has been replaced by @npmcli/package-json
npm ERR! code 1
npm ERR! path E:\test\electron-acrylic-window\node_modules\@seorii\win32-displayconfig
npm ERR! command failed
npm ERR! command C:\Windows\system32\cmd.exe /d /s /c npm run rebuild
npm ERR! > @seorii/win32-displayconfig@0.1.1 rebuild
npm ERR! > node-gyp rebuild
npm ERR! gyp info it worked if it ends with ok
npm ERR! gyp info using node-gyp@8.4.1
npm ERR! gyp info using node@20.10.0 | win32 | x64
npm ERR! gyp info find Python using Python version 3.12.0 found at "C:\Users\Aptyp\AppData\Local\Programs\Python\Python312\python.exe"
npm ERR! gyp info find VS using VS2022 (17.6.33829.357) found at:
npm ERR! gyp info find VS "C:\Program Files\Microsoft Visual Studio\2022\Community"
npm ERR! gyp info find VS run with --verbose for detailed information
npm ERR! gyp info spawn C:\Users\Aptyp\AppData\Local\Programs\Python\Python312\python.exe
npm ERR! gyp info spawn args [
npm ERR! gyp info spawn args   'E:\\test\\electron-acrylic-window\\node_modules\\node-gyp\\gyp\\gyp_main.py',
npm ERR! gyp info spawn args   'binding.gyp',
npm ERR! gyp info spawn args   '-f',
npm ERR! gyp info spawn args   'msvs',
npm ERR! gyp info spawn args   '-I',
npm ERR! gyp info spawn args   'E:\\test\\electron-acrylic-window\\node_modules\\@seorii\\win32-displayconfig\\build\\config.gypi',
npm ERR! gyp info spawn args   '-I',
npm ERR! gyp info spawn args   'E:\\test\\electron-acrylic-window\\node_modules\\node-gyp\\addon.gypi',
npm ERR! gyp info spawn args   '-I',
npm ERR! gyp info spawn args   'C:\\Users\\Aptyp\\AppData\\Local\\node-gyp\\Cache\\20.10.0\\include\\node\\common.gypi',
npm ERR! gyp info spawn args   '-Dlibrary=shared_library',
npm ERR! gyp info spawn args   '-Dvisibility=default',
npm ERR! gyp info spawn args   '-Dnode_root_dir=C:\\Users\\Aptyp\\AppData\\Local\\node-gyp\\Cache\\20.10.0',
npm ERR! gyp info spawn args   '-Dnode_gyp_dir=E:\\test\\electron-acrylic-window\\node_modules\\node-gyp',
npm ERR! gyp info spawn args   '-Dnode_lib_file=C:\\\\Users\\\\Aptyp\\\\AppData\\\\Local\\\\node-gyp\\\\Cache\\\\20.10.0\\\\<(target_arch)\\\\node.lib',
npm ERR! gyp info spawn args   '-Dmodule_root_dir=E:\\test\\electron-acrylic-window\\node_modules\\@seorii\\win32-displayconfig',
npm ERR! gyp info spawn args   '-Dnode_engine=v8',
npm ERR! gyp info spawn args   '--depth=.',
npm ERR! gyp info spawn args   '--no-parallel',
npm ERR! gyp info spawn args   '--generator-output',
npm ERR! gyp info spawn args   'E:\\test\\electron-acrylic-window\\node_modules\\@seorii\\win32-displayconfig\\build',
npm ERR! gyp info spawn args   '-Goutput_dir=.'
npm ERR! gyp info spawn args ]
npm ERR! Traceback (most recent call last):
npm ERR!   File "E:\test\electron-acrylic-window\node_modules\node-gyp\gyp\gyp_main.py", line 42, in <module>
npm ERR!     import gyp  # noqa: E402
npm ERR!     ^^^^^^^^^^
npm ERR!   File "E:\test\electron-acrylic-window\node_modules\node-gyp\gyp\pylib\gyp\__init__.py", line 9, in <module>
npm ERR!     import gyp.input
npm ERR!   File "E:\test\electron-acrylic-window\node_modules\node-gyp\gyp\pylib\gyp\input.py", line 19, in <module>
npm ERR!     from distutils.version import StrictVersion
npm ERR! ModuleNotFoundError: No module named 'distutils'
npm ERR! gyp ERR! configure error
npm ERR! gyp ERR! stack Error: `gyp` failed with exit code: 1
npm ERR! gyp ERR! stack     at ChildProcess.onCpExit (E:\test\electron-acrylic-window\node_modules\node-gyp\lib\configure.js:259:16)
npm ERR! gyp ERR! stack     at ChildProcess.emit (node:events:514:28)
npm ERR! gyp ERR! stack     at ChildProcess._handle.onexit (node:internal/child_process:294:12)
npm ERR! gyp ERR! System Windows_NT 10.0.22000
npm ERR! gyp ERR! command "C:\\Program Files\\nodejs\\node.exe" "E:\\test\\electron-acrylic-window\\node_modules\\node-gyp\\bin\\node-gyp.js" "rebuild"
npm ERR! gyp ERR! cwd E:\test\electron-acrylic-window\node_modules\@seorii\win32-displayconfig
npm ERR! gyp ERR! node -v v20.10.0
npm ERR! gyp ERR! node-gyp -v v8.4.1
npm ERR! gyp ERR! not ok

どうやら、

ModuleNotFoundError: No module named 'distutils'

が問題っぽい。

生じた環境は、

  • python 3.12
  • npm 10系
  • node 21系

です。

原因

根本的な問題は、 distutilsがpython3.12系では削除されたためだそうです。

github.com

解決策

解決策1

pip install setuptool

でだそうです。

筆者は、これでは解決しなかったです。

解決策2

virtualenvを使う方法もあるようです。

pip install virtualenv
virtualenv -p python3.10 venv

source venv/bin/activate

stackoverflow.com

解決策3

pythonのダウングレードが最も早いです。マストな要件がないのであれば、ダウングレードしてしまいましょう。

筆者はこれで解決しました。

なお、nodeが21系だと、node-saasで失敗するので、nodeも16系にダウングレードしました。

qiita.com

【爆速】pythonを使って、ポリゴンデータから地点データを取得する方法

はじめに

ベクトルデータからデータを切り出す方法は以前、こちらでも紹介しました。

www.yuta-nakata.net

今回は、より高速に・Tipsも交えて追加の内容があるのでご紹介します。

結論

import pandas as pd
import shapely

# 取得したい緯度・経度
lon = 135
lat = 35

# 抽出した元データを読み込む
df = pd.read_csv("dataset.csv")

tree = shapely.STRtree(shapely.from_wkt(df['geometry'].astype(str)).to_numpy())
res = tree.query(shapely.points([lon], [lat]), 'within')
result = df.iloc[res[1]]

# 結果を表示する
print(result)

ポリゴンデータとは?

ベクトルデータの一種です。

GISの世界ではよく使われるデータになります。

ポリゴンには、シングルポリゴンとマルチポリゴンがあります。

シングルパートポリゴンとは、境界によって区切られた1つ1つのポリゴンと属性情報が1対1で対応しているようなポリゴンデータのことです。

マルチパートポリゴンは、1つの属性情報に対し複数のポリゴンが対応しているようなポリゴンデータのことです。

爆速のためのPoint

今回爆するうえでのPointとして、全てシングルポリゴンデータとして扱った点が挙げられます。

また、これらのデータを一度CSVとして書き出しています(上記の例では、geojson->csvや、shapefile->csv等に加工しています)。

import geopandas as gpd

df_shp = gpd.read_file('shapefile.shp',encoding='SHIFT-JIS')
df_gjs = gpd.read_file('gjs.geojson',encoding='SHIFT-JIS')

df_shp.to_csv("dataset_shp.csv")
df_gis.to_csv("dataset_gis.csv")

CSVのイメージとしては、

data geometry
1 POLYGON *1
2 POLYGON *2

です。

また、

res = tree.query(shapely.points([lon], [lat]), 'within')

サンプルでは、指定したポリゴンが含まれる地点を取得したためwithinとしましたが、Polygon上にある場合はintersectsとして取得ができます。

res = tree.query(shapely.points([lon], [lat]), 'intersects')

*1:-12485.05864419129 -77604.35297655607, -12477.826699746857

*2:-12485.05864419129 -77604.35297655607, -12477.826699746857

LambdaでPandasを高速化するための方法

Lambda(Python)でPandasを使ってる方は、多いのではないのでしょうか?

弊社では、サーバーレスがファーストチョイスとしてよく使われるため、Lambdaの出現頻度が高いです。

このPandasですが、Lambdaの世界(FaaS)で使う際の高速化の方法についてお教えてしようと思います。

結論

Lambda Layerとしてインポートするのではなく、Lambda Container(コンテナを利用したLambda関数)として利用する

なぜ?

そもそも、Lambdaにはコールドスタートウォームスタートという概念があります。

コールドスタートの場合、Lambdaの実行環境を作成する必要があります。

このとき、Lambdaの内部の世界では、Pandasのインストールが行われます。

この作業が重く、数秒(2~5秒程度)かかります。

Web API として利用するには、少し重いです。

そのため、弊社ではよほどの複雑な処理系を書く場合を除き、Pandasの利用は推奨されていません。

aws.amazon.com

続いて、コンテナイメージを利用したLambdaの場合です。

この場合、ECRにDockerfileをdeployして利用するのですが、なぜか?こちらのほうが早いようです(大体1~2sec)。

michimani.net

なぜLambda Containerのほうが早いのか?それはよくわかりませんが、弊社ではAWSエンタープライズサポートを導入しており、AWSのSAにも聞いてみた所、偶々というレベルの代物ではないらしいです。

仕組みはわからないけど、高速化の一案の紹介でした〜。

よかったら、いいね and シェアをお願いします!

立ち上げ時のSaaS/Webアプリに役立つサービスまとめ

私自身、立ち上げ期のSaaSサービス・Webサービスの開発、個人開発を通じて学んだ立ち上げ期に役に立つサービスをまとめます。

そもそも、なぜ立ち上げ期で役に立つのか?

サービス立ち上げ時は、とにかく爆速でコンテンツの充実・プロダクトの中身を作っていかなければいけません。

そのため、本質ではないところについては、外部サービスを頼る・参考にする事が重要になります。

認証

OAuthを推奨します。

自前でアカウント周りの機能を作成することは控えましょう。

なぜなら、、、

  • 個人開発系のアプリの場合、見ず知らずのアプリでアカウント登録を行うのは心理的な障壁がある
  • 商用、toB系のサービスの場合、個人情報はセンシティブであり、セキュリティの穴は大きなリスクになる

からです。

Google認証を持っておけば、最悪OKです。

認証まわりをまるっと、外部SaaSに頼るなら、Auth0がおすすめです。

決済

Stripe一択です。

よほどの理由がない限り、自前で作ることはないと思います。

他にも選択肢がないわけではありませんが、ここ数年SaaS系サービスにおけるStripeの使いやすさ・セキュリティ等、群を抜いている感覚です。

CSSフレームワーク

デザインが超重要なソフトウェア以外であれば、まずはCSSフレームワークに頼るのが早いです。

有名どころだと、

などがありますので、好きなものを使われるといいと思います。

すべてスクラッチCSSを作ることはおすすめしません。

技術選定に関して

Webフレームワークに関して

立ち上げ期であれば、

など、フルスタックフレームワークで作成することもありかと思います。

ただし、これらのフルスタックフレームワークは、フロントエンド・バックエンドが分化される現代において、新規開発の選択としてファーストチョイスではないと思います(現場のエンジニアがこれらに強みがあるなら、仕方ありませんが)。

そのため、フロントエンドは、

  • React
  • Vue

といったフロントエンドフレームワークを使用し、バックエンドはAPIをベースにやり取りすることを推奨します。

React vs Vueについては、全世界的にみると、Reactに軍配があるようですが、日本ではVueが強いといったガラパゴス化傾向があります。

バックエンドについては、マイクロサービスを適用することで、Go/PythonなどAPIユースケースに応じて、柔軟に変更・対応ができるかと思います。

インフラ

立ち上げ期であれば、最初はなんでも構いません。とにかくサービスの開発を優先するべきです。

今後のスケーラビリティを考慮するのであれば、クラウドの利用一択です。

Azure/GCP/AWSどれでも構いませんが、こだわりがなければとりあえずAWSでいいと思います(ネットで見つかる情報が非常に多いです)。

また、クラウド化に伴い、脱EC2を目指しましょう。

サーバーレス・コンテナ化といったレベルを検討するべきです。

また、CI/CDやCode Build/PipeLine/Depolyなどを使って、アジャイルな開発もクラウドなら簡単に導入可能です。

ぜひ、やっていきましょう。

Pythonマスターへの近道: きれいなコードでプロになる

現場のエンジニア目線でPythonのコードの書き方について、初学者から未経験エンジニアに知ってもらいたい内容です。

一般的な話が多く、現場のスタイルに制限されるものではないので色々なところで使えるかと思います。

やってほしくないこと

変数名をカタカナ日本語にしない

# だめなコード
a = [1, 2, 3, 4, 5]
goukei = sum(a)
# 良いコード
a = [1, 2, 3, 4, 5]
total = sum(a)

goukeiは日本語です。

適切な英単語に書き換えましょう。

ただし、Pythonには予約語といって使うべきではない単語があります(例えば、sumなど)。

それらの言葉は回避して使ってください。

http://www.ic.daito.ac.jp/~mizutani/python/intro8_python.html

複雑な条件分岐、ループ構造を作らない

# だめなコード
if x == 1:
    if y == 2:
        if z == 3:
elif x == 2:
    pass
elif x == 3:
    pass
# 良いコード
if x == 1 and y == 2 and z == 3:
    pass
elif x >= 2:
    pass

2重・3重となるif文の実装はやめましょう。

また、多数のelifで分岐するのもやめましょう。

for文も同様です。多重実装はNGです。

条件分岐・ループ構造は、エンジニアの力量が現れます。書き方をよく考えましょう。

素人エンジニアに最も多いのが、このケースです。

直書きしない

# だめなコード
a = [1, ,2, 3, 4, 5]

total = sum(a)

print(a)
# 良いコード

def get_total(data):
    return sum(data)

if __name__ == '__main__':
    print(get_total([1, ,2, 3, 4, 5]))

関数を使わず、直書きするのはやめましょう。

機能ごとに関数化して処理まとめることで、問題の特定がしやすくなります。

関数部分と直書き部分を混ぜない

# だめなコード

def process1():
    pass

a = process1()

def process2():
    pass

b = process2()
# 良いコード

def process1():
    pass

def process2():
    pass

a = process1()
b = process2()

関数化して書く部分、処理を行う部分は分けて書きましょう。

できれば、ファイルを分けるのもGoodです。

OOPオブジェクト指向プログラミング)の考え方を理解せず、クラス化を多様しない

オブジェクト指向プログラミングは、抽象度が高く概念的な側面があります。

なぜ、オブジェクト指向なのか?

そこで、なぜクラス化がメリットあるのか?

適切に理解していないと、クラス化して書く意味を見いだせません。

まずは、下記の本を読んでオブジェクト指向を理解しましょう。クラス化はそこからです。

https://www.amazon.co.jp/%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%81%A7%E3%81%AA%E3%81%9C%E3%81%A4%E3%81%8F%E3%82%8B%E3%81%AE%E3%81%8B-%E7%AC%AC3%E7%89%88-%E7%9F%A5%E3%81%A3%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84OOP%E3%80%81%E8%A8%AD%E8%A8%88%E3%80%81%E3%82%A2%E3%82%B8%E3%83%A3%E3%82%A4%E3%83%AB%E9%96%8B%E7%99%BA%E3%81%AE%E5%9F%BA%E7%A4%8E%E7%9F%A5%E8%AD%98-%E5%B9%B3%E6%BE%A4-%E7%AB%A0/dp/4296000187

やってほしいこと

flake8を使ってリファクタリングをする

あなたの書いたコードはどこかに欠陥があります。

Pythonには、pep8というコードの書き方に関する規約があります。

qiita.com

必ずしもすべてを守るべきかはプロジェクトに寄りますが、まずはルールを確認しましょう。

flake8というライブラリを使うと、自動で検出してくれます。

pip install flake8
flake8 <対象ファイルもしくはフォルダ>

エラーコード一覧は下記からCHECK!

qiita.com

ひとまとまりのロジックを関数化し、型ヒントを導入する

関数化については、先述しました。

型ヒントも導入しましょう。

特に、型ヒントに関しては近年のPythonバージョンにて変化が激しいので、Python 3.9, 3.10, 3.11など比較的最近のものを使いましょう。

型ヒントを用いて、関数を書くとは以下のようなことを指します。

def get_total(data: list) -> int:
    return sum(data)

データベースについて学び、効率的なデータ処理の基礎を身につける

Pythonユーザーなら、Pandasを使っているケースは多いのではないでしょうか?

Pandasはとても使いやすく、直感的にデータ操作ができるため、非常に便利なためオススメです。

ですが、ここまで紹介したような、

  • 多重ループ
  • 複雑な条件分岐

をすると、計算速度が大きく低下します。

ただし、Pandasにはデフォルトで便利なメソッドがたくさんあります。

これらを上手に活用するためには、データベースについての知識があると効率的な計算処理ができます。

例えば、以下の内容を説明できますか?

  • 結合処理とは?
  • 外部結合・内部結合の違いは?
  • SELECT, WHERE, FROM, FILTERは何を指すか?

これらを理解し、DataFrameをデータベースと見たてて処理を考えると、効率的な計算を行うことができます。

入門書で結構です。一読してみてください。