Skip to content

Commit

Permalink
benchmark: Split pandas agent into native and concise (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
rht authored Jul 10, 2024
1 parent a70b39e commit 23fe6f1
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 23 deletions.
Binary file removed docs/images/readme_plot_2.png
Binary file not shown.
71 changes: 48 additions & 23 deletions docs/scripts/readme_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def give_money(self):
)


class MoneyAgentPandas(AgentSetPandas):
class MoneyAgentPandasConcise(AgentSetPandas):
def __init__(self, n: int, model: ModelDF) -> None:
super().__init__(model)
## Adding the agents to the agent set
Expand All @@ -184,41 +184,59 @@ def step(self) -> None:

def give_money(self):
## Active agents are changed to wealthy agents
# 1. Using a native expression
# self.select(self.agents['wealth'] > 0)
# 2. Using the __getitem__ method
# 1. Using the __getitem__ method
# self.select(self["wealth"] > 0)
# 3. Using the fallback __getattr__ method
# 2. Using the fallback __getattr__ method
self.select(self.wealth > 0)

# Receiving agents are sampled (only native expressions currently supported)
other_agents = self.agents.sample(n=len(self.active_agents), replace=True)

# Wealth of wealthy is decreased by 1
# 1. Using a native expression
"""b_mask = self.active_agents.index.isin(self.agents)
self.agents.loc[b_mask, "wealth"] -= 1"""
# 2. Using the __setitem__ method with self.active_agents mask
# 1. Using the __setitem__ method with self.active_agents mask
# self[self.active_agents, "wealth"] -= 1
# 3. Using the __setitem__ method with "active" mask
# 2. Using the __setitem__ method with "active" mask
self["active", "wealth"] -= 1

# Compute the income of the other agents (only native expressions currently supported)
new_wealth = other_agents.groupby("unique_id").count()

# Add the income to the other agents
# 1. Using native expressions
"""merged = pd.merge(
# 1. Using the set method
# self.set(attr_names="wealth", values=self["wealth"] + new_wealth["wealth"], mask=new_wealth)
# 2. Using the __setitem__ method
self[new_wealth, "wealth"] += new_wealth["wealth"]


class MoneyAgentPandasNative(AgentSetPandas):
def __init__(self, n: int, model: ModelDF) -> None:
super().__init__(model)
## Adding the agents to the agent set
self += pd.DataFrame({"unique_id": np.arange(n), "wealth": np.ones(n)})

def step(self) -> None:
# The give_money method is called
self.do("give_money")

def give_money(self):
self.select(self.agents["wealth"] > 0)

# Receiving agents are sampled (only native expressions currently supported)
other_agents = self.agents.sample(n=len(self.active_agents), replace=True)

# Wealth of wealthy is decreased by 1
b_mask = self.active_agents.index.isin(self.agents)
self.agents.loc[b_mask, "wealth"] -= 1

# Compute the income of the other agents (only native expressions currently supported)
new_wealth = other_agents.groupby("unique_id").count()

# Add the income to the other agents
merged = pd.merge(
self.agents, new_wealth, on="unique_id", how="left", suffixes=("", "_new")
)
merged["wealth"] = merged["wealth"] + merged["wealth_new"].fillna(0)
self.agents = merged.drop(columns=["wealth_new"])"""

# 2. Using the set method
# self.set(attr_names="wealth", values=self["wealth"] + new_wealth["wealth"], mask=new_wealth)

# 3. Using the __setitem__ method
self[new_wealth, "wealth"] += new_wealth["wealth"]
self.agents = merged.drop(columns=["wealth_new"])


class MoneyModelDF(ModelDF):
Expand Down Expand Up @@ -246,8 +264,13 @@ def mesa_frames_polars_native(n_agents: int) -> None:
model.run_model(100)


def mesa_frames_pandas(n_agents: int) -> None:
model = MoneyModelDF(n_agents, MoneyAgentPandas)
def mesa_frames_pandas_concise(n_agents: int) -> None:
model = MoneyModelDF(n_agents, MoneyAgentPandasConcise)
model.run_model(100)


def mesa_frames_pandas_native(n_agents: int) -> None:
model = MoneyModelDF(n_agents, MoneyAgentPandasNative)
model.run_model(100)


Expand All @@ -258,15 +281,17 @@ def main():
# "mesa",
"mesa-frames (pl concise)",
"mesa-frames (pl native)",
"mesa-frames (pandas)",
"mesa-frames (pd concise)",
"mesa-frames (pd native)",
]
out = perfplot.bench(
setup=lambda n: n,
kernels=[
# mesa_implementation,
mesa_frames_polars_concise,
mesa_frames_polars_native,
mesa_frames_pandas,
mesa_frames_pandas_concise,
mesa_frames_pandas_native,
],
labels=labels,
n_range=[k for k in range(100, 10000, 1000)],
Expand Down

0 comments on commit 23fe6f1

Please sign in to comment.