ローレンツ方程式 SciPy

ローレンツ方程式

非線形微分方程式であるローレンツ方程式を解き、その結果を3次元のグラフで表示してみましょう。

ローレンツ系は次の3つの非線形連立微分方程式からなります。

$$
dx/dt = σ(y - x)
$$
$$
dy/dt = x(ρ - z) - y
$$
$$
dz/dt = xy - βz
$$

ここで、$σ、ρ、β$は正の定数です。

以下のPythonコードは、上記のローレンツ方程式を解き、その結果を3Dグラフで表示します。

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
32
33
34
35
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def lorenz_system(current_state, t):
sigma = 10.0 # σの値
rho = 28.0 # ρの値
beta = 8.0 / 3.0 # βの値

x, y, z = current_state # 現在のx, y, zの値
dx_dt = sigma * (y - x) # dx/dt
dy_dt = x * (rho - z) - y # dy/dt
dz_dt = x * y - beta * z # dz/dt

return [dx_dt, dy_dt, dz_dt]

# 初期状態
initial_state = [1.0, 1.0, 1.0]

# 時間の範囲を定義
t = np.arange(0.0, 50.0, 0.01)

# 微分方程式を解く
solution = odeint(lorenz_system, initial_state, t)

# 結果を3Dグラフで表示
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot(solution[:, 0], solution[:, 1], solution[:, 2])
ax.set_title('Lorenz Attractor')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()

このコードを走らせると、解の軌道がローレンツアトラクターと呼ばれる蝶形の図形を形成します。

これはカオス理論を象徴する図形としてよく知られています。

[実行結果]

ソースコード解説

このコードは、ローレンツ方程式を数値的に解き、結果を3Dグラフとして表示するものです。

1. 必要なライブラリをインポートする:

numpy(数値計算のため)、scipy.integrateからのodeint(常微分方程式を解くため)、matplotlib.pyplot(グラフ描画のため)、mpl_toolkits.mplot3dからのAxes3D(3Dプロットのため)をインポートします。

2. ローレンツ方程式を定義する:

lorenz_system関数は、ローレンツ方程式を定義しています。
この方程式は3つの微分方程式からなり、特定のパラメータ(sigmarhobeta)と現在の状態(xyz)を受け取ります。

それぞれの微分方程式は次のように表されます。
$$
dx/dt = sigma * (y - x)
$$
$$
dy/dt = x * (rho - z) - y
$$
$$
dz/dt = x * y - beta * z
$$

3. 初期状態を設定する:

initial_stateは、$x、y、z$の初期値を$1.0$として設定します。

4. 時間の範囲を定義する:

tは$0$から$50$までの時間の範囲を$0.01$刻みで定義します。

5. 微分方程式を解く:

odeint関数を使用して、lorenz_system関数に初期状態と時間の範囲を渡して微分方程式を解きます。

6. 結果を3Dグラフで表示する:

solutionは微分方程式の解です。
これを3Dグラフでプロットして、XYZ軸に解の値をプロットし、Lorenz Attractorというタイトルをつけます。

これにより、ローレンツアトラクタとして知られる複雑な非線形系の挙動が視覚化されます。

3次元ガウス関数

3次元ガウス関数は、多変量ガウス分布を表現するための関数です。

以下は3次元ガウス関数の式です。

$$
[ f(x, y) = \frac{1}{2\pi\sigma_x\sigma_y}e^{-\frac{1}{2}\left(\frac{(x-\mu_x)^2}{\sigma_x^2} + \frac{(y-\mu_y)^2}{\sigma_y^2}\right)} ]
$$

ここで、$ (x) $と$ (y) $は変数で、$ (\mu_x) $と$ (\mu_y) $はそれぞれ$ (x) $と$ (y) $の平均、$ (\sigma_x) $と$ (\sigma_y) $は標準偏差です。

Pythonで3次元ガウス関数をグラフ化するための例を示します。

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
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D

def gaussian_2d(x, y, mux, muy, sigmax, sigmay):
return (1. / (2 * np.pi * sigmax * sigmay) *
np.exp(-0.5 * ((x - mux)**2 / sigmax**2 + (y - muy)**2 / sigmay**2)))

# ガウス関数のパラメータ設定
mux = 0
muy = 0
sigmax = 1
sigmay = 1

x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
x, y = np.meshgrid(x, y)
z = gaussian_2d(x, y, mux, muy, sigmax, sigmay)

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(x, y, z, cmap='viridis')

ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.set_title('3D Gaussian Function')

plt.show()

このコードでは、2つの変数$ (x) $と$ (y) $のガウス関数を計算し、3次元プロットを作成しています。

平均標準偏差の値を変更すると、関数の形状がどのように変わるかを観察できます。

[実行結果]

ソースコード解説

このコードは、2変数の2次元ガウス関数を作成し、その関数を3次元プロットで視覚化するためのものです。

以下、詳細な説明です:

1. import文:

  • matplotlib.pyplotからpltをインポートしています。
    これはグラフの描画に使用されます。
  • numpyからnpをインポートしています。
    これは数値計算に使用されます。
  • mpl_toolkits.mplot3dからAxes3Dをインポートしています。
    これは3次元プロットのための機能を提供します。

2. gaussian_2d関数:

  • 2変数の2次元ガウス関数を定義しています。
    この関数は、座標 (x, y) に対するガウス関数の値を返します。

3. ガウス関数のパラメータ設定:

  • muxmuysigmaxsigmay は、ガウス関数の平均と標準偏差を設定するためのパラメータです。

4. np.linspace()を使って xy の値を生成:

  • np.linspace()は指定された範囲内で一定間隔の値を生成します。

5. np.meshgrid()を使って xy の格子を作成:

  • np.meshgrid()xy の2つの1次元配列を受け取り、それぞれの組み合わせに対する格子を作成します。

6. gaussian_2d()関数を使って xy に対するガウス関数の値 z を計算:

  • gaussian_2d()関数は、先ほど定義したガウス関数を使用して、各 (x, y) 座標でのガウス関数の値を計算します。

7. plt.figure()を使って図を作成:

  • plt.figure()は新しい図を作成します。

8. fig.add_subplot()を使って3Dサブプロットを追加:

  • fig.add_subplot()は図に新しい3次元のサブプロットを追加します。

9. ax.plot_surface()を使って3Dプロットを作成:

  • ax.plot_surface()xyz 座標上のデータから3次元プロットを作成します。
    cmap='viridis'はカラーマップを設定します。

10. ax.set_xlabel()ax.set_ylabel()ax.set_zlabel()を使って軸ラベルを設定:

  • それぞれ X、Y、Z 軸のラベルを設定します。

11. ax.set_title()を使ってグラフタイトルを設定:

  • グラフにタイトルを追加します。

12. plt.show()でグラフを表示:

  • plt.show()は作成したグラフを表示します。

このコードは、2変数の2次元ガウス関数を計算し、それを3次元プロットとして視覚化しています。

球体の方程式

球体の方程式

3次元方程式の例として、球体の方程式を挙げて、そのグラフ化を行います。

球体の方程式は次のように表されます。

$$
[ x^2 + y^2 + z^2 = r^2 ]
$$

これは、原点を中心とし、半径が$ (r) $の球の方程式です。

Pythonでこの方程式をグラフ化するには、Matplotlibを使用して3次元のプロットを行います。

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
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

r = 1 # 球の半径

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

# x, y, zの値を生成
theta = np.linspace(0, 2 * np.pi, 100)
phi = np.linspace(0, np.pi, 100)
x = r * np.outer(np.cos(theta), np.sin(phi))
y = r * np.outer(np.sin(theta), np.sin(phi))
z = r * np.outer(np.ones(100), np.cos(phi))

# 球をプロット
ax.plot_surface(x, y, z, color='b', alpha=0.5)

# 軸ラベルの設定
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')

plt.show()

このコードでは、球の方程式をパラメータ化して球体を描画しています。

球の半径解像度を変更することで、異なる球を描画することができます。

[実行結果]

ソースコード解説

このコードは、Matplotlibを使用して3次元の球を描画するものです。

それぞれの部分について説明します。

1. モジュールのインポート:

1
2
3
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

必要なライブラリをインポートしています。
matplotlib.pyplotはグラフを描画するために使用され、mpl_toolkits.mplot3dは3次元プロットをサポートするために必要です。
numpyは数学的な演算を行うために使用されます。

2. 球の半径の設定:

1
r = 1  # 球の半径

描画する球の半径を設定しています。

3. FigureとAxesの設定:

1
2
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

plt.figure()を使用してFigureオブジェクトを作成し、fig.add_subplot()でAxesオブジェクトを作成しています。
ここでは、3次元プロットを行うためにprojection='3d'を指定しています。

4. x, y, zの値の生成:

1
2
3
4
5
theta = np.linspace(0, 2 * np.pi, 100)
phi = np.linspace(0, np.pi, 100)
x = r * np.outer(np.cos(theta), np.sin(phi))
y = r * np.outer(np.sin(theta), np.sin(phi))
z = r * np.outer(np.ones(100), np.cos(phi))

球の表面を構成する$x, y, z$座標の値を生成しています。
np.linspace()は指定された範囲で等間隔の値を生成し、np.outer()は2つの配列の外積を計算します。

5. 球のプロット:

1
ax.plot_surface(x, y, z, color='b', alpha=0.5)

ax.plot_surface()を使用して球を描画しています。
ここでは、生成したx, y, z座標の値を使用し、color='b'で青色、alpha=0.5で透明度を設定しています。

6. 軸ラベルの設定:

1
2
3
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')

$x$軸、$y$軸、$z$軸のラベルを設定しています。

7. グラフの表示:

1
plt.show()

最後にplt.show()を使ってグラフを表示します。
これにより、3次元の球が表示されます。

ロジスティックマップ

ロジスティックマップ

非線形の関数としてロジスティックマップを例に挙げます。

ロジスティックマップは、次のような非線形差分方程式で定義されます:

$$
x[n+1] = r * x[n] * (1 - x[n])
$$

ここで、$ n $は離散時間、$ x[n] $は時刻nにおける値、$ r $は制御パラメータです。

この方程式は生物個体数などの成長モデルに用いられることがあります。

パラメータ$r$により、周期$ 2, 4, 8, …, caos $など様々なダイナミクスを見ることができます。

以下に、ロジスティックマップをPythonでグラフ化するコードを示します。

これは$r$を$0.5$から$4.0$まで$0.01$間隔で変化させ、$x$の時間発展をプロットするものです:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import numpy as np
import matplotlib.pyplot as plt

def logistic(r, x):
return r * x * (1 - x)

x = np.linspace(0, 1)
fig, ax = plt.subplots(1, 1, figsize=(6, 10), dpi=80)
for r in np.linspace(0.5, 4.0, 400):
X = np.empty(1000)
X[0] = 0.1
for i in range(999):
X[i+1] = logistic(r, X[i])
ax.plot([r]*1000, X, ',k', alpha=0.2)

ax.set_xlim(0.4, 4)
ax.set_title("Bifurcation diagram")
plt.show()

これによりビフルケーション図が得られます。

点々とした部分がカオス性を示し、この隙間の生じるパターンはフラクタル性を示します。

また、一定範囲の$ r $での値の振動はピリオドダブリングと呼ばれ、カオスへと向かう典型的な挙動を表しています。

ソースコード解説

このPythonのコードは、ロジスティック写像の分岐図(Bifurcation diagram)を描画するものです。

それぞれの部分について詳しく説明します。

ライブラリのインポート

1
2
import numpy as np
import matplotlib.pyplot as plt
  • numpyは数値計算をサポートするPythonライブラリで、配列操作や数値計算を高速に行います。
  • matplotlib.pyplotはグラフ描画ライブラリです。

ロジスティック写像の関数

1
2
def logistic(r, x):
return r * x * (1 - x)
  • logistic関数はロジスティック写像の式を表しています。

分岐図の作成

1
2
3
4
5
6
7
8
x = np.linspace(0, 1)
fig, ax = plt.subplots(1, 1, figsize=(6, 10), dpi=80)
for r in np.linspace(0.5, 4.0, 400):
X = np.empty(1000)
X[0] = 0.1
for i in range(999):
X[i+1] = logistic(r, X[i])
ax.plot([r]*1000, X, ',k', alpha=0.2)
  • np.linspace(0, 1)で0から1までの間を等間隔に分割した配列xを作成します。
  • fig, ax = plt.subplots(1, 1, figsize=(6, 10), dpi=80)でグラフのサイズを設定します。
  • for r in np.linspace(0.5, 4.0, 400):でパラメータrの範囲を指定します。
    rは0.5から4.0の間を400ステップで変化します。
  • ロジスティック写像を使って、与えられたパラメータrにおける1000ステップの反復を計算し、それをプロットします。
  • ax.plot([r]*1000, X, ',k', alpha=0.2)で分岐図を描画します。
    [r]*1000rを1000回繰り返した配列を作成し、それとXをプロットします。

グラフの設定

1
2
3
ax.set_xlim(0.4, 4)
ax.set_title("Bifurcation diagram")
plt.show()
  • ax.set_xlim(0.4, 4)でx軸の範囲を設定します。
  • ax.set_title("Bifurcation diagram")でグラフのタイトルを設定します。
  • plt.show()でグラフを表示します。

このコードは、ロジスティック写像による分岐図を描画するためのもので、特定のパラメータ範囲での振る舞いを可視化します。

流体力学 SciPy

流体力学

流体力学の問題の1つとして、流れの中の速度分布を考えてみましょう。

例として、流れが円管内を通る場合の速度分布を解析してみます。

ナビエ・ストークス方程式を仮定し、理想的な流れを対象にします。

以下は、円管内の流れにおける速度分布の解析グラフ化の例です。

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
32
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import fsolve

# パラメータの設定
R = 1.0 # 円管の半径
viscosity = 0.1 # 粘度係数

# ナビエ・ストークス方程式の関数
def equation(u):
return u - (1 / R) * (0.5 * viscosity) * ((1 - (u ** 2)) / u)

# 初期推定値
initial_guess = 0.1

# 方程式を解いて速度分布を求める
u_solution = fsolve(equation, initial_guess)

# 半径方向の位置
r_values = np.linspace(0, R, 100)

# 速度分布の計算
u_values = (1 / R) * (0.5 * viscosity) * ((1 - (u_solution ** 2)) / u_solution) * (1 - (r_values / R) ** 2)

# 結果をグラフ化
plt.figure(figsize=(8, 6))
plt.plot(r_values, u_values)
plt.xlabel('Radius')
plt.ylabel('Velocity')
plt.title('Velocity Distribution in Pipe Flow')
plt.grid(True)
plt.show()

このコードでは、ナビエ・ストークス方程式の近似解析を行い、円管内の速度分布を計算しています。

結果はMatplotlibを使用してグラフ化されます。

得られた速度分布は、円管内の中心から周辺への速度変化を示しています。

[実行結果]

ソースコード解説

このPythonのコードは、円管内の流れにおける速度分布を解析し、結果をグラフ化するためのものです。

それぞれの部分について詳しく説明します。

ライブラリのインポート

1
2
3
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import fsolve
  • numpyは数値計算をサポートするPythonライブラリで、行列や配列などの高性能な数値計算機能を提供します。
  • matplotlib.pyplotはデータを視覚化するためのグラフ描画ライブラリです。
    pltとして一般的にエイリアスされます。
  • scipy.optimize.fsolve非線形方程式の数値解を見つけるためのSciPyライブラリの関数です。

パラメータの設定

1
2
R = 1.0  # 円管の半径
viscosity = 0.1 # 粘度係数
  • Rは円管の半径を表し、この例では$1.0$に設定されています。
  • viscosityは流体の粘度係数を表し、この例では$0.1$に設定されています。

ナビエ・ストークス方程式の関数

1
2
def equation(u):
return u - (1 / R) * (0.5 * viscosity) * ((1 - (u ** 2)) / u)
  • equation関数は、円管内の流れにおける速度分布を表すナビエ・ストークス方程式の非線形方程式を定義します。

方程式を解いて速度分布を求める

1
2
initial_guess = 0.1
u_solution = fsolve(equation, initial_guess)
  • fsolve関数を使用して、equation関数を解くことで速度分布の解析解を計算します。
    initial_guessは初期推定値を表します。

半径方向の位置の計算

1
r_values = np.linspace(0, R, 100)
  • np.linspace関数を使用して、$0$から円管の半径(R)までの範囲を$100$等分した半径方向の位置を作成します。

速度分布の計算

1
u_values = (1 / R) * (0.5 * viscosity) * ((1 - (u_solution ** 2)) / u_solution) * (1 - (r_values / R) ** 2)
  • ナビエ・ストークス方程式の解から、円管内の各位置での速度分布を計算します。

結果をグラフ化

1
2
3
4
5
6
7
plt.figure(figsize=(8, 6))
plt.plot(r_values, u_values)
plt.xlabel('Radius')
plt.ylabel('Velocity')
plt.title('Velocity Distribution in Pipe Flow')
plt.grid(True)
plt.show()
  • matplotlibを使用して、計算された速度分布を円管の半径に対する速度としてグラフ化します。
    plt.xlabelplt.ylabelplt.titleを使用して、軸のラベルとグラフのタイトルを設定し、plt.grid(True)でグリッドを表示します。
    plt.show()でグラフを表示します。

このコードは、ナビエ・ストークス方程式を使用して円管内の流れにおける速度分布を解析し、その結果を可視化するものです。

グラフ解説

このグラフは円管内の流れにおける速度分布を示しています。

[実行結果]

x軸は円管の半径を示し、y軸はその位置における流速を表しています。

解析した速度分布は、理想的な流れ条件を仮定しています。
円管内の中心$ (r=0)$では、流速は最大になります。
そして、円管の壁に近づくにつれて流速はゼロに近づきます。

この結果は、円管内の流れにおいて、中心部分の流れが最も速く壁に近づくほど流速が低くなることを示しています。
このような速度分布は、レイノルズ数流体の粘度などの条件によって変化する可能性がありますが、円管流れの一般的な傾向を示しています。

また、このグラフは円管内の速度分布が放射状に変化していることを示しています。
中心部から外側に向かって流速が減少していることが分かります。
このような速度プロファイルは、流体が壁面で摩擦を受けることによって生じる、粘性効果によるものです。

グループ化/集約 Polars

グループ化/集約

Polarsの一つの強みは、大規模データセットを高速に処理する能力です。

その最適化された処理エンジンのおかげで、大量のデータを即座に変換整理したり、集計することが容易となり、パフォーマンスを大いに向上させます。

また、シンプルで明確なAPIPolarsの大きな魅力の一つです。

これにより、ユーザーはpandasのような一般的なデータ分析ライブラリと同様のユーザビリティを享受しながら、より大きなデータ量を扱うことができます。

以下に、Polarsを使ったデータのグループ化集約のサンプルコードを示します。

1
2
3
4
5
6
7
8
9
10
11
12
13
import polars as pl

# データフレームの作成
df = pl.DataFrame({
"fruits": ["apple", "banana", "banana", "apple", "apple", "banana", "banana", "apple"],
"sales": [5, 6, 8, 9, 5, 6, 7, 9],
"city": ["Tokyo", "Tokyo", "Tokyo", "London", "London", "London", "New York", "New York"]
})

# 都市ごと、果物ごとの総売上を計算
df_grouped = df.groupby(["city", "fruits"]).agg([pl.col("sales").sum().alias("total_sales")])

print(df_grouped)

上記のコードは、都市ごとに果物の売上合計を計算するシンプルな例です。

都市と果物ごとにグループ化し、各グループの“sales”列の合計を計算します。

[実行結果]

shape: (6, 3)
┌──────────┬────────┬─────────────┐
│ city     ┆ fruits ┆ total_sales │
│ ---      ┆ ---    ┆ ---         │
│ str      ┆ str    ┆ i64         │
╞══════════╪════════╪═════════════╡
│ Tokyo    ┆ apple  ┆ 5           │
│ Tokyo    ┆ banana ┆ 14          │
│ New York ┆ banana ┆ 7           │
│ London   ┆ apple  ┆ 14          │
│ London   ┆ banana ┆ 6           │
│ New York ┆ apple  ┆ 9           │
└──────────┴────────┴─────────────┘

shape: (6, 3) はこのデータフレームが6行3列であることを示しています。
列は city、fruits、そして total_sales となります。

それぞれの行を見てみましょう:

  • 1行目:
    東京でのリンゴの総売上は5と計算されています。
  • 2行目:
    東京でのバナナの総売上は14と計算されています。
  • 3行目:
    ニューヨークでのバナナの総売上は7と計算されています。
  • 4行目:
    ロンドンでのリンゴの総売上は14と計算されています。
  • 5行目:
    ロンドンでのバナナの総売上は6と計算されています。
  • 6行目:
    ニューヨークでのリンゴの総売上は9と計算されています。

これにより、各都市で各フルーツの総販売量を直観的に理解することができます。

このようなデータの表示は、日々の販売活動の理解や、将来的な販売戦略の策定に非常に有用です。

フルーツの種類と都市に基づいてデータを分析することで、どの商品がどの市場でよく売れているのか洞察を得ることが可能です。

Polars

Polarsの概要

Polarsは、高速なDataFrame操作を可能にするライブラリで、Apache Arrowの列指向メモリモデルを使用しています。

Polarsは、Rustで書かれており、多スレッドのクエリエンジンを使用して効率的な並列処理を実現しています。

また、Polarsはオープンソースであり、MITライセンスで利用できます。

サンプルソース

以下に、Polarsを使用してDataFrameを作成し、そのDataFrameに対して操作を行う例を示します。

まず、必要なライブラリをインポートします。

1
import polars as pl

次に、DataFrameを作成します。

1
2
3
4
5
6
7
df = pl.DataFrame(
{
"name": ["John", "Sue", "Tom", "Alice"],
"age": [23, 21, 19, 18],
"grade": [90, 85, 78, 92],
}
)

次に、DataFrameに対して操作を行います。

例えば、特定の列を選択したり、特定の条件に基づいて行をフィルタリングしたり、新しい列を作成したりすることができます。

1
2
3
4
5
6
7
8
# 特定の列を選択
selected_df = df.select(["name", "age"])

# 特定の条件に基づいて行をフィルタリング
filtered_df = df.filter(pl.col("age") > 20)

# 新しい列を作成
df = df.with_columns(pl.col("age") + 1)

最後に、DataFrameを表示します。

1
2
3
print(selected_df)
print(filtered_df)
print(df)

[実行結果]

shape: (4, 2)
┌───────┬─────┐
│ name  ┆ age │
│ ---   ┆ --- │
│ str   ┆ i64 │
╞═══════╪═════╡
│ John  ┆ 23  │
│ Sue   ┆ 21  │
│ Tom   ┆ 19  │
│ Alice ┆ 18  │
└───────┴─────┘
shape: (2, 3)
┌──────┬─────┬───────┐
│ name ┆ age ┆ grade │
│ ---  ┆ --- ┆ ---   │
│ str  ┆ i64 ┆ i64   │
╞══════╪═════╪═══════╡
│ John ┆ 23  ┆ 90    │
│ Sue  ┆ 21  ┆ 85    │
└──────┴─────┴───────┘
shape: (4, 3)
┌───────┬─────┬───────┐
│ name  ┆ age ┆ grade │
│ ---   ┆ --- ┆ ---   │
│ str   ┆ i64 ┆ i64   │
╞═══════╪═════╪═══════╡
│ John  ┆ 24  ┆ 90    │
│ Sue   ┆ 22  ┆ 85    │
│ Tom   ┆ 20  ┆ 78    │
│ Alice ┆ 19  ┆ 92    │
└───────┴─────┴───────┘

このコードは、Polarsを使用してDataFrameを作成し、そのDataFrameに対して操作を行い、その結果を表示します。

このように、Polarsを使用することで、DataFrameの操作を効率的に行うことができます。


Polarsは、高速なDataFrame操作を可能にするライブラリで、多くの操作が可能です。

以下に、一部の操作を示します。

1. 行の選択

DataFrame内の1行を選択するには、row()メソッドを使用して行番号を渡します。
複数の行を選択するためには、filter()関数を使用します。

1
2
# 最初の行を取得する
df.row(0)

[実行結果]

('John', 24, 90)
1
2
3
# 'name'列の値が'Tom'の行を取得する
res = df.filter(pl.col('name') == 'Tom')
print(res)

[実行結果]

shape: (1, 3)
┌──────┬─────┬───────┐
│ name ┆ age ┆ grade │
│ ---  ┆ --- ┆ ---   │
│ str  ┆ i64 ┆ i64   │
╞══════╪═════╪═══════╡
│ Tom  ┆ 20  ┆ 78    │
└──────┴─────┴───────┘

2. 論理演算子の使用

Polarsでは、論理演算子を使用して複数の条件を指定できます。

1
2
3
# 'name'列の値が'John'または'Alice'の行を取得する
res = df.filter((pl.col('name') == 'John') | (pl.col('name') == 'Alice'))
print(res)

[実行結果]

shape: (2, 3)
┌───────┬─────┬───────┐
│ name  ┆ age ┆ grade │
│ ---   ┆ --- ┆ ---   │
│ str   ┆ i64 ┆ i64   │
╞═══════╪═════╪═══════╡
│ John  ┆ 24  ┆ 90    │
│ Alice ┆ 19  ┆ 92    │
└───────┴─────┴───────┘

3. 結果の格納

Polarsは演算結果を新しい列として格納する際の記述方法に優れています。
例えば、新しい列を作成するときには、普通の四則演算以外の結果も格納できます。

1
2
3
# 'age'列の値を2で割った結果を新しい列'age_half'に格納する
df2 = df.with_columns(pl.col("age") / 2)
print(df2)

[実行結果]

shape: (4, 3)
┌───────┬──────┬───────┐
│ name  ┆ age  ┆ grade │
│ ---   ┆ ---  ┆ ---   │
│ str   ┆ f64  ┆ i64   │
╞═══════╪══════╪═══════╡
│ John  ┆ 12.0 ┆ 90    │
│ Sue   ┆ 11.0 ┆ 85    │
│ Tom   ┆ 10.0 ┆ 78    │
│ Alice ┆ 9.5  ┆ 92    │
└───────┴──────┴───────┘

これらの操作は、Polarsの強力な機能の一部を示しています。

Polarsは、DataFrameの操作を効率的に行うための強力なツールであり、これらの操作を通じて、データ分析データ操作の幅広いタスクを効率的に実行することができます。

色彩の相補色 SciPy

色彩の相補色

美術関連の問題として、色彩の相補色を見つける問題を考えてみましょう。

相補色は、RGB色空間内で最も対照的な色です。

与えられた色に対して、それに最も近い相補色を見つけることができます。

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
32
33
34
35
36
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import distance

# 関数定義: RGB色空間内で最も近い相補色を計算する
def find_complementary_color(color):
# 相補色の定義: RGB値の各要素を1から引くことで相補色を得る
complementary_color = [1 - channel for channel in color]
return complementary_color

# 与えられた色(RGB値)
given_color = [0.4, 0.2, 0.9] # 例えば青系統の色

# 相補色を計算
complementary_color = find_complementary_color(given_color)

# 色の距離を計算
distance_value = distance.euclidean(given_color, complementary_color)

# グラフ化
colors = [np.array(given_color), np.array(complementary_color)]
labels = ['Given Color', 'Complementary Color']

plt.figure(figsize=(8, 4))
for i in range(2):
plt.subplot(1, 2, i+1)
plt.bar(range(len(colors[i])), colors[i], color=['r', 'g', 'b'], alpha=0.6)
plt.xticks(range(len(colors[i])), ['R', 'G', 'B'])
plt.title(labels[i])

plt.tight_layout()
plt.show()

print(f"The given color is: {given_color}")
print(f"The complementary color is: {complementary_color}")
print(f"The distance between these colors is: {distance_value}")

このコードは、与えられた色(例えば青系統の色)のRGB値を取り、その色に最も近い相補色を見つけます。

そして、2つの色を棒グラフで示し、それらの色の距離を表示します。

色の距離が大きいほど、その色はより対照的であると考えられます。

[実行結果]

ソースコード解説

このソースコードは、Pythonで色彩処理を行うためのプログラムです。

以下はコードの構造と機能の詳細な説明です:

ライブラリのインポート

1
2
3
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import distance
  • numpy:数値計算を行うためのライブラリ。
  • matplotlib.pyplot:グラフを描画するためのライブラリ。
  • scipy.spatial.distance:距離を計算するためのライブラリ。

相補色を見つける関数の定義

1
2
3
def find_complementary_color(color):
complementary_color = [1 - channel for channel in color]
return complementary_color
  • find_complementary_color 関数は、与えられた色に対する相補色を計算します。
  • 各RGBチャンネルの値から1を引くことで相補色を生成しています。

与えられた色の定義

1
given_color = [0.4, 0.2, 0.9]
  • この行では、青系統の色を表すRGB値 [0.4, 0.2, 0.9] を定義しています。

相補色の計算

1
complementary_color = find_complementary_color(given_color)
  • find_complementary_color 関数を使って、与えられた色の相補色を計算しています。

色の距離の計算

1
distance_value = distance.euclidean(given_color, complementary_color)
  • scipydistance モジュールの euclidean 関数を使って、与えられた色とその相補色の間の距離を計算しています。

グラフの描画

1
2
3
4
5
6
7
8
9
10
11
12
colors = [np.array(given_color), np.array(complementary_color)]
labels = ['Given Color', 'Complementary Color']

plt.figure(figsize=(8, 4))
for i in range(2):
plt.subplot(1, 2, i+1)
plt.bar(range(len(colors[i])), colors[i], color=['r', 'g', 'b'], alpha=0.6)
plt.xticks(range(len(colors[i])), ['R', 'G', 'B'])
plt.title(labels[i])

plt.tight_layout()
plt.show()
  • 2つのグラフを描画します。左側には与えられた色、右側にはその相補色を示すバー形式のグラフが表示されます。
  • 色の強度は、RGBチャンネルの値を表しており、各バーの高さが対応する色の成分を示しています。

結果の出力

1
2
3
print(f"The given color is: {given_color}")
print(f"The complementary color is: {complementary_color}")
print(f"The distance between these colors is: {distance_value}")
  • 最後に、与えられた色、その相補色、およびその間の距離をコンソールに表示します。

このプログラムは、与えられた色とその相補色の関係性を理解しやすく視覚化し、色の距離を数値化して表示することで、色彩理論に関する概念を理解するのに役立ちます。

結果解説

下記の結果は、与えられた色とその相補色に関する情報を示しています。

[実行結果]

The given color is: [0.4, 0.2, 0.9]
The complementary color is: [0.6, 0.8, 0.09999999999999998]
The distance between these colors is: 1.019803902718557
  1. 与えられた色:
  • RGB値が [0.4, 0.2, 0.9] となっています。
  • これは、赤の成分が40%、緑の成分が20%、青の成分が90%である色を示しています。
    青が最も強く、赤と緑が弱い色です。
  1. 相補色:
  • 計算された相補色のRGB値[0.6, 0.8, 0.09999999999999998] です。
  • この色は、与えられた色と対照的であり、赤と緑の成分が高く、青の成分が低い色です。
    つまり、青系統の色に対して赤と緑が強く現れる色です。
  1. 色の距離:
  • 与えられた色と相補色の間の距離は、1.019803902718557 です。
  • この値は、色彩空間内で2つの色がどれだけ対照的かを示しています。
    この場合、与えられた色とその相補色はかなり対照的であることを示しています。

グラフ解説

[実行結果]

このグラフは、与えられた色とその相補色を示しています。

それぞれの棒グラフは、RGB色空間内の3つのチャンネル(赤、緑、青)を表しています。

  1. 左側のグラフ(Given Color)

    • 与えられた色のRGB値が示されています。
    • 各バーは、赤、緑、青のチャンネルを示し、それぞれの色の強度を表しています。
    • 例えば、青系統の色が与えられた場合、青のバーが最も高くなるでしょう。
  2. 右側のグラフ(Complementary Color)

    • 計算された相補色のRGB値が示されています。
    • 同様に、赤、緑、青のバーがそれぞれの色の強度を表しています。
    • 相補色は、与えられた色と対照的な色であるため、バーの高さが与えられた色とは異なる場合があります。

これらのグラフを見ることで、与えられた色とその相補色の各色成分の相違類似性が視覚的に理解できます。

また、それらの色の距離も計算され、その差異の大きさが数値として示されています。

色の距離が大きいほど、色の相補性が高いと考えられます。

振動子の運動方程式 SciPy

振動子の運動方程式

物理に関連する問題として、振動子の運動方程式を解いてみましょう。

例として、単振動子の運動を考えます。

単振動子は、バネにつながれた質点が減衰力外力を受けずに振動するシンプルなモデルです。

振動子の運動方程式は、次のように表されます。

$$
[
m \frac{d^2x}{dt^2} + c \frac{dx}{dt} + kx = 0
]
$$

ここで、$ (m) $は質量、$ (c) $は減衰係数、$ (k) $はバネ定数です。

これをSciPyを使って数値的に解いて、結果をグラフ化してみましょう。

以下は、質量$ (m = 1) $、減衰係数$ (c = 0.1) $、バネ定数$ (k = 1) $の単振動子の運動方程式を解く例です。

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
32
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt

# 運動方程式を定義
def harmonic_oscillator(x, t, m, c, k):
dxdt = x[1] # 速度を表す状態変数
dvdt = -(c/m) * x[1] - (k/m) * x[0] # 加速度を表す状態変数
return [dxdt, dvdt]

# 初期条件とパラメータ
x0 = [1.0, 0.0] # 初期位置と初速度
m = 1.0 # 質量
c = 0.1 # 減衰係数
k = 1.0 # バネ定数

# 時間の範囲
t = np.linspace(0, 20, 1000)

# 運動方程式を解く
solution = odeint(harmonic_oscillator, x0, t, args=(m, c, k))

# 位置と速度の時間変化をプロット
plt.figure(figsize=(8, 6))
plt.plot(t, solution[:, 0], label='Position')
plt.plot(t, solution[:, 1], label='Velocity')
plt.xlabel('Time')
plt.ylabel('Value')
plt.title('Harmonic Oscillator Motion')
plt.legend()
plt.grid(True)
plt.show()

このコードでは、Scipyの odeint を使用して単振動子の運動方程式を数値的に解いています。

結果は時間と共に変化する位置と速度の変化をグラフ化しています。

位置と速度のグラフが振動する様子が見られます。

[実行結果]

ソースコード解説

このコードは、単振動子(harmonic oscillator)の運動方程式を解いて、その結果をグラフ化するものです。

以下にソースコードの各部分を説明します。

1. モジュールのインポート:

1
2
3
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
  • numpy は数値計算用ライブラリで、数値配列を処理するために使われます。
  • scipy.integrateodeint常微分方程式を数値的に解くための関数です。
  • matplotlib.pyplot はグラフ描画ライブラリで、データを可視化するために使用されます。

2. 運動方程式の定義:

1
2
3
4
def harmonic_oscillator(x, t, m, c, k):
dxdt = x[1] # 速度を表す状態変数
dvdt = -(c/m) * x[1] - (k/m) * x[0] # 加速度を表す状態変数
return [dxdt, dvdt]
  • harmonic_oscillator 関数は、単振動子の運動方程式を定義しています。
  • 位置$ (x) $と時間$ (t) $を引数として受け取り、速度$ (dx/dt) $と加速度$ (d^2x/dt^2) $を計算して返します。

3. 初期条件とパラメータの設定:

1
2
3
4
x0 = [1.0, 0.0]  # 初期位置と初速度
m = 1.0 # 質量
c = 0.1 # 減衰係数
k = 1.0 # バネ定数
  • 初期位置と初速度、質量、減衰係数、バネ定数を設定します。

4. 時間の設定:

1
t = np.linspace(0, 20, 1000)
  • np.linspace を使って、$0$から$20$までの範囲を$1000$個の等間隔な点に区切り、時間の配列を作成します。

5. 運動方程式の解を計算:

1
solution = odeint(harmonic_oscillator, x0, t, args=(m, c, k))
  • odeint 関数を使用して、運動方程式を数値的に解きます。
  • harmonic_oscillator 関数に初期条件とパラメータを渡し、時間 t の範囲での解を求めます。

6. 位置と速度の時間変化をプロット:

1
2
3
4
5
6
7
8
9
plt.figure(figsize=(8, 6))
plt.plot(t, solution[:, 0], label='Position')
plt.plot(t, solution[:, 1], label='Velocity')
plt.xlabel('Time')
plt.ylabel('Value')
plt.title('Harmonic Oscillator Motion')
plt.legend()
plt.grid(True)
plt.show()
  • matplotlib を使用して、時間に対する位置と速度の変化折れ線グラフでプロットします。
  • solution[:, 0] は位置、solution[:, 1] は速度の結果を表します。
  • グラフには軸ラベル、タイトル、凡例、グリッド線が追加されます。
  • 最後に plt.show() でグラフを表示します。

グラフ解説

[実行結果]

このグラフは、単振動子の振動を時間と共に表現したものです。

1. 位置(Position)のグラフ:

  • 横軸は時間を表し、縦軸は単振動子の位置を示しています。
  • グラフは、時間の経過とともに振動子の位置が変化する様子を示しています。
    振動子は、特定の周期で正弦波のような動きをします。
    このグラフはその振動の様子を可視化しています。

2. 速度(Velocity)のグラフ:

  • 横軸は時間を表し、縦軸は単振動子の速度を示しています。
  • 速度グラフは、時間と共に速度がどのように変化するかを示しています。
    振動子は、位置が最大または最小になるときに速度が0になり、その間に速度が最大になることが一般的です。
    このグラフはその速度の変化を示しています。

これらのグラフから、単振動子が周期的に位置と速度が変化する様子を観察できます。

位置と速度の変化が互いに90度ずれた位相で起こり、振動が継続していることがわかります。

航空旅客数の予測 Prophet

航空旅客数の予測

Facebookが開発した時系列分析ライブラリProphetを用いて、航空旅客数のデータを分析し、将来の旅客数を予測してみましょう。

まず、以下のようにライブラリをインストールします。

1
!pip install prophet

次に、以下のコードを使ってデータを分析・予測します。

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
import pandas as pd
from prophet import Prophet
import matplotlib.pyplot as plt

# データの読み込み
df = pd.read_csv('https://raw.githubusercontent.com/jbrownlee/Datasets/master/airline-passengers.csv')

# 列名の変更
df.columns = ['ds', 'y']
df['ds'] = pd.to_datetime(df['ds'])

# モデルの訓練
m = Prophet(yearly_seasonality=True)
m.fit(df)

# 未来の予測のためのデータフレームの作成
future = m.make_future_dataframe(periods=365)
forecast = m.predict(future)

# 予測のプロット
m.plot(forecast)
plt.show()

# トレンドとコンポーネントの表示
m.plot_components(forecast)
plt.show()

ここでは、航空旅客数のデータを読み込み、Prophetのモデルに適用可能な形式に加工します。

その後、モデルを訓練し、将来の365日にわたる予測を行います。

m.plot(forecast)では、元のデータ(点)予測の結果(線)をプロットしています。

また、m.plot_components(forecast)では、予測の各コンポーネント(トレンド、年間の季節性)をプロットしています。

これらの結果から、旅客数の長期的なトレンド季節的な変動を理解することができ、さらに未来の旅客数を予測することが可能です。

[実行結果]

ソースコード解説

ソースコードの詳細を説明します。

1. データの読み込み

  • pd.read_csv を使用して、航空旅客数の時系列データをURLから読み込みます。
  • データフレームの列名を['ds', 'y'] に変更し、'ds' 列を日付型に変換します。

2. Prophetモデルの訓練

  • Prophetを初期化し、年次の季節性を有効にしてモデルを構築します。
  • 訓練用のデータを使って、m.fit(df) でモデルを訓練します。

3. 未来の予測のためのデータフレームの作成

  • 未来の予測のために、m.make_future_dataframe(periods=365) を使って新しい日付のデータフレームを作成します。
  • この新しいデータフレームに対して m.predict(future) を実行し、将来の予測を行います。

4. 予測のプロット

  • m.plot(forecast) を使って、予測されたデータを含むグラフを表示します。
  • 実際のデータ予測されたデータが可視化され、さらに予測の信頼区間も表示されます。

5. トレンドとコンポーネントの表示

  • m.plot_components(forecast) を使用して、Prophetが検出したトレンド季節性の成分を個別にプロットします。
  • トレンド、年次、週次、日次の季節性成分が表示され、データのパターン季節変動を視覚的に理解するのに役立ちます。

これらのステップにより、Prophetを使って時系列データの予測を行い、その結果をグラフで視覚化する完全な流れが示されています。

グラフ解説

このコードは、Prophetを使って時系列データの予測とその分解を行います。

データセットは航空旅客数の時系列データで、以下の3つのグラフを生成します。

[実行結果]

  1. 全体の時系列データの予測

    • Prophetによる時系列データの予測を可視化します。
      横軸は時間(日付)を、縦軸は航空旅客数を表します。
      黒色の点が実際のデータ、青色の線が予測されたデータを示します。
      さらに、予測の信頼区間も表示されます(水色の領域)。
  2. トレンド

    • Prophetが検出したトレンドを示します。
      時系列データの中での長期的な変動を捉えており、時間に伴う変動や推移を示します。
      年次(yearly)、週次(weekly)、日次(daily)の季節性成分も含まれます。
  3. 季節性成分の表示

    • 季節性成分を個別にプロットし、それぞれの季節パターンを示します。
      年間の季節変動や週ごとのパターン、さらに日単位の変動を示しています。

これらのグラフは、時系列データの予測に使用されるProphetモデルの挙動や、データが持つトレンド季節性などを視覚的に理解するのに役立ちます。