メモ_Ubuntu上のAnacondaで仮想環境を切り替える際、「conda activate 仮想環境名」とコマンドするが「conda activate 仮想環境PATH(/home/*****/myenv1)」としても切り替えられる

Anacondaで仮想環境を切り替える際、「conda activate 仮想環境名」とコマンド実行するが「conda activate 仮想環境のPATH(/home/*****/myenv1)」としても切り替えられた。当然だが、推奨される方法ではないらしい(環境変数とかシステム設定で不具合が出るかも、とか)

 

Xserver VPS(レンタルサーバと変わらないくらい安かったので試しに借りた)、minicondaとAnacondaが混在できるということで、先にminicondaで環境構築して自作のpythonアプリを実験していたあと(環境をぐちゃぐちゃにしているので、試行錯誤した後には、OSからクリーンにするので壊す前提で)、Anacondaをあとから入れて、Jupyter lab上のターミナルでminconda仮想環境で構築したアプリを起動できるか実験していて気づいた。

 

メモ_Virtual Box Ubuntu22.04 ServerをインストールしてSSH接続までの手順

Ubuntu22.04 Serverをインストールした直後の状況(メモリ使用量とか)を知りたかったので(検索すれば情報はたくさん出てくるけど)、手元で試してみた。

環境:

Windows 11 Home
Virtual Box 7.0.6
Ubuntu22.04 LTS Server

手順:
  1. Ubuntu22.04 LTS serverのイメージをダウンロード

  2. Virtual Box で仮想マシンを新規作成


    ダウンロードしたisoイメージを指定して、後はお任せ。
    リソースの設定も推奨通りの、CPU 1core、メモリ2GB、ストレージ25GB。

  3. インストール直後だとsshできないので、【設定】の【ネットワーク】で、アダプター1を「ブリッジアダプター」に変更する。



  4. コマンド「ip -a」とかでゲスト側のIPアドレスを確認する。ホスト側からpingで導通確認。念のため、ゲスト側からも外部にpingで確認(ping 8.8.8.8)。8.8.8.8 はgoogleDNSサーバ。

  5. SSHのステータスをコマンド「sudo systemctl status ssh」で確認。「Unit ssh.server could not be found」とか出れば、SSHがインストールされてない。

  6. SSH をインストールする。
    コマンド「sudo apt install openssh-server」

  7. もう一度、コマンド「sudo systemctl status ssh」でステータスを確認。以下のようにActiveになっていればOK。

  8. Tera TeamとかPuttySSHでログインする。まだ秘密鍵とかを設定していないので、UbuntuのUserとPWで入れる。

 

メモリは200MBが利用中。空いているのは約1.8GB(freeが1507MBでBuff/cacheが300MB)

各社VPSの一番低いスペックに多いメモリ512MBのマシンだと、Ubuntu22 serverはインストールすらできないらしいが、インストール直後であれば、バカみたいにメモリを食う処理とかアプリを起動しない限り、それなりにリソースは空いている。

 

メモ_Pythonでグラフ構造のダミーデータを生成しjsonで保存して関係図を描画する

Pythonでグラフ構造のダミーデータを生成しjsonで保存して関係図を描画するまでの一連のメモです。コード例も。

 

ダミーデータ生成:

以下のような仕様でダミーデータを生成します。

 

ノード : User_id
エッジ : relative、friend、acquaintance
プロパティ : 氏名、年齢、性別、所在地(都道府県)

 

生成するダミーデータの最大数と、各ノードが持つエッジの最大数も指定します。

コード例:

import networkx as nx
from faker import Faker
import random

# ダミーデータ生成のための初期設定
fake = Faker('ja_JP')
G = nx.Graph()

# ノードとエッジの数
num_nodes = 10
max_edges_per_node = 5

# ノードを生成してグラフに追加
for _ in range(num_nodes):
    user_id = fake.unique.random_int(min=1, max=1000000)
    name = fake.name()
    age = fake.random_int(min=18, max=80)
    gender = fake.random_element(elements=('man', 'woman'))
    location = fake.prefecture()
    
    G.add_node(user_id, name=name, age=age, gender=gender, location=location)

# エッジを生成してノードに追加
for node in G.nodes:
    num_edges = random.randint(1, max_edges_per_node)
    edges_to_add = random.sample(G.nodes, num_edges)
    
    for neighbor in edges_to_add:
        if neighbor != node:
            relationship = fake.random_element(elements=('relative', 'friend', 'acquaintance'))
            G.add_edge(node, neighbor, relationship=relationship)

# グラフを表示
print(f"ノード数: {len(G.nodes)}")
print(f"エッジ数: {len(G.edges)}")

# 例として最初のノードの情報を表示
first_node = list(G.nodes)[0]
print(f"最初のノードの情報: {G.nodes[first_node]}")


    
結果

以下のように成功しました。生成数が控えめなのは、後で関係図を描画する際にノードが多いと見づらいためで、1万でも10万でも生成できました。

生成したダミーのグラフ構造データをjsonに保存する

以下のコードでjsonに保存します


import json

# ダミーデータを辞書に変換
data = {
    "nodes": [],
    "edges": []
}

for node in G.nodes:
    node_data = {
        "user_id": node,
        "name": G.nodes[node]["name"],
        "age": G.nodes[node]["age"],
        "gender": G.nodes[node]["gender"],
        "location": G.nodes[node]["location"]
    }
    data["nodes"].append(node_data)

for edge in G.edges:
    edge_data = {
        "source": edge[0],
        "target": edge[1],
        "relationship": G.edges[edge]["relationship"]
    }
    data["edges"].append(edge_data)

# データをJSONファイルに保存
with open("dummy_data.json", "w") as json_file:
    json.dump(data, json_file, indent=4)

print("ダミーデータをJSONファイルに保存しました。")

    
結果

無事にjsonデータで保存できました。石川翔太なのにwomanとなってしまっているのはご愛敬。

グラフ構造データを描画する

生成されたダミーデータをjsonから読み込んでmatplotlibで描画してみます


import networkx as nx
import matplotlib.pyplot as plt
import json
import japanize_matplotlib  # japanize-matplotlibをインポート

# JSONファイルからダミーデータを読み込む
with open("dummy_data.json", "r") as json_file:
    data = json.load(json_file)

# NetworkXグラフを作成
G = nx.Graph()

# ノードを追加
for node_data in data["nodes"]:
    G.add_node(node_data["user_id"], **node_data)

# エッジを追加
for edge_data in data["edges"]:
    G.add_edge(edge_data["source"], edge_data["target"], relationship=edge_data["relationship"])

# 関係図を描画
pos = nx.spring_layout(G, seed=42)  # グラフのレイアウトを決定
fig, ax = plt.subplots(figsize=(12, 12))  # 図のサイズを設定

# エッジの関係ラベルを表示
edge_labels = nx.get_edge_attributes(G, 'relationship')
nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_size=14, font_color='red')

# ノードとエッジを描画
nx.draw(G, pos, with_labels=True, node_size=300, font_size=14, font_color='black', node_color='lightblue', edge_color='gray', width=0.5, ax=ax)

plt.title("関係図")
plt.axis("off")  # 軸を非表示にする
plt.show()

    
結果

以下のように成功しました。font-sizeは見やすいように少し大きめに設定してます。

y-cruncherをUbuntu22で動かしてみた

y-cruncherという有名な円周率計算ソフトがあります。Windows版以外に、Linux版もあるので、試しにUbuntu22で動かしてみました。pythonで出来るだけ高速に大きな桁の円周率を求める方法を調べていたのですが、y-cruncherを実行して出力をそのまま利用するのが手っ取り早いかな。

 

1. ダウンロード:

ここからダウンロードします。
y-cruncher - A Multi-Threaded Pi Program (numberworld.org)

 

2. tarを解凍

ダウンロードしたファイルを解凍します。

tar -xvf y-cruncher~省略.tar.xz
3. 実行

解凍したディレクトリーへ移動し、以下のコマンドで実行してみます。

./y-cruncher custom pi -dec:1000
結果

無事に実行されれば、ターミナルにいろいろと表示されます。実行結果がテキストファイル(例: Pi - 20230828-115025.txt。実行した年月日時分秒.txtという形)に出力されます。1000桁だと一瞬(0.001 seconds)で終わりました。

1億桁でもやってみましたが、34.033 secondsでした。さすがに速い。使用メモリ量も表示してくれます。1億桁でTotal Memory: 523,114,624 ( 499 MiB)でした。環境にもよりますが、私の環境では10億桁くらいまでは普通に実行できそうです。

計算された円周率は、Pi - Dec - Chudnovsky.txt、Pi - Hex - Chudnovsky.txtというテキストファイルに保存されています。桁数に応じてファイルサイズが大きくなるのでご注意。1億桁だと95.4MBになってました。実行するたびに上書きされるので、桁数を変えたものを残したい場合は、都度リネームしておきましょう。

環境:

せっかくなのでy-cruncherの実行結果ファイルから引用

Benchmark Validation File - DO NOT MODIFY! If you do, it will fail validation.

Validation Version:    1.3

Program:               y-cruncher v0.8.1 Build 9517
Tuning:                08-NHM ~ Ushio

User:                  None Specified - You can edit this in "Username.txt".

Operating System:      Linux 5.19.0-46-generic x86_64

Processor(s):
    Name:              AMD Ryzen 7 5825U with Radeon Graphics 
    Logical Cores:     4
    Physical Cores:    4
    Sockets:           1
    NUMA Nodes:        1
    Base Frequency:    1,997,161,280 Hz

Motherboard:
    Manufacturer:      Oracle Corporation
    Model:             VirtualBox
    Version:           1.2
    Serial Number:     Suppressed - Personally identifiable information is opt-in only.

Memory:
    Usable Memory:     8,320,471,040 (7.75 GiB)
    Total Memory:      Unable to Detect

Constant:              Pi
Algorithm:             Chudnovsky (1988)
Decimal Digits:        1,000
Hexadecimal Digits:    831
Computation Mode:      Ram Only
Threading Mode:        Push Pool  ->  4 / ?  (randomization on)
Working Memory:        1,572,096 (1.50 MiB)
Total Memory:          30,538,752 (29.1 MiB)

参考:画面キャプチャ

 

メモ_Flaskでmysql.connectorとpymysqlだとエラーハンドリングが失敗する

Flaskアプリで、Mysqlと接続して情報を表示するという単純な処理で、DB接続のエラーハンドリングが失敗する。

mysql.connectorではなく、pymysqlライブラリを利用するようにしたら解消した。。。mysql.connectorとpymysqlを一緒に使うとダメなのかな。

mysql-connector-python=8.0.33
PyMySQL=1.1.0

失敗していた際のコード:

# app/utils/db_utils.py
import mysql.connector
from configparser import ConfigParser
import os
import pymysql

# ファイルの絶対パスを取得
file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'config.ini'))

# コンフィグファイルの読み込み
config = ConfigParser()
config.read(file_path)


def get_db_connection():
    return mysql.connector.connect(
~中略
    )

# エラーメッセージ
MYSQL_DOWN_ERROR_MESSAGE = "MySQL is currently unavailable."

def get_record_from_db(current_number):
    try:
        conn = get_db_connection()
        cursor = conn.cursor()
        cursor.execute(ここにはSQL文が入る)
        record = cursor.fetchone()
        cursor.close()
        conn.close()

        if record:
            return record[0]
        else:
            return None
    except pymysql.MySQLError:
        # MySQLがダウンしている場合はエラーメッセージを返す
        return MYSQL_DOWN_ERROR_MESSAGE
訂正したコード:

import pymysql.cursors
from configparser import ConfigParser
import os

# ファイルの絶対パスを取得
file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'config.ini'))

# コンフィグファイルの読み込み
config = ConfigParser()
config.read(file_path)

def get_db_connection():
    connection = pymysql.connect(
~中略
        cursorclass=pymysql.cursors.DictCursor  # DictCursorを使用して結果を辞書形式で取得
    )
    return connection

# エラーメッセージ
MYSQL_DOWN_ERROR_MESSAGE = "MySQL is currently unavailable."

def get_record_from_db(current_number):
    try:
        conn = get_db_connection()
        with conn.cursor() as cursor:
            cursor.execute(ここにはSQL文が入る)
            record = cursor.fetchone()

        if record:
            return record['explanation']
        else:
            return None
    except pymysql.MySQLError:
        # MySQLがダウンしている場合はエラーメッセージを返す
        return MYSQL_DOWN_ERROR_MESSAGE

メモ_Pythonプロジェクトでソースコード群だけからrequirements.txtを生成する前準備

Pythonプロジェクトでソースコード群だけからrequirements.txtを生成する前準備のメモです。

githubなどからソースコードだけは取得できる状況で、手元には真っ新なPython環境しかなくて(出先で借りたパソコンで google colabとか)、requirements.txt なども整備していなかった場合、後からrequirements.txtを生成して実行環境をなんとかするための前準備として、ソースコードを解析して利用しているパッケージやライブラリの一覧を取得するコードが以下です。

当然、プロジェクト用に自作したパッケージやライブラリも一覧として取得されてしまうので、それらは手動で除去する必要があります。

コード

import os
import re

def find_imports_in_file(file_path):
    with open(file_path, "r", encoding="utf-8") as file:
        content = file.read()
        import_statements = re.findall(r"(?:from|import)\s+([\w\.]+)", content)
        return import_statements

def find_all_imports_in_directory(directory):
    imports = set()
    for root, _, files in os.walk(directory):
        for file in files:
            if file.endswith(".py"):
                file_path = os.path.join(root, file)
                import_statements = find_imports_in_file(file_path)
                imports.update(import_statements)
    return imports

def generate_requirements_txt(import_list, output_file):
    with open(output_file, "w") as file:
        for package in import_list:
            file.write(package + "\n")

target_directory = "path/to/your/code/directory"
import_list = find_all_imports_in_directory(target_directory)
requirements_output_file = "requirements.txt"
generate_requirements_txt(import_list, requirements_output_file)
結果

requirements.txtというファイルが生成されるので、あとはそれを開いて編集してrequirements.txtを完成させていきます。

趣味や実験的なプロジェクトでも、面倒くさがらずに普段からrequirements.txtをきちんと整備していれば良いだけなのですが(汗)