파이톤에서 격차 확대 시뮬레이션 실시

원자재


나는 일경과학의 2020년 9월호 보도인 수리가 말한 격차가 확대되는 메커니즘을 보았다.( http://www.nikkei-science.com/202009_080.html )
이 보도는 공정거래가 지속돼도 빈부격차가 확대될 것이라는 간단한 수리모델로 시뮬레이션을 실시했다.

상황 설정


시뮬레이션의 설정은 매우 간단하다. 아래와 같다.기사에서는 거래라고 불리지만 도박을 하는 쪽이 더 이해가 간다고 생각하기 때문에 다음은 거래를 도박으로 표현한다.
  • 에 1000명의 대리가 거래에 참여했다.
  • 각 대리인이 같은 초기 자금 100을 보유하고 있다.
  • 랜덤으로 선택한 두 대리인이 도박을 하면 한쪽이 공정한 50%의 확률로 이긴다.
  • 이 거래를 중복한다.
  • 포인트는 승부 때의 자금 이동이다.B가 부모와 A사이에 아이를 걸면 A의 승부 결과는 다음과 같다.
  • A가 이긴 경우
  • B로부터 A 총자산의 20%에 해당하는 금액
  • 을 수령
  • A가 진 경우
  • A 총자산의 20%에 해당하는 금액을 B
  • 에 전달
    A가 부모인 B에게 자신의 자산의 어떤 비율을 외상으로 제시하고, A가 이기면 B로부터 외상과 같은 금액을 받는 방식이다.A가 지면 그 부분은 B에게 맡긴다.

    결실


    가로축은 대리이고, 세로축은 대리가 보유한 자산이다.올라가면 올라갈수록 자산이 많아진다는 뜻이다.
    전체 영상은 이 링크비디오 링크에서
    [1] 첫 번째 도박에서 이긴 대리와 진 대리의 차이가 조금 있다.

    [2] 바라츠키가 나타나기 시작했고 500여 개의 대리인이 처음으로 파산했다.

    [3] 자산을 대량으로 보유한 대리와 파산 대리가 나타나기 시작한다.

    [4] 한 대리인이 모든 자산을 수집했다.

    소스 코드

  • 에이전트 클래스 제한 자산이 0일 경우 alive=False이며 후속 거래에 참여하지 않습니다.
  • matplotlib의 FuncAnimation을 통해 애니메이션을 생성합니다.
  • import random
    
    import matplotlib.pyplot as plt
    from matplotlib.animation import FuncAnimation
    import numpy
    
    
    class Agent:
        def __init__(self, initial_asset=0):
            self.asset = initial_asset
            self.alive = True
            self.ratio = 0.2
    
        def match(self, agent):
            is_won = random.uniform(0, 1) > 0.5
            delta = int(self.asset * self.ratio)
    
            if is_won:
                if agent.asset < delta:
                    delta = agent.asset
                self.asset += delta
                agent.asset -= delta
            else:
                if self.asset < delta:
                    delta = self.asset
                self.asset -= delta
                agent.asset += delta
    
            self.alive = self.asset > 0
            agent.alive = agent.asset > 0
    
    
    class AgentList:
        def __init__(self, nagents, initial_asset=100):
            self.nagents = nagents
            self.agents = [Agent(initial_asset) for _ in range(nagents)]
    
        def choose_pair(self):
            candidates = [i for i, a in enumerate(self.agents) if a.alive]
            if len(candidates) >= 2:
                return random.sample(candidates, 2)
            return None
    
        def list_assets(self):
            return [a.asset for a in self.agents]
    
        def __getitem__(self, index):
            return self.agents[index]
    
    
    if __name__ == '__main__':
        # plot の設定
        fig, ax = plt.subplots()
        lines, = plt.plot([], [], 'k-')
        nagents = 1000
        ymax = 150
    
        # Agents の初期化
        agents = AgentList(nagents)
        bets_per_frame = 10
    
        def init():
            # plot 初期設定
            ax.set_xlim(0, nagents)
            ax.set_ylim(0, ymax)
            ax.set_xlabel('Agents')
            ax.set_ylabel('Asset')
            return lines,
    
        def update(frame):
            global ymax
            print('\r%d' % frame, end='')
    
            # 1フレームあたり bets_per_frame だけ取引をする
            for _ in range(bets_per_frame):
                pair = agents.choose_pair()
                if pair is None:
                    break
                agents[pair[0]].match(agents[pair[1]])
    
            # プロットの軸を更新
            assets = agents.list_assets()
            ymax = max(ymax, max(assets))
            ax.set_title('Frame %d' % (frame * bets_per_frame))
            ax.set_ylim(0, ymax)
    
            # プロットを更新
            lines.set_data(list(range(nagents)), assets)
            return lines,
    
        anim = FuncAnimation(
            fig, update, frames=range(3000),
            init_func=init, blit=True, interval=25
        )
    
        anim.save('result.mp4', writer='ffmpeg')
    
    

    감상


    자산을 많이 가진 대리는 자기 자산의 일부만 사용해도 상당한 거래를 할 수 있지만, 자산이 적은 대리는 파산 위험이 잦아 비대칭성이 확대될 수 있다는 얘기다.
    원래 보도는 이 시뮬레이션만으로도 실제 자산 데이터에 해당하는데, 부유세 요소와 부채 요소를 넣으면 정밀도가 더 높아지는 모델부터 물리적 모델과의 연관성까지 부의 재분배 필요성이 적혀 있어 흥미롭다.

    좋은 웹페이지 즐겨찾기