見出し画像

デジタル音痴を克服中の商学部→美大院卒がPythonで描く文化進化ー文化進化という方法②ー

「デジタル音痴ではないのではないか」という温かい意見も頂きましたが、ChatGPTのアプリとDropboxのアプリをスマホやPC、そしてタブレットに入れて「まだ」1ヶ月も経過していないというありさまです😂(→それをスゴい進歩だと私は喜んでいるのですが……😅)

今回から、このシリーズのみPCで描いてゆきたいと思います。

まず、前回は、

「文化進化の研究では、文化の「伝達される情報」としての側面に焦点を当てる。 文化は伝達・継承されることにより連続性を持つ。
文化進化においては、伝達・継承によって生じる文化多様性の変化を量的に扱い、「複雑な総体」で ある文化の理解を深めようとする。
この節では、本文の定義(文化=非遺伝的手段により伝達される情報/文化進化=集団中の文化的構 成の時間変化)を、Pythonでそのまま扱える形(データ構造+更新則+多様性指標)に落とす。
※ まず、文化を「個体が持つ文化的状態(variant)」として表現する。 最小限では、各個体が 1 つの文化 variant(例:A/B)を持つと考えればよい。 集団内の文化的構成は、各 variant の頻度(比率)で表せる。」
→→→

# note_2_1_文化進化という方法_Pythonコード
# ------------------------------------------------------------
# 目的:
# - 文化進化を「集団中の文化的構成(variant の頻度)の時間変化」として最小限に定式化する
# - 生物進化(遺伝子頻度の変化)との類比を、同じ数学・同じデータ構造で扱えることを示す
# - 文化の伝達経路(垂直/水平/斜め)を簡単に切り替え、文化多様性(Shannon/Simpson)を観察する
#
# 実行環境: Python 3.10+ 推奨
# ------------------------------------------------------------

from __future__ import annotations

import math
import random
from dataclasses import dataclass
from collections import Counter
from typing import Dict, List, Optional, Sequence, Tuple

Variant = str  # 文化的な「型」(言語の用法、技術、規範、嗜好などを抽象化したラベル)

@dataclass
class Population:
    """文化的 variant を個体ごとに持つ集団。"""
    variants: List[Variant]

    def size(self) -> int:
        return len(self.variants)

    def freq(self) -> Dict[Variant, float]:
        """各 variant の頻度(割合)"""
        c = Counter(self.variants)
        n = self.size()
        return {k: v / n for k, v in c.items()}

    def diversity_shannon(self) -> float:
        """Shannon エントロピー(多様性指標)"""
        ps = self.freq().values()
        return -sum(p * math.log(p) for p in ps if p > 0)

    def diversity_simpson(self) -> float:
        """Simpson 多様性(1 - Σ p^2)"""
        ps = self.freq().values()
        return 1.0 - sum(p * p for p in ps)

def init_population(
    n: int,
    variants: Sequence[Variant],
    weights: Optional[Sequence[float]] = None,
    seed: int = 0,
) -> Population:
    rng = random.Random(seed)
    w = list(weights) if weights is not None else [1.0] * len(variants)
    vs = rng.choices(list(variants), weights=w, k=n)
    return Population(vs)

でしたね😌

まずは、先に進めながら、(→逆引き辞典「Python ポケットリファレンス」(柏野雄太著 技術評論社)の使い方になれつつ、Pythonの問題集を並行でひたすらこなしている段階なので、コメントを後にまとめて書くとして😅)、あまり挟まず、次に進めてみたいと思います😊

「伝達・変異・選択・ドリフトを最小モデル化
この時点で「文化的構成」は pop.freq() のように頻度分布として可視化できる。
また「文化多様性の時間変化」を扱うには、更新(伝達)を反復して、各時点の多様性(Shannon/S
impson)を記録すればよい。

次に、生物進化と文化進化の共通プロセスとして本文が挙げる「伝達(複製)・変異・選択・ドリフ
ト」を、文化の伝達則に埋め込む。
ここでは、最小モデルとして次を採用する。

  1. 社会学習(模倣)により、個体 i が参照個体 j の variant をコピーする(複製) 2) 一定確率で別
    variant に誤写・創発する(変異) 3) ある variant が選好され、模倣されやすい(選択) 4)
    有限集団の確率的ゆらぎ(ドリフト)は自動的に入る(ランダムな模倣)
    さらに、本文が強調する文化の特徴として「親以外からの継承」「多様な伝達経路(垂直・水平・斜
    行)」を、参照相手の選び方で表現する。」→→→

def choose_role_model(
    rng: random.Random,
    pop: Population,
    mode: str,
    parents: Optional[List[int]] = None,
) -> int:
    """
    文化の伝達経路を最小限にモデル化する。

    mode:
      - "vertical"  : 親(parents)から学ぶ(生物の親子伝達に近い)
      - "horizontal": 同世代の他者から学ぶ
      - "oblique"   : 年長世代/教師役(ここでは集団の任意個体を教師として近似)
    """
    n = pop.size()

    if mode == "vertical":
        if parents is None:
            raise ValueError("vertical には parents(親インデックス列)が必要です。")
        return rng.choice(parents)

    if mode in ("horizontal", "oblique"):
        return rng.randrange(n)

    raise ValueError(f"unknown mode: {mode}")

def cultural_update(
    pop: Population,
    mode: str = "horizontal",
    innovation_rate: float = 0.01,
    variants_pool: Optional[Sequence[Variant]] = None,
    seed: int = 0,
) -> Population:
    """
    1 ステップの文化更新(学習 + イノベーション)。

    - 各個体は role model を 1 人選び、その variant をコピーする(社会学習)
    - ただし innovation_rate の確率で、ランダムに新しい variant に置換する(文化的変異の近似)
    """
    rng = random.Random(seed)
    n = pop.size()

    # 親子関係(最小モデルとして、インデックスをシャッフルして「親候補」を作る)
    idx = list(range(n))
    rng.shuffle(idx)
    half = max(1, n // 2)
    parents = idx[:half]

    pool = list(variants_pool) if variants_pool is not None else sorted(set(pop.variants))

    next_variants: List[Variant] = []
    for _ in range(n):
        model = choose_role_model(rng, pop, mode=mode, parents=parents)
        v = pop.variants[model]

        # イノベーション(文化的変異)
        if rng.random() < innovation_rate:
            v = rng.choice(pool)

        next_variants.append(v)

    return Population(next_variants)

出力からインデントなどなどにいたるまでまだまだ完全に皆様に手伝ってもらっています😥
わからないところは解説待ちというおんぶに抱っこ状態です😭
が、さらにもう少しだけ、進めます😁

「多様性の時間変化を計測する この mode を切り替えるだけで、本文の「親以外からの情報継承」「多様な伝達経路」を同じ枠組み で比較できる。 ここでは「文化多様性の時間変化」を計測する。 3 文化進化と生物進化(note用)2.1 文化進化という方法(Pythonで読む)では、同じ初期条件から、水平伝播(horizontal)と垂直伝播(vertical)で多様性がどう変わるかを比較する。」→→→

def simulate(
    n: int = 200,
    steps: int = 200,
    mode: str = "horizontal",
    innovation_rate: float = 0.01,
    seed: int = 0,
) -> List[Tuple[int, Dict[Variant, float], float, float]]:
    """(t, freq, shannon, simpson) の時系列を返す。"""
    variants = ["A", "B", "C"]  # 文化的構成の最小例
    pop = init_population(n=n, variants=variants, weights=[0.7, 0.2, 0.1], seed=seed)

    history = []
    for t in range(steps + 1):
        history.append((t, pop.freq(), pop.diversity_shannon(), pop.diversity_simpson()))
        pop = cultural_update(
            pop,
            mode=mode,
            innovation_rate=innovation_rate,
            variants_pool=variants,
            seed=seed + t + 1,
        )
    return history

def print_summary(history: List[Tuple[int, Dict[Variant, float], float, float]], every: int = 50) -> None:
    for t, freq, sh, si in history:
        if t % every == 0 or t == history[-1][0]:
            freq_str = ", ".join(f"{k}:{v:.2f}" for k, v in sorted(freq.items()))
            print(f"t={t:4d} | freq=({freq_str}) | Shannon={sh:.3f} | Simpson={si:.3f}")

if __name__ == "__main__":
    # 例: 水平伝播(同世代から学ぶ)+低いイノベーション率
    hist = simulate(mode="horizontal", innovation_rate=0.02, seed=42)
    print_summary(hist, every=40)

    # 例: 垂直伝播(親から学ぶ)
    hist_v = simulate(mode="vertical", innovation_rate=0.02, seed=42)
    print("\n--- vertical ---")
    print_summary(hist_v, every=40)

    # 例: 斜め伝播(教師役から学ぶ)
    hist_o = simulate(mode="oblique", innovation_rate=0.02, seed=42)
    print("\n--- oblique ---")
    print_summary(hist_o, every=40)


ChatGPTはすごいですね😲
ちゃんと検証しなければならないし、検討したものを次回にはなんとか載せたいと思っています😅
頑張りすぎず、頑張ります。
本文というのはもとの私の文章があるのですが、きれいに対応できた頃に(1ヶ月後くらいかなあ?)に並べて載せたいと考えています😌

なお、以下はチャッピーさんのアドバイスです。

「本文との対応と次の展開 この出力は「文化的構成(頻度)が時間とともに変化する」ことをそのまま示す。 Shannon 多様性(H)が下がれば、特定 variant への収束(同質化)が進んだと解釈できる。 逆に H が維持される場合、複数 variant の共存が保たれている。 ※ 本文の要点に対応づけると、次のように整理できる。 文化は「非遺伝的手段により伝達される情報」 → variants(文化情報)を個体が保持し、模倣で更新する。 文化進化は「集団中の文化的構成の時間変化」 → freq() が時間とともに変わる過程を simulate() で追う。 生物進化と共通する「伝達・変異・選択・ドリフト」 → step_cultural_transmission() のコピー( 伝達)、mu(変異)、selection_bias(選択)、有限集団のランダム更新(ドリフト)、生物進化に比べ文化進化は「親以外からの継承」「多様な伝達経路」 → mode="horizontal"/"oblique" により、親以外を参照しても更新できる。 ※ 次の展開(2.1 の後半に接続するための提案) この節の末尾では、文化情報が「脳内の神経結合パターン」や「体外の記録(コンピューターコード 、音符、文字)」として保持される点が述べられている。 ここに自然に繋げるなら、次は文化情報を「文字列(A/B/C)だけでなく、配列やグラフとして表す 」モデルへ拡張すると良い。 例: ・文化をビット列(特徴の束)として表し、部分的に模倣・変異する(複雑な総体の最小表現) ・文化をネットワーク上で伝播させ、伝達経路(ネットワーク構造)そのものが多様性に与える影響 を見る 必要なら、この拡張部分に「幾何学模様(ネットワークや位相図の描画)」を挿入すると、視覚的に も note 記事として読みやすくなる。」
だそうです。
頑張りすぎず、頑張ります。
では、また、次回。


いいなと思ったら応援しよう!