Skip to content

Commit

Permalink
feat(python): allow for simple creation of n-row empty frame/series v…
Browse files Browse the repository at this point in the history
…ia `clear` (#7095)
  • Loading branch information
alexander-beedie authored Feb 22, 2023
1 parent 54eb6b0 commit 0f16412
Show file tree
Hide file tree
Showing 14 changed files with 236 additions and 144 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Manipulation/selection
.. autosummary::
:toctree: api/

DataFrame.cleared
DataFrame.clear
DataFrame.clone
DataFrame.drop
DataFrame.drop_in_place
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Manipulation/selection
.. autosummary::
:toctree: api/

LazyFrame.cleared
LazyFrame.clear
LazyFrame.clone
LazyFrame.drop
LazyFrame.drop_nulls
Expand Down
2 changes: 1 addition & 1 deletion py-polars/docs/source/reference/series/modify_select.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Manipulation/selection
Series.argsort
Series.cast
Series.ceil
Series.cleared
Series.clear
Series.clip
Series.clip_max
Series.clip_min
Expand Down
2 changes: 1 addition & 1 deletion py-polars/polars/internals/construction.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ def sequence_to_pyseries(
nan_to_null=nan_to_null,
strict=strict,
)
return s if values else pli.Series._from_pyseries(s)[:0]._s
return s if values else pli.Series._from_pyseries(s).head(0)._s

# logs will show a panic if we infer wrong dtype and it's hard to error
# from the rust side. to reduce the likelihood of this happening we
Expand Down
34 changes: 29 additions & 5 deletions py-polars/polars/internals/dataframe/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ def wrap_df(df: PyDataFrame) -> DataFrame:

@redirect(
{
"cleared": "clear",
"iterrows": "iter_rows",
"with_column": "with_columns",
}
Expand Down Expand Up @@ -4822,12 +4823,17 @@ def drop_in_place(self, name: str) -> pli.Series:
"""
return pli.wrap_s(self._df.drop_in_place(name))

def cleared(self) -> Self:
def clear(self, n: int = 0) -> Self:
"""
Create an empty copy of the current DataFrame.
Create an empty copy of the current DataFrame, with zero to 'n' rows.
Returns a DataFrame with identical schema but no data.
Parameters
----------
n
Number of (empty) rows to return in the cleared frame.
See Also
--------
clone : Cheap deepcopy/clone.
Expand All @@ -4841,7 +4847,7 @@ def cleared(self) -> Self:
... "c": [True, True, False, None],
... }
... )
>>> df.cleared()
>>> df.clear()
shape: (0, 3)
┌─────┬─────┬──────┐
│ a ┆ b ┆ c │
Expand All @@ -4850,16 +4856,34 @@ def cleared(self) -> Self:
╞═════╪═════╪══════╡
└─────┴─────┴──────┘
>>> df.clear(n=2)
shape: (2, 3)
┌──────┬──────┬──────┐
│ a ┆ b ┆ c │
│ --- ┆ --- ┆ --- │
│ i64 ┆ f64 ┆ bool │
╞══════╪══════╪══════╡
│ null ┆ null ┆ null │
│ null ┆ null ┆ null │
└──────┴──────┴──────┘
"""
return self.head(0) if len(self) > 0 else self.clone()
if n > 0 or len(self) > 0:
return self.__class__(
{
nm: pli.Series(name=nm, dtype=tp).extend_constant(None, n)
for nm, tp in self.schema.items()
}
)
return self.clone()

def clone(self) -> Self:
"""
Cheap deepcopy/clone.
See Also
--------
cleared : Create an empty copy of the current DataFrame, with identical
clear : Create an empty copy of the current DataFrame, with identical
schema but no data.
Examples
Expand Down
39 changes: 30 additions & 9 deletions py-polars/polars/internals/lazyframe/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,12 @@ def wrap_ldf(ldf: PyLazyFrame) -> LazyFrame:
return LazyFrame._from_pyldf(ldf)


@redirect({"with_column": "with_columns"})
@redirect(
{
"cleared": "clear",
"with_column": "with_columns",
}
)
class LazyFrame:
"""
Representation of a Lazy computation graph/query against a DataFrame.
Expand Down Expand Up @@ -1442,26 +1447,31 @@ def cache(self) -> Self:
"""Cache the result once the execution of the physical plan hits this node."""
return self._from_pyldf(self._ldf.cache())

def cleared(self) -> Self:
def clear(self, n: int = 0) -> Self:
"""
Create an empty copy of the current LazyFrame.
Create an empty copy of the current LazyFrame, with zero to 'n' rows.
Returns a copy with an identical schema but no data.
The copy has an identical schema but no data.
Parameters
----------
n
Number of (empty) rows to return in the cleared frame.
See Also
--------
clone : Cheap deepcopy/clone.
Examples
--------
>>> df = pl.DataFrame(
>>> ldf = pl.DataFrame(
... {
... "a": [None, 2, 3, 4],
... "b": [0.5, None, 2.5, 13],
... "c": [True, True, False, None],
... }
... ).lazy()
>>> df.cleared().fetch()
>>> ldf.clear().fetch()
shape: (0, 3)
┌─────┬─────┬──────┐
│ a ┆ b ┆ c │
Expand All @@ -1470,16 +1480,27 @@ def cleared(self) -> Self:
╞═════╪═════╪══════╡
└─────┴─────┴──────┘
>>> ldf.clear(2).fetch()
shape: (2, 3)
┌──────┬──────┬──────┐
│ a ┆ b ┆ c │
│ --- ┆ --- ┆ --- │
│ i64 ┆ f64 ┆ bool │
╞══════╪══════╪══════╡
│ null ┆ null ┆ null │
│ null ┆ null ┆ null │
└──────┴──────┴──────┘
"""
return self._from_pyldf(pli.DataFrame(schema=self.schema).lazy()._ldf)
return self._from_pyldf(pli.DataFrame(schema=self.schema).clear(n).lazy()._ldf)

def clone(self) -> Self:
"""
Very cheap deepcopy/clone.
See Also
--------
cleared : Create an empty copy of the current LazyFrame, with identical
clear : Create an empty copy of the current LazyFrame, with identical
schema but no data.
Examples
Expand Down Expand Up @@ -3144,7 +3165,7 @@ def tail(self, n: int = 5) -> Self:
Parameters
----------
n
Number of rows.
Number of rows to return.
Examples
--------
Expand Down
37 changes: 30 additions & 7 deletions py-polars/polars/internals/series/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,12 @@ def wrap_s(s: PySeries) -> Series:
return Series._from_pyseries(s)


@redirect({"is_datelike": "is_temporal"})
@redirect(
{
"cleared": "clear",
"is_datelike": "is_temporal",
}
)
@expr_dispatch
class Series:
"""
Expand Down Expand Up @@ -3182,11 +3187,16 @@ def set_at_idx(
self._s.set_at_idx(idx._s, value._s)
return self

def cleared(self) -> Series:
def clear(self, n: int = 0) -> Series:
"""
Create an empty copy of the current Series.
Create an empty copy of the current Series, with zero to 'n' elements.
The copy has identical name/dtype but no data.
The copy has an identical name/dtype, but no data.
Parameters
----------
n
Number of (empty) elements to return in the cleared frame.
See Also
--------
Expand All @@ -3195,22 +3205,35 @@ def cleared(self) -> Series:
Examples
--------
>>> s = pl.Series("a", [None, True, False])
>>> s.cleared()
>>> s.clear()
shape: (0,)
Series: 'a' [bool]
[
]
>>> s.clear(n=2)
shape: (2,)
Series: 'a' [bool]
[
null
null
]
"""
return self.limit(0) if len(self) > 0 else self.clone()
s = (
self.__class__(name=self.name, values=[], dtype=self.dtype)
if len(self) > 0
else self.clone()
)
return s.extend_constant(None, n=n) if n > 0 else s

def clone(self) -> Series:
"""
Very cheap deepcopy/clone.
See Also
--------
cleared : Create an empty copy of the current Series, with identical
clear : Create an empty copy of the current Series, with identical
schema but no data.
Examples
Expand Down
4 changes: 2 additions & 2 deletions py-polars/polars/internals/slice.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def apply(self, s: slice) -> FrameOrSeries:

# check for fast-paths / single-operation calls
if self.slice_length == 0:
return self.obj.cleared()
return self.obj.clear()

elif self.is_unbounded and self.stride in (-1, 1):
return self.obj.reverse() if (self.stride < 0) else self.obj.clone()
Expand Down Expand Up @@ -146,7 +146,7 @@ def apply(self, s: slice) -> "pli.LazyFrame":
if (step > 0 and (s.stop is not None and start >= s.stop)) or (
step < 0 and (s.stop is not None and s.stop >= s.start >= 0)
):
return self.obj.cleared()
return self.obj.clear()

# ---------------------------------------
# straight-through mappings for "reverse"
Expand Down
Loading

0 comments on commit 0f16412

Please sign in to comment.