Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Comparison and Indexing methods to DataFrameMixin #58

Merged
merged 35 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
d8cab68
fix to _df_all and _df_concat
adamamer20 Aug 4, 2024
98bfe11
adding right overload to concat
adamamer20 Aug 4, 2024
015edee
Merge branch 'main' of https://github.com/adamamer20/mesa-frames into…
adamamer20 Aug 4, 2024
77ad379
change _df_filter to _df_get_masked_df + _df_all
adamamer20 Aug 4, 2024
9f757c8
adding custom name to _df_groupby_cumcount
adamamer20 Aug 4, 2024
7fe1933
Merge branch 'main' of https://github.com/adamamer20/mesa-frames into…
adamamer20 Aug 5, 2024
b4f757a
Merge branch 'main' of https://github.com/adamamer20/mesa-frames into…
adamamer20 Aug 12, 2024
3186a12
adding tests for PolarsMixin
adamamer20 Aug 12, 2024
93c7db3
fixes to PolarsMixins
adamamer20 Aug 12, 2024
f3543b9
Merge branch 'main' of https://github.com/adamamer20/mesa-frames into…
adamamer20 Aug 12, 2024
1ec89ae
Merge branch 'main' of https://github.com/adamamer20/mesa-frames into…
adamamer20 Aug 12, 2024
7280243
Merge branch 'main' into 53-tests-for-polarsmixin
adamamer20 Aug 12, 2024
e3e6d91
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 12, 2024
703b561
adding index_cols to _df_join per abstract DataFrameMixin
adamamer20 Aug 12, 2024
7746cc8
Merge branch '53-tests-for-polarsmixin' of https://github.com/adamame…
adamamer20 Aug 12, 2024
089900d
adding greater or equal to DataFrameMixin
adamamer20 Aug 12, 2024
e3423a9
adding boolean or to DataFrameMixin
adamamer20 Aug 12, 2024
58a149d
adding less than to DataFrameMixin
adamamer20 Aug 12, 2024
7c0f3da
adding _df_and and _df_or
adamamer20 Aug 12, 2024
ca42fe5
using mixin logical operations in space
adamamer20 Aug 12, 2024
e0914ee
fixing collections mixin
adamamer20 Aug 12, 2024
6187c8d
adding modulus to DataFrameMixin
adamamer20 Aug 13, 2024
5ba1bbe
adding index to DataFrameMixin
adamamer20 Aug 13, 2024
9ea50e0
fixes to method logic
adamamer20 Aug 13, 2024
a096a5d
Merge branch '53-tests-for-polarsmixin' of https://github.com/adamame…
adamamer20 Aug 13, 2024
c89a7ef
changing % to _df_mod in abstract space
adamamer20 Aug 13, 2024
4d603d3
adding reindexing DataFrameMixin
adamamer20 Aug 13, 2024
d459f80
fixing reindex logic
adamamer20 Aug 13, 2024
ce1a0df
testing _df_or
adamamer20 Aug 13, 2024
5bdae00
Merge branch 'main' into comparisons-mixin
adamamer20 Aug 13, 2024
0be0c62
Merge branch 'main' into comparisons-mixin
adamamer20 Aug 13, 2024
e64d384
missing ")"
adamamer20 Aug 13, 2024
865028b
Fixing abstract space methods with new logical _df methods
adamamer20 Aug 13, 2024
2d42afe
adding tests for _df_reindex
adamamer20 Aug 13, 2024
6ec9144
Merge branch 'tests_mixin_pandas' into comparisons-mixin
adamamer20 Aug 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions mesa_frames/abstract/mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,15 @@ class DataFrameMixin(ABC):
def _df_remove(self, df: DataFrame, mask: Mask, index_cols: str) -> DataFrame:
return self._df_get_masked_df(df, index_cols, mask, negate=True)

@abstractmethod
def _df_and(
self,
df: DataFrame,
other: DataFrame | Sequence[float | int],
axis: Literal["index", "columns"] = "index",
index_cols: str | list[str] | None = None,
) -> DataFrame: ...

@abstractmethod
def _df_add(
self,
Expand Down Expand Up @@ -258,6 +267,15 @@ def _df_drop_duplicates(
keep: Literal["first", "last", False] = "first",
) -> DataFrame: ...

@abstractmethod
def _df_ge(
self,
df: DataFrame,
other: DataFrame | Sequence[float | int],
axis: Literal["index", "columns"] = "index",
index_cols: str | list[str] | None = None,
) -> DataFrame: ...

@abstractmethod
def _df_get_bool_mask(
self,
Expand All @@ -282,6 +300,9 @@ def _df_groupby_cumcount(
self, df: DataFrame, by: str | list[str], name: str = "cum_count"
) -> Series: ...

@abstractmethod
def _df_index(self, df: DataFrame, index_name: str) -> Index: ...

@abstractmethod
def _df_iterator(self, df: DataFrame) -> Iterator[dict[str, Any]]: ...

Expand All @@ -302,6 +323,24 @@ def _df_join(
suffix="_right",
) -> DataFrame: ...

@abstractmethod
def _df_lt(
self,
df: DataFrame,
other: DataFrame | Sequence[float | int],
axis: Literal["index", "columns"] = "index",
index_cols: str | list[str] | None = None,
) -> DataFrame: ...

@abstractmethod
def _df_mod(
self,
df: DataFrame,
other: DataFrame | Sequence[float | int],
axis: Literal["index", "columns"] = "index",
index_cols: str | list[str] | None = None,
) -> DataFrame: ...

@abstractmethod
def _df_mul(
self,
Expand Down Expand Up @@ -337,6 +376,23 @@ def _df_norm(
include_cols: bool = False,
) -> Series | DataFrame: ...

@abstractmethod
def _df_or(
self,
df: DataFrame,
other: DataFrame | Sequence[float | int],
axis: Literal["index", "columns"] = "index",
index_cols: str | list[str] | None = None,
) -> DataFrame: ...

@abstractmethod
def _df_reindex(
self,
df: DataFrame,
other: Sequence[Hashable] | DataFrame,
index_cols: str | list[str],
) -> DataFrame: ...

@abstractmethod
def _df_rename_columns(
self,
Expand Down
36 changes: 22 additions & 14 deletions mesa_frames/abstract/space.py
Original file line number Diff line number Diff line change
Expand Up @@ -1341,13 +1341,15 @@ def get_neighborhood(
neighbors_df = self._df_drop_duplicates(neighbors_df, self._pos_col_names)

# Filter out-of-bound neighbors
neighbors_df = self._df_get_masked_df(
neighbors_df,
mask=self._df_all(
(neighbors_df[self._pos_col_names] < self._dimensions)
& (neighbors_df >= 0)
),
mask = self._df_all(
self._df_and(
self._df_lt(
neighbors_df[self._pos_col_names], self._dimensions, axis="columns"
),
neighbors_df >= 0,
)
)
neighbors_df = self._df_get_masked_df(neighbors_df, mask=mask)

if include_center:
center_df = self._df_rename_columns(
Expand Down Expand Up @@ -1409,7 +1411,15 @@ def out_of_bounds(self, pos: GridCoordinate | GridCoordinates) -> DataFrame:
raise ValueError("This method is only valid for non-torus grids")
pos_df = self._get_df_coords(pos, check_bounds=False)
out_of_bounds = self._df_all(
(pos_df < 0) | (pos_df >= self._dimensions),
self._df_or(
pos_df < 0,
self._df_ge(
pos_df,
self._dimensions,
axis="columns",
index_cols=self._pos_col_names,
),
),
name="out_of_bounds",
)
return self._df_concat(objs=[pos_df, out_of_bounds], how="horizontal")
Expand Down Expand Up @@ -1452,7 +1462,7 @@ def torus_adj(self, pos: GridCoordinate | GridCoordinates) -> DataFrame:
The adjusted coordinates
"""
df_coords = self._get_df_coords(pos)
df_coords = df_coords % self._dimensions
df_coords = self._df_mod(df_coords, self._dimensions, axis="columns")
return df_coords

def _calculate_differences(
Expand Down Expand Up @@ -1603,13 +1613,11 @@ def _get_df_coords(
if agents.n_unique() != len(agents):
raise ValueError("Some agents are present multiple times")
if agents is not None:
return self._df_reset_index(
self._df_get_masked_df(
self._agents, index_cols="agent_id", mask=agents
),
index_cols="agent_id",
drop=True,
df = self._df_get_masked_df(
self._agents, index_cols="agent_id", mask=agents
)
df = self._df_reindex(df, agents, "agent_id")
return self._df_reset_index(df, index_cols="agent_id", drop=True)
if isinstance(pos, DataFrame):
return pos[self._pos_col_names]
elif (
Expand Down
105 changes: 104 additions & 1 deletion mesa_frames/concrete/pandas/mixin.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from collections.abc import Collection, Hashable, Iterator, Sequence
from collections.abc import Callable, Collection, Hashable, Iterator, Sequence
from typing import Literal

import numpy as np
Expand All @@ -19,6 +19,21 @@
) -> pd.DataFrame:
return df.add(other=other, axis=axis)

def _df_and(
self,
df: pd.DataFrame,
other: pd.DataFrame | Sequence[float | int],
axis: Literal["index"] | Literal["columns"] = "index",
index_cols: str | list[str] | None = None,
) -> pd.DataFrame:
return self._df_logical_operation(
df=df,
other=other,
operation=lambda x, y: x & y,
axis=axis,
index_cols=index_cols,
)

def _df_all(
self,
df: pd.DataFrame,
Expand Down Expand Up @@ -137,6 +152,15 @@
) -> pd.DataFrame:
return df.drop_duplicates(subset=subset, keep=keep)

def _df_ge(
self,
df: pd.DataFrame,
other: pd.DataFrame | Sequence[float | int],
axis: Literal["index", "columns"] = "index",
index_cols: str | list[str] | None = None,
) -> pd.DataFrame:
return df.ge(other, axis=axis)

def _df_get_bool_mask(
self,
df: pd.DataFrame,
Expand Down Expand Up @@ -192,6 +216,16 @@
) -> pd.Series:
return df.groupby(by).cumcount().rename(name) + 1

def _df_index(self, df: pd.DataFrame, index_col: str | list[str]) -> pd.Index:
if (

Check warning on line 220 in mesa_frames/concrete/pandas/mixin.py

View check run for this annotation

Codecov / codecov/patch

mesa_frames/concrete/pandas/mixin.py#L220

Added line #L220 was not covered by tests
index_col is None
or df.index.name == index_col
or df.index.names == index_col
):
return df.index

Check warning on line 225 in mesa_frames/concrete/pandas/mixin.py

View check run for this annotation

Codecov / codecov/patch

mesa_frames/concrete/pandas/mixin.py#L225

Added line #L225 was not covered by tests
else:
return df.set_index(index_col).index

Check warning on line 227 in mesa_frames/concrete/pandas/mixin.py

View check run for this annotation

Codecov / codecov/patch

mesa_frames/concrete/pandas/mixin.py#L227

Added line #L227 was not covered by tests

def _df_iterator(self, df: pd.DataFrame) -> Iterator[dict[str, Any]]:
for index, row in df.iterrows():
row_dict = row.to_dict()
Expand Down Expand Up @@ -246,6 +280,50 @@
else:
return df

def _df_lt(
self,
df: pd.DataFrame,
other: pd.DataFrame | Sequence[float | int],
axis: Literal["index", "columns"] = "index",
index_cols: str | list[str] | None = None,
) -> pd.DataFrame:
return df.lt(other, axis=axis)

def _df_logical_operation(
self,
df: pd.DataFrame,
other: pd.DataFrame | Sequence[bool],
operation: Callable[
[pd.DataFrame, Sequence[bool] | pd.DataFrame], pd.DataFrame
],
axis: Literal["index"] | Literal["columns"] = "index",
index_cols: str | list[str] | None = None,
) -> pd.DataFrame:
if isinstance(other, pd.DataFrame):
if index_cols is not None:
if df.index.name != index_cols:
df = df.set_index(index_cols)
if other.index.name != index_cols:
other = other.set_index(index_cols)

Check warning on line 307 in mesa_frames/concrete/pandas/mixin.py

View check run for this annotation

Codecov / codecov/patch

mesa_frames/concrete/pandas/mixin.py#L304-L307

Added lines #L304 - L307 were not covered by tests
other = other.reindex(df.index, fill_value=np.nan)
return operation(df, other)
else: # Sequence[bool]
other = pd.Series(other)
if axis == "index":
other.index = df.index
return operation(df, other.values[:, None]).astype(bool)

Check warning on line 314 in mesa_frames/concrete/pandas/mixin.py

View check run for this annotation

Codecov / codecov/patch

mesa_frames/concrete/pandas/mixin.py#L311-L314

Added lines #L311 - L314 were not covered by tests
else:
return operation(df, other.values[None, :]).astype(bool)

Check warning on line 316 in mesa_frames/concrete/pandas/mixin.py

View check run for this annotation

Codecov / codecov/patch

mesa_frames/concrete/pandas/mixin.py#L316

Added line #L316 was not covered by tests

def _df_mod(
self,
df: pd.DataFrame,
other: pd.DataFrame | Sequence[float | int],
axis: Literal["index", "columns"] = "index",
index_cols: str | list[str] | None = None,
) -> pd.DataFrame:
return df.mod(other, axis=axis)

def _df_mul(
self,
df: pd.DataFrame,
Expand Down Expand Up @@ -285,6 +363,31 @@
else:
return srs

def _df_or(
self,
df: pd.DataFrame,
other: pd.DataFrame | Sequence[bool],
axis: Literal["index"] | Literal["columns"] = "index",
index_cols: str | list[str] | None = None,
) -> pd.DataFrame:
return self._df_logical_operation(
df=df,
other=other,
operation=lambda x, y: x | y,
axis=axis,
index_cols=index_cols,
)

def _df_reindex(
self,
df: pd.DataFrame,
other: Sequence[Hashable] | pd.DataFrame,
index_cols: str | list[str],
) -> pd.DataFrame:
df = df.reindex(other)
df.index.name = index_cols
return df

def _df_rename_columns(
self,
df: pd.DataFrame,
Expand Down
Loading