Skip to content

Commit f928522

Browse files
reyan-singhpre-commit-ci[bot]adamamer20
authored
Rename 'agents' property to 'df' for AgentContainer for issue # 68 (#148)
* moved agents to df chnages done in AgentContainer to move agents to df and change done as rquied in agents/agentset in abstract/concrete. Note: i have depreciated agents to use df instead to keep it compatible with others and will remove once all looks good * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * emoving agents property completely to use df property removing agents property completely, instead use df property, also replacing agents with df in tests and boltzmann_wealth example * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * refactor: remove deprecated 'agents' property and its setter in AgentSetDF * refactor: remove unnecessary blank line in AgentSetDF class * refactor: rename 'agents' setter to 'df' in AgentContainer class * refactor: update agentset property access from 'agents' to 'df' in AgentsDF class * refactor: update agent access from 'agents' to 'df' in AntPolarsBase and subclasses * refactor: update agent access from 'agents' to 'df' in AgentSetPolars class * refactor: update model access from 'df' to 'agents' in fixture functions * refactor: update agent access from 'agents' to 'df' in get_unique_ids function * refactor: update agent access from '_agents' to '_df' across AgentSetDF, AgentsDF, and AgentSetPolars classes * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * refactor: update agent access from 'agents' to 'df' in multiple classes and tests * refactor: update agent access from 'agents' to 'df' in README and tutorial notebook --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Adam Amer <136176500+adamamer20@users.noreply.github.com>
1 parent 470f8ae commit f928522

12 files changed

Lines changed: 286 additions & 361 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ class MoneyAgentPolars(AgentSetPolars):
110110
self.select(self.wealth > 0)
111111

112112
# Receiving agents are sampled (only native expressions currently supported)
113-
other_agents = self.agents.sample(
113+
other_agents = self.df.sample(
114114
n=len(self.active_agents), with_replacement=True
115115
)
116116

docs/general/user-guide/1_classes.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ class MoneyAgent(AgentSetPolars):
2424
self["wealth"] = self["wealth"] + self.random.integers(n)
2525
```
2626

27-
You can access the underlying DataFrame where agents are stored with `self.agents`. This allows you to use DataFrame methods like `self.agents.sample` or `self.agents.group_by("wealth")` and more.
27+
You can access the underlying DataFrame where agents are stored with `self.df`. This allows you to use DataFrame methods like `self.df.sample` or `self.df.group_by("wealth")` and more.
2828

2929
## ModelDF 🏗️
3030

3131
To add your AgentSetDF to your ModelDF, you should also add it to the agents with `+=` or `add`.
3232

33-
NOTE: ModelDF.agents are stored in a class which is entirely similar to AgentSetDF called AgentsDF. The API of the two are the same. If you try accessing AgentsDF.agents, you will get a dictionary of `[AgentSetDF, DataFrame]`.
33+
NOTE: ModelDF.agents are stored in a class which is entirely similar to AgentSetDF called AgentsDF. The API of the two are the same. If you try accessing AgentsDF.df, you will get a dictionary of `[AgentSetDF, DataFrame]`.
3434

3535
Example:
3636

docs/general/user-guide/2_introductory-tutorial.ipynb

Lines changed: 14 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
},
8080
{
8181
"cell_type": "code",
82-
"execution_count": 2,
82+
"execution_count": null,
8383
"id": "2bac0126",
8484
"metadata": {},
8585
"outputs": [],
@@ -99,9 +99,7 @@
9999
"\n",
100100
" def give_money(self):\n",
101101
" self.select(self.wealth > 0)\n",
102-
" other_agents = self.agents.sample(\n",
103-
" n=len(self.active_agents), with_replacement=True\n",
104-
" )\n",
102+
" other_agents = self.df.sample(n=len(self.active_agents), with_replacement=True)\n",
105103
" self[\"active\", \"wealth\"] -= 1\n",
106104
" new_wealth = other_agents.group_by(\"unique_id\").len()\n",
107105
" self[new_wealth[\"unique_id\"], \"wealth\"] += new_wealth[\"len\"]"
@@ -120,33 +118,10 @@
120118
},
121119
{
122120
"cell_type": "code",
123-
"execution_count": 3,
121+
"execution_count": null,
124122
"id": "65da4e6f",
125123
"metadata": {},
126-
"outputs": [
127-
{
128-
"name": "stdout",
129-
"output_type": "stream",
130-
"text": [
131-
"shape: (9, 2)\n",
132-
"┌────────────┬──────────┐\n",
133-
"│ statistic ┆ wealth │\n",
134-
"│ --- ┆ --- │\n",
135-
"│ str ┆ f64 │\n",
136-
"╞════════════╪══════════╡\n",
137-
"│ count ┆ 1000.0 │\n",
138-
"│ null_count ┆ 0.0 │\n",
139-
"│ mean ┆ 1.0 │\n",
140-
"│ std ┆ 1.171056 │\n",
141-
"│ min ┆ 0.0 │\n",
142-
"│ 25% ┆ 0.0 │\n",
143-
"│ 50% ┆ 1.0 │\n",
144-
"│ 75% ┆ 2.0 │\n",
145-
"│ max ┆ 9.0 │\n",
146-
"└────────────┴──────────┘\n"
147-
]
148-
}
149-
],
124+
"outputs": [],
150125
"source": [
151126
"# Choose either MoneyAgentPandas or MoneyAgentPolars\n",
152127
"agent_class = MoneyAgentPolars\n",
@@ -155,7 +130,7 @@
155130
"model = MoneyModelDF(1000, agent_class)\n",
156131
"model.run_model(100)\n",
157132
"\n",
158-
"wealth_dist = list(model.agents.agents.values())[0]\n",
133+
"wealth_dist = list(model.agents.df.values())[0]\n",
159134
"# Print the final wealth distribution\n",
160135
"print(wealth_dist.select(pl.col(\"wealth\")).describe())"
161136
]
@@ -175,7 +150,7 @@
175150
},
176151
{
177152
"cell_type": "code",
178-
"execution_count": 4,
153+
"execution_count": null,
179154
"id": "fbdb540810924de8",
180155
"metadata": {},
181156
"outputs": [],
@@ -184,8 +159,8 @@
184159
" def __init__(self, n: int, model: ModelDF):\n",
185160
" super().__init__(model)\n",
186161
" ## Adding the agents to the agent set\n",
187-
" # 1. Changing the agents attribute directly (not recommended, if other agents were added before, they will be lost)\n",
188-
" \"\"\"self.agents = pl.DataFrame(\n",
162+
" # 1. Changing the df attribute directly (not recommended, if other agents were added before, they will be lost)\n",
163+
" \"\"\"self.df = pl.DataFrame(\n",
189164
" {\"unique_id\": pl.arange(n, eager=True), \"wealth\": pl.ones(n, eager=True)}\n",
190165
" )\"\"\"\n",
191166
" # 2. Adding the dataframe with add\n",
@@ -215,9 +190,7 @@
215190
" self.select(self.wealth > 0)\n",
216191
"\n",
217192
" # Receiving agents are sampled (only native expressions currently supported)\n",
218-
" other_agents = self.agents.sample(\n",
219-
" n=len(self.active_agents), with_replacement=True\n",
220-
" )\n",
193+
" other_agents = self.df.sample(n=len(self.active_agents), with_replacement=True)\n",
221194
"\n",
222195
" # Wealth of wealthy is decreased by 1\n",
223196
" # 1. Using the __setitem__ method with self.active_agents mask\n",
@@ -254,12 +227,10 @@
254227
" ## Active agents are changed to wealthy agents\n",
255228
" self.select(pl.col(\"wealth\") > 0)\n",
256229
"\n",
257-
" other_agents = self.agents.sample(\n",
258-
" n=len(self.active_agents), with_replacement=True\n",
259-
" )\n",
230+
" other_agents = self.df.sample(n=len(self.active_agents), with_replacement=True)\n",
260231
"\n",
261232
" # Wealth of wealthy is decreased by 1\n",
262-
" self.agents = self.agents.with_columns(\n",
233+
" self.df = self.df.with_columns(\n",
263234
" wealth=pl.when(pl.col(\"unique_id\").is_in(self.active_agents[\"unique_id\"]))\n",
264235
" .then(pl.col(\"wealth\") - 1)\n",
265236
" .otherwise(pl.col(\"wealth\"))\n",
@@ -268,8 +239,8 @@
268239
" new_wealth = other_agents.group_by(\"unique_id\").len()\n",
269240
"\n",
270241
" # Add the income to the other agents\n",
271-
" self.agents = (\n",
272-
" self.agents.join(new_wealth, on=\"unique_id\", how=\"left\")\n",
242+
" self.df = (\n",
243+
" self.df.join(new_wealth, on=\"unique_id\", how=\"left\")\n",
273244
" .fill_null(0)\n",
274245
" .with_columns(wealth=pl.col(\"wealth\") + pl.col(\"len\"))\n",
275246
" .drop(\"len\")\n",
@@ -438,4 +409,4 @@
438409
},
439410
"nbformat": 4,
440411
"nbformat_minor": 5
441-
}
412+
}

examples/boltzmann_wealth/performance_plot.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,7 @@ def give_money(self):
101101
self.select(self.wealth > 0)
102102

103103
# Receiving agents are sampled (only native expressions currently supported)
104-
other_agents = self.agents.sample(
105-
n=len(self.active_agents), with_replacement=True
106-
)
104+
other_agents = self.df.sample(n=len(self.active_agents), with_replacement=True)
107105

108106
# Wealth of wealthy is decreased by 1
109107
# 1. Using the __setitem__ method with self.active_agents mask
@@ -140,12 +138,10 @@ def give_money(self):
140138
## Active agents are changed to wealthy agents
141139
self.select(pl.col("wealth") > 0)
142140

143-
other_agents = self.agents.sample(
144-
n=len(self.active_agents), with_replacement=True
145-
)
141+
other_agents = self.df.sample(n=len(self.active_agents), with_replacement=True)
146142

147143
# Wealth of wealthy is decreased by 1
148-
self.agents = self.agents.with_columns(
144+
self.df = self.df.with_columns(
149145
wealth=pl.when(pl.col("unique_id").is_in(self.active_agents["unique_id"]))
150146
.then(pl.col("wealth") - 1)
151147
.otherwise(pl.col("wealth"))
@@ -154,8 +150,8 @@ def give_money(self):
154150
new_wealth = other_agents.group_by("unique_id").len()
155151

156152
# Add the income to the other agents
157-
self.agents = (
158-
self.agents.join(new_wealth, on="unique_id", how="left")
153+
self.df = (
154+
self.df.join(new_wealth, on="unique_id", how="left")
159155
.fill_null(0)
160156
.with_columns(wealth=pl.col("wealth") + pl.col("len"))
161157
.drop("len")

examples/sugarscape_ig/ss_polars/agents.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def eat(self):
4545

4646
def step(self):
4747
self.shuffle().do("move").do("eat")
48-
self.discard(self.agents.filter(pl.col("sugar") <= 0))
48+
self.discard(self.df.filter(pl.col("sugar") <= 0))
4949

5050
def move(self):
5151
neighborhood = self._get_neighborhood()
@@ -175,7 +175,7 @@ def get_best_moves(self, neighborhood: pl.DataFrame):
175175
best_moves = pl.DataFrame()
176176

177177
# While there are agents that do not have a best move, keep looking for one
178-
while len(best_moves) < len(self.agents):
178+
while len(best_moves) < len(self.df):
179179
# Check if there are previous agents that might make the same move (priority for the given move is > 1)
180180
neighborhood = neighborhood.with_columns(
181181
priority=pl.col("agent_order").cum_count().over(["dim_0", "dim_1"])
@@ -232,7 +232,7 @@ def get_best_moves(self, neighborhood: pl.DataFrame):
232232
occupied_cells, free_cells, target_cells = self._prepare_cells(neighborhood)
233233
best_moves_func = self._get_best_moves()
234234

235-
processed_agents = np.zeros(len(self.agents), dtype=np.bool_)
235+
processed_agents = np.zeros(len(self.df), dtype=np.bool_)
236236

237237
if self.numba_target is None:
238238
# Non-vectorized case: we need to create and pass the best_moves array
@@ -243,7 +243,7 @@ def get_best_moves(self, neighborhood: pl.DataFrame):
243243
df.struct.field("agent_order"),
244244
df.struct.field("blocking_agent_order"),
245245
processed_agents,
246-
best_moves=np.full(len(self.agents), -1, dtype=np.int32),
246+
best_moves=np.full(len(self.df), -1, dtype=np.int32),
247247
)
248248
else:
249249
# Vectorized case: Polars will create the output array (best_moves) automatically

mesa_frames/abstract/agents.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -695,17 +695,17 @@ def space(self) -> mesa_frames.abstract.space.SpaceDF | None:
695695

696696
@property
697697
@abstractmethod
698-
def agents(self) -> DataFrame | dict[str, DataFrame]:
698+
def df(self) -> DataFrame | dict[str, DataFrame]:
699699
"""The agents in the AgentContainer.
700700
701701
Returns
702702
-------
703703
DataFrame | dict[str, DataFrame]
704704
"""
705705

706-
@agents.setter
706+
@df.setter
707707
@abstractmethod
708-
def agents(
708+
def df(
709709
self, agents: DataFrame | list[mesa_frames.concrete.agents.AgentSetDF]
710710
) -> None:
711711
"""Set the agents in the AgentContainer.
@@ -788,7 +788,7 @@ class AgentSetDF(AgentContainer, DataFrameMixin):
788788
The model that the agent set belongs to.
789789
"""
790790

791-
_agents: DataFrame # The agents in the AgentSetDF
791+
_df: DataFrame # The agents in the AgentSetDF
792792
_mask: (
793793
AgentMask # The underlying mask used for the active agents in the AgentSetDF.
794794
)
@@ -875,13 +875,13 @@ def do(
875875
) -> Self | Any:
876876
masked_df = self._get_masked_df(mask)
877877
# If the mask is empty, we can use the object as is
878-
if len(masked_df) == len(self._agents):
878+
if len(masked_df) == len(self._df):
879879
obj = self._get_obj(inplace)
880880
method = getattr(obj, method_name)
881881
result = method(*args, **kwargs)
882882
else: # If the mask is not empty, we need to create a new masked AgentSetDF and concatenate the AgentSetDFs at the end
883883
obj = self._get_obj(inplace=False)
884-
obj._agents = masked_df
884+
obj._df = masked_df
885885
original_masked_index = obj._get_obj_copy(obj.index)
886886
method = getattr(obj, method_name)
887887
result = method(*args, **kwargs)
@@ -937,7 +937,7 @@ def remove(self, agents: IdsLike | AgentMask, inplace: bool = True) -> Self:
937937
agentsdf = self.model.agents.remove(agents, inplace=inplace)
938938
# TODO: Refactor AgentsDF to return dict[str, AgentSetDF] instead of dict[AgentSetDF, DataFrame]
939939
# And assign a name to AgentSetDF? This has to be replaced by a nicer API of AgentsDF
940-
for agentset in agentsdf.agents.keys():
940+
for agentset in agentsdf.df.keys():
941941
if isinstance(agentset, self.__class__):
942942
return agentset
943943
return self
@@ -1058,9 +1058,9 @@ def __iadd__(self, other: DataFrame | DataFrameInput) -> Self:
10581058
@abstractmethod
10591059
def __getattr__(self, name: str) -> Any:
10601060
if __debug__: # Only execute in non-optimized mode
1061-
if name == "_agents":
1061+
if name == "_df":
10621062
raise AttributeError(
1063-
"The _agents attribute is not set. You probably forgot to call super().__init__ in the __init__ method."
1063+
"The _df attribute is not set. You probably forgot to call super().__init__ in the __init__ method."
10641064
)
10651065

10661066
@overload
@@ -1087,31 +1087,31 @@ def __getitem__(
10871087
return attr
10881088

10891089
def __len__(self) -> int:
1090-
return len(self._agents)
1090+
return len(self._df)
10911091

10921092
def __repr__(self) -> str:
1093-
return f"{self.__class__.__name__}\n {str(self._agents)}"
1093+
return f"{self.__class__.__name__}\n {str(self._df)}"
10941094

10951095
def __str__(self) -> str:
1096-
return f"{self.__class__.__name__}\n {str(self._agents)}"
1096+
return f"{self.__class__.__name__}\n {str(self._df)}"
10971097

10981098
def __reversed__(self) -> Iterator:
1099-
return reversed(self._agents)
1099+
return reversed(self._df)
11001100

11011101
@property
1102-
def agents(self) -> DataFrame:
1103-
return self._agents
1102+
def df(self) -> DataFrame:
1103+
return self._df
11041104

1105-
@agents.setter
1106-
def agents(self, agents: DataFrame) -> None:
1105+
@df.setter
1106+
def df(self, agents: DataFrame) -> None:
11071107
"""Set the agents in the AgentSetDF.
11081108
11091109
Parameters
11101110
----------
11111111
agents : DataFrame
11121112
The agents to set.
11131113
"""
1114-
self._agents = agents
1114+
self._df = agents
11151115

11161116
@property
11171117
@abstractmethod

mesa_frames/abstract/space.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ def _get_ids_srs(
439439
return self._srs_constructor([], name="agent_id", dtype="uint64")
440440
if isinstance(agents, AgentSetDF):
441441
return self._srs_constructor(
442-
self._df_index(agents.agents, "unique_id"),
442+
self._df_index(agents.df, "unique_id"),
443443
name="agent_id",
444444
dtype="uint64",
445445
)
@@ -451,7 +451,7 @@ def _get_ids_srs(
451451
if isinstance(a, AgentSetDF):
452452
ids.append(
453453
self._srs_constructor(
454-
self._df_index(a.agents, "unique_id"),
454+
self._df_index(a.df, "unique_id"),
455455
name="agent_id",
456456
dtype="uint64",
457457
)

mesa_frames/concrete/agents.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ def get(
220220

221221
for agentset, mask in agentsets_masks.items():
222222
# Fast column existence check - no data processing, just property access
223-
agentset_columns = agentset.agents.columns
223+
agentset_columns = agentset.df.columns
224224

225225
# Check if all required columns exist in this agent set
226226
if not required_columns or all(
@@ -532,7 +532,7 @@ def __isub__(self, agents: AgentSetDF | Iterable[AgentSetDF] | IdsLike) -> Self:
532532
return super().__isub__(agents)
533533

534534
def __len__(self) -> int:
535-
return sum(len(agentset._agents) for agentset in self._agentsets)
535+
return sum(len(agentset._df) for agentset in self._agentsets)
536536

537537
def __repr__(self) -> str:
538538
return "\n".join([repr(agentset) for agentset in self._agentsets])
@@ -577,11 +577,11 @@ def __sub__(self, agents: AgentSetDF | Iterable[AgentSetDF] | IdsLike) -> Self:
577577
return super().__sub__(agents)
578578

579579
@property
580-
def agents(self) -> dict[AgentSetDF, DataFrame]:
581-
return {agentset: agentset.agents for agentset in self._agentsets}
580+
def df(self) -> dict[AgentSetDF, DataFrame]:
581+
return {agentset: agentset.df for agentset in self._agentsets}
582582

583-
@agents.setter
584-
def agents(self, other: Iterable[AgentSetDF]) -> None:
583+
@df.setter
584+
def df(self, other: Iterable[AgentSetDF]) -> None:
585585
"""Set the agents in the AgentsDF.
586586
587587
Parameters

0 commit comments

Comments
 (0)