Repository: pyjanitor-devs/pyjanitor (python)

Issue:
`alias` function for `pd.Series`
# Brief Description

<!-- Please provide a brief description of what you'd like to propose. -->

I would like to propose pd.Series.alias(new name) to allow for convenient renaming of a Series.
This comes in handy when renaming within a function, and allow for changing a Series name via a callable.
pd.Series.rename only changes the name if a scalar is passed; if a callable is passed, it is passed to the index labels, not the name of the Series. alias works only on the name, not the index labels.

# Example API

```python
series = pd.Series({'a':[1,2,3]})
series.alias('new_name')
series.alias(str.lower)
series.alias(lambda s: f"{s}_mean")
```


Pull request:
[ENH] add alias function for series

# PR Description

Please describe the changes proposed in the pull request:

- Add `.alias` function for pd.Series
- comes in handy when renaming Series within functions, or when you need to use a callable

**This PR resolves #1449 **

Please tag maintainers to review.

- @ericmjl


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2740ad2..bcb597b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@
 -  [ENH] Added support for pd.Series.select - Issue #1394 @samukweku
 -  [ENH] Added suport for janitor.mutate - Issue #1226 @samukweku
 -  [ENH] Added support for janitor.summarise - Issue #1225 @samukweku
+-  [ENH] Added support for janitor.alias - Issue #1449 @samukweku
 
 ## [v0.30.0] - 2024-12-04
 
diff --git a/janitor/functions/__init__.py b/janitor/functions/__init__.py
index 03ed1bb..402ec54 100644
--- a/janitor/functions/__init__.py
+++ b/janitor/functions/__init__.py
@@ -16,6 +16,7 @@ pyjanitor's general-purpose data cleaning functions.
 # 7. Never import utils.
 
 from .add_columns import add_columns
+from .alias import alias
 from .also import also
 from .bin_numeric import bin_numeric
 from .case_when import case_when
@@ -96,6 +97,7 @@ from .utils import (
 
 __all__ = [
     "add_columns",
+    "alias",
     "also",
     "bin_numeric",
     "cartesian_product",
diff --git a/janitor/functions/alias.py b/janitor/functions/alias.py
new file mode 100644
index 0000000..d6613d2
--- /dev/null
+++ b/janitor/functions/alias.py
@@ -0,0 +1,49 @@
+"""Implementation of the `toset` function."""
+
+from __future__ import annotations
+
+from typing import Any
+
+import pandas as pd
+import pandas_flavor as pf
+
+
+@pf.register_series_method
+def alias(series: pd.Series, alias: Any = None) -> pd.Series:
+    """Return a Series with a new name. Accepts either a scalar or a callable.
+
+
+    Examples:
+        >>> import pandas as pd
+        >>> import janitor
+        >>> s = pd.Series([1, 2, 3], name='series')
+        >>> s
+        0    1
+        1    2
+        2    3
+        Name: series, dtype: int64
+        >>> s.alias('series_new')
+        0    1
+        1    2
+        2    3
+        Name: series_new, dtype: int64
+        >>> s.alias(str.upper)
+        0    1
+        1    2
+        2    3
+        Name: SERIES, dtype: int64
+
+    Args:
+        series: A pandas Series.
+        alias: scalar or callable to create a new name for the pandas Series.
+
+    Returns:
+        A new pandas Series.
+    """
+    series = series[:]
+    if alias is None:
+        return series
+    if callable(alias):
+        alias = alias(series.name)
+    series.name = alias
+    return series
diff --git a/mkdocs/api/functions.md b/mkdocs/api/functions.md
index e7d043e..9e1a745 100644
--- a/mkdocs/api/functions.md
+++ b/mkdocs/api/functions.md
@@ -6,6 +6,7 @@
       - "!^_"
       members:
         - add_columns
+        - alias
         - also
         - bin_numeric
         - case_when


Test patch:
diff --git a/tests/functions/test_alias.py b/tests/functions/test_alias.py
new file mode 100644
index 0000000..bca1ee4
--- /dev/null
+++ b/tests/functions/test_alias.py
@@ -0,0 +1,20 @@
+import pandas as pd
+from pandas.testing import assert_series_equal
+
+
+def test_alias_no_name():
+    """Test output if Series does not have a name"""
+    series = pd.Series([1, 2, 3])
+    assert_series_equal(series, series.alias())
+
+
+def test_alias_callable():
+    """Test output if alias is a callable"""
+    series = pd.Series([1, 2, 3], name="UPPER")
+    assert_series_equal(series.rename("upper"), series.alias(str.lower))
+
+
+def test_alias_scalar():
+    """Test output if alias is a scalar"""
+    series = pd.Series([1, 2, 3], name="UPPER")
+    assert_series_equal(series.rename("upper"), series.alias("upper"))