We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[BUG] Unhelpful default arguments in `round_to_fraction`
# Brief description

## [`round_to_fraction`](https://github.com/pyjanitor-devs/pyjanitor/blob/9d3653f959f11150bcc9aca87476efc72affc60a/janitor/functions/round_to_fraction.py#L11) function
- The `column_name` parameter is currently given a non-useful default argument (`None`) while the function logic dictates that it should be an existing column within the dataframe. I propose to: 1) make this parameter non-optional, and 2) add an additional check to enforce that the given column name is present in the dataframe.
- Similarly, the `denominator` parameter is currently given a non-useful default `None`, while it should clearly be a number. Propose to either make it non-optional since I'm unsure if there is a sensible default value to place here.


### Minimally Reproducible Code

```python
import numpy as np
import pandas as pd
import janitor
df = pd.DataFrame({
    "a1": [1.203, 2.499, np.nan],
    "a2": ["x", "y", "z"],
})

df.round_to_fraction()  # KeyError: None
df.round_to_fraction("a1")  # TypeError: unsupported operand type(s) for *: 'float' and 'NoneType'
```

The first error should be replaced with a more informative errmsg as per the improvements suggested for `column_name` above.

The second error should be caught earlier (at the moment, the type check of the `denominator` parameter is only done if `denominator` is Truthy, which is not really accurate.)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `janitor/functions/add_columns.py`
Content:
```
1 import pandas_flavor as pf
2 
3 from janitor.utils import check, deprecated_alias
4 import pandas as pd
5 from typing import Union, List, Any, Tuple
6 import numpy as np
7 
8 
9 @pf.register_dataframe_method
10 @deprecated_alias(col_name="column_name")
11 def add_column(
12     df: pd.DataFrame,
13     column_name: str,
14     value: Union[List[Any], Tuple[Any], Any],
15     fill_remaining: bool = False,
16 ) -> pd.DataFrame:
17     """Add a column to the dataframe.
18 
19     Intended to be the method-chaining alternative to:
20 
21     ```python
22     df[column_name] = value
23     ```
24 
25     Example: Add a column of constant values to the dataframe.
26 
27         >>> import pandas as pd
28         >>> import janitor
29         >>> df = pd.DataFrame({"a": list(range(3)), "b": list("abc")})
30         >>> df.add_column(column_name="c", value=1)
31            a  b  c
32         0  0  a  1
33         1  1  b  1
34         2  2  c  1
35 
36     Example: Add a column of different values to the dataframe.
37 
38         >>> import pandas as pd
39         >>> import janitor
40         >>> df = pd.DataFrame({"a": list(range(3)), "b": list("abc")})
41         >>> df.add_column(column_name="c", value=list("efg"))
42            a  b  c
43         0  0  a  e
44         1  1  b  f
45         2  2  c  g
46 
47     Example: Add a column using an iterator.
48 
49         >>> import pandas as pd
50         >>> import janitor
51         >>> df = pd.DataFrame({"a": list(range(3)), "b": list("abc")})
52         >>> df.add_column(column_name="c", value=range(4, 7))
53            a  b  c
54         0  0  a  4
55         1  1  b  5
56         2  2  c  6
57 
58     :param df: A pandas DataFrame.
59     :param column_name: Name of the new column. Should be a string, in order
60         for the column name to be compatible with the Feather binary
61         format (this is a useful thing to have).
62     :param value: Either a single value, or a list/tuple of values.
63     :param fill_remaining: If value is a tuple or list that is smaller than
64         the number of rows in the DataFrame, repeat the list or tuple
65         (R-style) to the end of the DataFrame.
66     :returns: A pandas DataFrame with an added column.
67     :raises ValueError: if attempting to add a column that already exists.
68     :raises ValueError: if `value` has more elements that number of
69         rows in the DataFrame.
70     :raises ValueError: if attempting to add an iterable of values with
71         a length not equal to the number of DataFrame rows.
72     :raises ValueError: if `value` has length of `0``.
73     """
74     df = df.copy()
75     check("column_name", column_name, [str])
76 
77     if column_name in df.columns:
78         raise ValueError(
79             f"Attempted to add column that already exists: " f"{column_name}."
80         )
81 
82     nrows = df.shape[0]
83 
84     if hasattr(value, "__len__") and not isinstance(
85         value, (str, bytes, bytearray)
86     ):
87         # if `value` is a list, ndarray, etc.
88         if len(value) > nrows:
89             raise ValueError(
90                 "`value` has more elements than number of rows "
91                 f"in your `DataFrame`. vals: {len(value)}, "
92                 f"df: {nrows}"
93             )
94         if len(value) != nrows and not fill_remaining:
95             raise ValueError(
96                 "Attempted to add iterable of values with length"
97                 " not equal to number of DataFrame rows"
98             )
99 
100         if len(value) == 0:
101             raise ValueError(
102                 "`value` has to be an iterable of minimum length 1"
103             )
104         len_value = len(value)
105     elif fill_remaining:
106         # relevant if a scalar val was passed, yet fill_remaining == True
107         len_value = 1
108         value = [value]
109 
110     nrows = df.shape[0]
111 
112     if fill_remaining:
113         times_to_loop = int(np.ceil(nrows / len_value))
114 
115         fill_values = list(value) * times_to_loop
116 
117         df[column_name] = fill_values[:nrows]
118     else:
119         df[column_name] = value
120 
121     return df
122 
123 
124 @pf.register_dataframe_method
125 def add_columns(
126     df: pd.DataFrame, fill_remaining: bool = False, **kwargs
127 ) -> pd.DataFrame:
128     """Add multiple columns to the dataframe.
129 
130     This method does not mutate the original DataFrame.
131 
132     Method to augment `add_column` with ability to add multiple columns in
133     one go. This replaces the need for multiple `add_column` calls.
134 
135     Usage is through supplying kwargs where the key is the col name and the
136     values correspond to the values of the new DataFrame column.
137 
138     Values passed can be scalar or iterable (list, ndarray, etc.)
139 
140     Example: Inserting two more columns into a dataframe.
141 
142         >>> import pandas as pd
143         >>> import janitor
144         >>> df = pd.DataFrame({"a": list(range(3)), "b": list("abc")})
145         >>> df.add_columns(x=4, y=list("def"))
146            a  b  x  y
147         0  0  a  4  d
148         1  1  b  4  e
149         2  2  c  4  f
150 
151     :param df: A pandas dataframe.
152     :param fill_remaining: If value is a tuple or list that is smaller than
153         the number of rows in the DataFrame, repeat the list or tuple
154         (R-style) to the end of the DataFrame. (Passed to `add_column`)
155     :param kwargs: column, value pairs which are looped through in
156         `add_column` calls.
157     :returns: A pandas DataFrame with added columns.
158     """
159     # Note: error checking can pretty much be handled in `add_column`
160 
161     for col_name, values in kwargs.items():
162         df = df.add_column(col_name, values, fill_remaining=fill_remaining)
163 
164     return df
165
```

Path: `janitor/functions/round_to_fraction.py`
Content:
```
1 """Implementation of `round_to_fraction`"""
2 from typing import Hashable
3 
4 import numpy as np
5 import pandas as pd
6 import pandas_flavor as pf
7 from janitor.utils import check, deprecated_alias
8 
9 
10 @pf.register_dataframe_method
11 @deprecated_alias(col_name="column_name")
12 def round_to_fraction(
13     df: pd.DataFrame,
14     column_name: Hashable = None,
15     denominator: float = None,
16     digits: float = np.inf,
17 ) -> pd.DataFrame:
18     """Round all values in a column to a fraction.
19 
20     This method mutates the original DataFrame.
21 
22     Taken from [the R package](https://github.com/sfirke/janitor/issues/235).
23 
24     Also, optionally round to a specified number of digits.
25 
26     Example: Round numeric column to the nearest 1/4 value.
27 
28         >>> import numpy as np
29         >>> import pandas as pd
30         >>> import janitor
31         >>> df = pd.DataFrame({
32         ...     "a1": [1.263, 2.499, np.nan],
33         ...     "a2": ["x", "y", "z"],
34         ... })
35         >>> df
36               a1 a2
37         0  1.263  x
38         1  2.499  y
39         2    NaN  z
40         >>> df.round_to_fraction("a1", denominator=4)
41              a1 a2
42         0  1.25  x
43         1  2.50  y
44         2   NaN  z
45 
46     :param df: A pandas DataFrame.
47     :param column_name: Name of column to round to fraction.
48     :param denominator: The denominator of the fraction for rounding.
49     :param digits: The number of digits for rounding after rounding to the
50         fraction. Default is np.inf (i.e. no subsequent rounding).
51     :returns: A pandas DataFrame with a column's values rounded.
52     """
53     if denominator:
54         check("denominator", denominator, [float, int])
55 
56     if digits:
57         check("digits", digits, [float, int])
58 
59     df[column_name] = round(df[column_name] * denominator, 0) / denominator
60     if not np.isinf(digits):
61         df[column_name] = round(df[column_name], digits)
62 
63     return df
64
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/janitor/functions/add_columns.py b/janitor/functions/add_columns.py
--- a/janitor/functions/add_columns.py
+++ b/janitor/functions/add_columns.py
@@ -69,7 +69,7 @@
         rows in the DataFrame.
     :raises ValueError: if attempting to add an iterable of values with
         a length not equal to the number of DataFrame rows.
-    :raises ValueError: if `value` has length of `0``.
+    :raises ValueError: if `value` has length of `0`.
     """
     df = df.copy()
     check("column_name", column_name, [str])
diff --git a/janitor/functions/round_to_fraction.py b/janitor/functions/round_to_fraction.py
--- a/janitor/functions/round_to_fraction.py
+++ b/janitor/functions/round_to_fraction.py
@@ -4,15 +4,15 @@
 import numpy as np
 import pandas as pd
 import pandas_flavor as pf
-from janitor.utils import check, deprecated_alias
+from janitor.utils import check, check_column, deprecated_alias
 
 
 @pf.register_dataframe_method
 @deprecated_alias(col_name="column_name")
 def round_to_fraction(
     df: pd.DataFrame,
-    column_name: Hashable = None,
-    denominator: float = None,
+    column_name: Hashable,
+    denominator: float,
     digits: float = np.inf,
 ) -> pd.DataFrame:
     """Round all values in a column to a fraction.
@@ -45,16 +45,19 @@
 
     :param df: A pandas DataFrame.
     :param column_name: Name of column to round to fraction.
-    :param denominator: The denominator of the fraction for rounding.
+    :param denominator: The denominator of the fraction for rounding. Must be
+        a positive number.
     :param digits: The number of digits for rounding after rounding to the
         fraction. Default is np.inf (i.e. no subsequent rounding).
     :returns: A pandas DataFrame with a column's values rounded.
+    :raises ValueError: If `denominator` is not a positive number.
     """
-    if denominator:
-        check("denominator", denominator, [float, int])
+    check_column(df, column_name)
+    check("denominator", denominator, [float, int])
+    check("digits", digits, [float, int])
 
-    if digits:
-        check("digits", digits, [float, int])
+    if denominator <= 0:
+        raise ValueError("denominator is expected to be a positive number.")
 
     df[column_name] = round(df[column_name] * denominator, 0) / denominator
     if not np.isinf(digits):

{"golden_diff": "diff --git a/janitor/functions/add_columns.py b/janitor/functions/add_columns.py\n--- a/janitor/functions/add_columns.py\n+++ b/janitor/functions/add_columns.py\n@@ -69,7 +69,7 @@\n         rows in the DataFrame.\n     :raises ValueError: if attempting to add an iterable of values with\n         a length not equal to the number of DataFrame rows.\n-    :raises ValueError: if `value` has length of `0``.\n+    :raises ValueError: if `value` has length of `0`.\n     \"\"\"\n     df = df.copy()\n     check(\"column_name\", column_name, [str])\ndiff --git a/janitor/functions/round_to_fraction.py b/janitor/functions/round_to_fraction.py\n--- a/janitor/functions/round_to_fraction.py\n+++ b/janitor/functions/round_to_fraction.py\n@@ -4,15 +4,15 @@\n import numpy as np\n import pandas as pd\n import pandas_flavor as pf\n-from janitor.utils import check, deprecated_alias\n+from janitor.utils import check, check_column, deprecated_alias\n \n \n @pf.register_dataframe_method\n @deprecated_alias(col_name=\"column_name\")\n def round_to_fraction(\n     df: pd.DataFrame,\n-    column_name: Hashable = None,\n-    denominator: float = None,\n+    column_name: Hashable,\n+    denominator: float,\n     digits: float = np.inf,\n ) -> pd.DataFrame:\n     \"\"\"Round all values in a column to a fraction.\n@@ -45,16 +45,19 @@\n \n     :param df: A pandas DataFrame.\n     :param column_name: Name of column to round to fraction.\n-    :param denominator: The denominator of the fraction for rounding.\n+    :param denominator: The denominator of the fraction for rounding. Must be\n+        a positive number.\n     :param digits: The number of digits for rounding after rounding to the\n         fraction. Default is np.inf (i.e. no subsequent rounding).\n     :returns: A pandas DataFrame with a column's values rounded.\n+    :raises ValueError: If `denominator` is not a positive number.\n     \"\"\"\n-    if denominator:\n-        check(\"denominator\", denominator, [float, int])\n+    check_column(df, column_name)\n+    check(\"denominator\", denominator, [float, int])\n+    check(\"digits\", digits, [float, int])\n \n-    if digits:\n-        check(\"digits\", digits, [float, int])\n+    if denominator <= 0:\n+        raise ValueError(\"denominator is expected to be a positive number.\")\n \n     df[column_name] = round(df[column_name] * denominator, 0) / denominator\n     if not np.isinf(digits):\n", "issue": "[BUG] Unhelpful default arguments in `round_to_fraction`\n# Brief description\r\n\r\n## [`round_to_fraction`](https://github.com/pyjanitor-devs/pyjanitor/blob/9d3653f959f11150bcc9aca87476efc72affc60a/janitor/functions/round_to_fraction.py#L11) function\r\n- The `column_name` parameter is currently given a non-useful default argument (`None`) while the function logic dictates that it should be an existing column within the dataframe. I propose to: 1) make this parameter non-optional, and 2) add an additional check to enforce that the given column name is present in the dataframe.\r\n- Similarly, the `denominator` parameter is currently given a non-useful default `None`, while it should clearly be a number. Propose to either make it non-optional since I'm unsure if there is a sensible default value to place here.\r\n\r\n\r\n### Minimally Reproducible Code\r\n\r\n```python\r\nimport numpy as np\r\nimport pandas as pd\r\nimport janitor\r\ndf = pd.DataFrame({\r\n    \"a1\": [1.203, 2.499, np.nan],\r\n    \"a2\": [\"x\", \"y\", \"z\"],\r\n})\r\n\r\ndf.round_to_fraction()  # KeyError: None\r\ndf.round_to_fraction(\"a1\")  # TypeError: unsupported operand type(s) for *: 'float' and 'NoneType'\r\n```\r\n\r\nThe first error should be replaced with a more informative errmsg as per the improvements suggested for `column_name` above.\r\n\r\nThe second error should be caught earlier (at the moment, the type check of the `denominator` parameter is only done if `denominator` is Truthy, which is not really accurate.)\r\n\n", "before_files": [{"content": "import pandas_flavor as pf\n\nfrom janitor.utils import check, deprecated_alias\nimport pandas as pd\nfrom typing import Union, List, Any, Tuple\nimport numpy as np\n\n\n@pf.register_dataframe_method\n@deprecated_alias(col_name=\"column_name\")\ndef add_column(\n    df: pd.DataFrame,\n    column_name: str,\n    value: Union[List[Any], Tuple[Any], Any],\n    fill_remaining: bool = False,\n) -> pd.DataFrame:\n    \"\"\"Add a column to the dataframe.\n\n    Intended to be the method-chaining alternative to:\n\n    ```python\n    df[column_name] = value\n    ```\n\n    Example: Add a column of constant values to the dataframe.\n\n        >>> import pandas as pd\n        >>> import janitor\n        >>> df = pd.DataFrame({\"a\": list(range(3)), \"b\": list(\"abc\")})\n        >>> df.add_column(column_name=\"c\", value=1)\n           a  b  c\n        0  0  a  1\n        1  1  b  1\n        2  2  c  1\n\n    Example: Add a column of different values to the dataframe.\n\n        >>> import pandas as pd\n        >>> import janitor\n        >>> df = pd.DataFrame({\"a\": list(range(3)), \"b\": list(\"abc\")})\n        >>> df.add_column(column_name=\"c\", value=list(\"efg\"))\n           a  b  c\n        0  0  a  e\n        1  1  b  f\n        2  2  c  g\n\n    Example: Add a column using an iterator.\n\n        >>> import pandas as pd\n        >>> import janitor\n        >>> df = pd.DataFrame({\"a\": list(range(3)), \"b\": list(\"abc\")})\n        >>> df.add_column(column_name=\"c\", value=range(4, 7))\n           a  b  c\n        0  0  a  4\n        1  1  b  5\n        2  2  c  6\n\n    :param df: A pandas DataFrame.\n    :param column_name: Name of the new column. Should be a string, in order\n        for the column name to be compatible with the Feather binary\n        format (this is a useful thing to have).\n    :param value: Either a single value, or a list/tuple of values.\n    :param fill_remaining: If value is a tuple or list that is smaller than\n        the number of rows in the DataFrame, repeat the list or tuple\n        (R-style) to the end of the DataFrame.\n    :returns: A pandas DataFrame with an added column.\n    :raises ValueError: if attempting to add a column that already exists.\n    :raises ValueError: if `value` has more elements that number of\n        rows in the DataFrame.\n    :raises ValueError: if attempting to add an iterable of values with\n        a length not equal to the number of DataFrame rows.\n    :raises ValueError: if `value` has length of `0``.\n    \"\"\"\n    df = df.copy()\n    check(\"column_name\", column_name, [str])\n\n    if column_name in df.columns:\n        raise ValueError(\n            f\"Attempted to add column that already exists: \" f\"{column_name}.\"\n        )\n\n    nrows = df.shape[0]\n\n    if hasattr(value, \"__len__\") and not isinstance(\n        value, (str, bytes, bytearray)\n    ):\n        # if `value` is a list, ndarray, etc.\n        if len(value) > nrows:\n            raise ValueError(\n                \"`value` has more elements than number of rows \"\n                f\"in your `DataFrame`. vals: {len(value)}, \"\n                f\"df: {nrows}\"\n            )\n        if len(value) != nrows and not fill_remaining:\n            raise ValueError(\n                \"Attempted to add iterable of values with length\"\n                \" not equal to number of DataFrame rows\"\n            )\n\n        if len(value) == 0:\n            raise ValueError(\n                \"`value` has to be an iterable of minimum length 1\"\n            )\n        len_value = len(value)\n    elif fill_remaining:\n        # relevant if a scalar val was passed, yet fill_remaining == True\n        len_value = 1\n        value = [value]\n\n    nrows = df.shape[0]\n\n    if fill_remaining:\n        times_to_loop = int(np.ceil(nrows / len_value))\n\n        fill_values = list(value) * times_to_loop\n\n        df[column_name] = fill_values[:nrows]\n    else:\n        df[column_name] = value\n\n    return df\n\n\n@pf.register_dataframe_method\ndef add_columns(\n    df: pd.DataFrame, fill_remaining: bool = False, **kwargs\n) -> pd.DataFrame:\n    \"\"\"Add multiple columns to the dataframe.\n\n    This method does not mutate the original DataFrame.\n\n    Method to augment `add_column` with ability to add multiple columns in\n    one go. This replaces the need for multiple `add_column` calls.\n\n    Usage is through supplying kwargs where the key is the col name and the\n    values correspond to the values of the new DataFrame column.\n\n    Values passed can be scalar or iterable (list, ndarray, etc.)\n\n    Example: Inserting two more columns into a dataframe.\n\n        >>> import pandas as pd\n        >>> import janitor\n        >>> df = pd.DataFrame({\"a\": list(range(3)), \"b\": list(\"abc\")})\n        >>> df.add_columns(x=4, y=list(\"def\"))\n           a  b  x  y\n        0  0  a  4  d\n        1  1  b  4  e\n        2  2  c  4  f\n\n    :param df: A pandas dataframe.\n    :param fill_remaining: If value is a tuple or list that is smaller than\n        the number of rows in the DataFrame, repeat the list or tuple\n        (R-style) to the end of the DataFrame. (Passed to `add_column`)\n    :param kwargs: column, value pairs which are looped through in\n        `add_column` calls.\n    :returns: A pandas DataFrame with added columns.\n    \"\"\"\n    # Note: error checking can pretty much be handled in `add_column`\n\n    for col_name, values in kwargs.items():\n        df = df.add_column(col_name, values, fill_remaining=fill_remaining)\n\n    return df\n", "path": "janitor/functions/add_columns.py"}, {"content": "\"\"\"Implementation of `round_to_fraction`\"\"\"\nfrom typing import Hashable\n\nimport numpy as np\nimport pandas as pd\nimport pandas_flavor as pf\nfrom janitor.utils import check, deprecated_alias\n\n\n@pf.register_dataframe_method\n@deprecated_alias(col_name=\"column_name\")\ndef round_to_fraction(\n    df: pd.DataFrame,\n    column_name: Hashable = None,\n    denominator: float = None,\n    digits: float = np.inf,\n) -> pd.DataFrame:\n    \"\"\"Round all values in a column to a fraction.\n\n    This method mutates the original DataFrame.\n\n    Taken from [the R package](https://github.com/sfirke/janitor/issues/235).\n\n    Also, optionally round to a specified number of digits.\n\n    Example: Round numeric column to the nearest 1/4 value.\n\n        >>> import numpy as np\n        >>> import pandas as pd\n        >>> import janitor\n        >>> df = pd.DataFrame({\n        ...     \"a1\": [1.263, 2.499, np.nan],\n        ...     \"a2\": [\"x\", \"y\", \"z\"],\n        ... })\n        >>> df\n              a1 a2\n        0  1.263  x\n        1  2.499  y\n        2    NaN  z\n        >>> df.round_to_fraction(\"a1\", denominator=4)\n             a1 a2\n        0  1.25  x\n        1  2.50  y\n        2   NaN  z\n\n    :param df: A pandas DataFrame.\n    :param column_name: Name of column to round to fraction.\n    :param denominator: The denominator of the fraction for rounding.\n    :param digits: The number of digits for rounding after rounding to the\n        fraction. Default is np.inf (i.e. no subsequent rounding).\n    :returns: A pandas DataFrame with a column's values rounded.\n    \"\"\"\n    if denominator:\n        check(\"denominator\", denominator, [float, int])\n\n    if digits:\n        check(\"digits\", digits, [float, int])\n\n    df[column_name] = round(df[column_name] * denominator, 0) / denominator\n    if not np.isinf(digits):\n        df[column_name] = round(df[column_name], digits)\n\n    return df\n", "path": "janitor/functions/round_to_fraction.py"}], "after_files": [{"content": "import pandas_flavor as pf\n\nfrom janitor.utils import check, deprecated_alias\nimport pandas as pd\nfrom typing import Union, List, Any, Tuple\nimport numpy as np\n\n\n@pf.register_dataframe_method\n@deprecated_alias(col_name=\"column_name\")\ndef add_column(\n    df: pd.DataFrame,\n    column_name: str,\n    value: Union[List[Any], Tuple[Any], Any],\n    fill_remaining: bool = False,\n) -> pd.DataFrame:\n    \"\"\"Add a column to the dataframe.\n\n    Intended to be the method-chaining alternative to:\n\n    ```python\n    df[column_name] = value\n    ```\n\n    Example: Add a column of constant values to the dataframe.\n\n        >>> import pandas as pd\n        >>> import janitor\n        >>> df = pd.DataFrame({\"a\": list(range(3)), \"b\": list(\"abc\")})\n        >>> df.add_column(column_name=\"c\", value=1)\n           a  b  c\n        0  0  a  1\n        1  1  b  1\n        2  2  c  1\n\n    Example: Add a column of different values to the dataframe.\n\n        >>> import pandas as pd\n        >>> import janitor\n        >>> df = pd.DataFrame({\"a\": list(range(3)), \"b\": list(\"abc\")})\n        >>> df.add_column(column_name=\"c\", value=list(\"efg\"))\n           a  b  c\n        0  0  a  e\n        1  1  b  f\n        2  2  c  g\n\n    Example: Add a column using an iterator.\n\n        >>> import pandas as pd\n        >>> import janitor\n        >>> df = pd.DataFrame({\"a\": list(range(3)), \"b\": list(\"abc\")})\n        >>> df.add_column(column_name=\"c\", value=range(4, 7))\n           a  b  c\n        0  0  a  4\n        1  1  b  5\n        2  2  c  6\n\n    :param df: A pandas DataFrame.\n    :param column_name: Name of the new column. Should be a string, in order\n        for the column name to be compatible with the Feather binary\n        format (this is a useful thing to have).\n    :param value: Either a single value, or a list/tuple of values.\n    :param fill_remaining: If value is a tuple or list that is smaller than\n        the number of rows in the DataFrame, repeat the list or tuple\n        (R-style) to the end of the DataFrame.\n    :returns: A pandas DataFrame with an added column.\n    :raises ValueError: if attempting to add a column that already exists.\n    :raises ValueError: if `value` has more elements that number of\n        rows in the DataFrame.\n    :raises ValueError: if attempting to add an iterable of values with\n        a length not equal to the number of DataFrame rows.\n    :raises ValueError: if `value` has length of `0`.\n    \"\"\"\n    df = df.copy()\n    check(\"column_name\", column_name, [str])\n\n    if column_name in df.columns:\n        raise ValueError(\n            f\"Attempted to add column that already exists: \" f\"{column_name}.\"\n        )\n\n    nrows = df.shape[0]\n\n    if hasattr(value, \"__len__\") and not isinstance(\n        value, (str, bytes, bytearray)\n    ):\n        # if `value` is a list, ndarray, etc.\n        if len(value) > nrows:\n            raise ValueError(\n                \"`value` has more elements than number of rows \"\n                f\"in your `DataFrame`. vals: {len(value)}, \"\n                f\"df: {nrows}\"\n            )\n        if len(value) != nrows and not fill_remaining:\n            raise ValueError(\n                \"Attempted to add iterable of values with length\"\n                \" not equal to number of DataFrame rows\"\n            )\n\n        if len(value) == 0:\n            raise ValueError(\n                \"`value` has to be an iterable of minimum length 1\"\n            )\n        len_value = len(value)\n    elif fill_remaining:\n        # relevant if a scalar val was passed, yet fill_remaining == True\n        len_value = 1\n        value = [value]\n\n    nrows = df.shape[0]\n\n    if fill_remaining:\n        times_to_loop = int(np.ceil(nrows / len_value))\n\n        fill_values = list(value) * times_to_loop\n\n        df[column_name] = fill_values[:nrows]\n    else:\n        df[column_name] = value\n\n    return df\n\n\n@pf.register_dataframe_method\ndef add_columns(\n    df: pd.DataFrame, fill_remaining: bool = False, **kwargs\n) -> pd.DataFrame:\n    \"\"\"Add multiple columns to the dataframe.\n\n    This method does not mutate the original DataFrame.\n\n    Method to augment `add_column` with ability to add multiple columns in\n    one go. This replaces the need for multiple `add_column` calls.\n\n    Usage is through supplying kwargs where the key is the col name and the\n    values correspond to the values of the new DataFrame column.\n\n    Values passed can be scalar or iterable (list, ndarray, etc.)\n\n    Example: Inserting two more columns into a dataframe.\n\n        >>> import pandas as pd\n        >>> import janitor\n        >>> df = pd.DataFrame({\"a\": list(range(3)), \"b\": list(\"abc\")})\n        >>> df.add_columns(x=4, y=list(\"def\"))\n           a  b  x  y\n        0  0  a  4  d\n        1  1  b  4  e\n        2  2  c  4  f\n\n    :param df: A pandas dataframe.\n    :param fill_remaining: If value is a tuple or list that is smaller than\n        the number of rows in the DataFrame, repeat the list or tuple\n        (R-style) to the end of the DataFrame. (Passed to `add_column`)\n    :param kwargs: column, value pairs which are looped through in\n        `add_column` calls.\n    :returns: A pandas DataFrame with added columns.\n    \"\"\"\n    # Note: error checking can pretty much be handled in `add_column`\n\n    for col_name, values in kwargs.items():\n        df = df.add_column(col_name, values, fill_remaining=fill_remaining)\n\n    return df\n", "path": "janitor/functions/add_columns.py"}, {"content": "\"\"\"Implementation of `round_to_fraction`\"\"\"\nfrom typing import Hashable\n\nimport numpy as np\nimport pandas as pd\nimport pandas_flavor as pf\nfrom janitor.utils import check, check_column, deprecated_alias\n\n\n@pf.register_dataframe_method\n@deprecated_alias(col_name=\"column_name\")\ndef round_to_fraction(\n    df: pd.DataFrame,\n    column_name: Hashable,\n    denominator: float,\n    digits: float = np.inf,\n) -> pd.DataFrame:\n    \"\"\"Round all values in a column to a fraction.\n\n    This method mutates the original DataFrame.\n\n    Taken from [the R package](https://github.com/sfirke/janitor/issues/235).\n\n    Also, optionally round to a specified number of digits.\n\n    Example: Round numeric column to the nearest 1/4 value.\n\n        >>> import numpy as np\n        >>> import pandas as pd\n        >>> import janitor\n        >>> df = pd.DataFrame({\n        ...     \"a1\": [1.263, 2.499, np.nan],\n        ...     \"a2\": [\"x\", \"y\", \"z\"],\n        ... })\n        >>> df\n              a1 a2\n        0  1.263  x\n        1  2.499  y\n        2    NaN  z\n        >>> df.round_to_fraction(\"a1\", denominator=4)\n             a1 a2\n        0  1.25  x\n        1  2.50  y\n        2   NaN  z\n\n    :param df: A pandas DataFrame.\n    :param column_name: Name of column to round to fraction.\n    :param denominator: The denominator of the fraction for rounding. Must be\n        a positive number.\n    :param digits: The number of digits for rounding after rounding to the\n        fraction. Default is np.inf (i.e. no subsequent rounding).\n    :returns: A pandas DataFrame with a column's values rounded.\n    :raises ValueError: If `denominator` is not a positive number.\n    \"\"\"\n    check_column(df, column_name)\n    check(\"denominator\", denominator, [float, int])\n    check(\"digits\", digits, [float, int])\n\n    if denominator <= 0:\n        raise ValueError(\"denominator is expected to be a positive number.\")\n\n    df[column_name] = round(df[column_name] * denominator, 0) / denominator\n    if not np.isinf(digits):\n        df[column_name] = round(df[column_name], digits)\n\n    return df\n", "path": "janitor/functions/round_to_fraction.py"}]}