Skip to content

Param

Creates a model parameter, i.e. an Expression that doesn't involve any variables.

A Parameter can be created from a DataFrame, CSV file, Parquet file, data dictionary, or a Pandas Series.

Param is a function, not a class

Technically, Param(data) is a function that returns an Expression, not a class. However, for consistency with other modeling frameworks, we provide it as a class-like function (i.e. an uppercase function).

Smart naming

If a Param is not given a name (i.e. if it is not assigned to a model: m.my_name = Param(...)), then its name is inferred from the name of the column in data that contains the parameter values. This makes debugging models with inline parameters easier.

Parameters:

Name Type Description Default
data DataFrame | DataFrame | Series | dict | str | Path

The data to use for the parameter.

If data is a polars or pandas DataFrame, the last column will be treated as the values of the parameter, and all other columns as labels.

If data is a string or Path, it will be interpreted as a path to a CSV or Parquet file that will be read and used as a DataFrame. The file extension must be .csv or .parquet.

If data is a pandas.Series, the index(es) will be treated as columns for labels and the series values as the parameter values.

If data is of any other type (e.g. a dictionary), it will be used as if you had called Param(pl.DataFrame(data)).

required

Returns:

Type Description
Expression

An Expression representing the parameter.

Examples:

>>> m = pf.Model()
>>> m.fixed_cost = pf.Param({"plant": ["A", "B"], "cost": [1000, 1500]})
>>> m.fixed_cost
<Expression (parameter) height=2 terms=2>
┌───────┬────────────┐
│ plant ┆ expression │
│ (2)   ┆            │
╞═══════╪════════════╡
│ A     ┆ 1000       │
│ B     ┆ 1500       │
└───────┴────────────┘

Since Param simply returns an Expression, you can use it in building larger expressions as usual:

>>> m.variable_cost = pf.Param(
...     pl.DataFrame({"plant": ["A", "B"], "cost": [50, 60]})
... )
>>> m.total_cost = m.fixed_cost + m.variable_cost
>>> m.total_cost
<Expression (parameter) height=2 terms=2>
┌───────┬────────────┐
│ plant ┆ expression │
│ (2)   ┆            │
╞═══════╪════════════╡
│ A     ┆ 1050       │
│ B     ┆ 1560       │
└───────┴────────────┘
Source code in pyoframe/_param.py
def Param(
    data: pl.DataFrame | pd.DataFrame | pd.Series | dict | str | Path,
) -> Expression:
    """Creates a model parameter, i.e. an [Expression][pyoframe.Expression] that doesn't involve any variables.

    A Parameter can be created from a DataFrame, CSV file, Parquet file, data dictionary, or a Pandas Series.

    !!! info "`Param` is a function, not a class"
        Technically, `Param(data)` is a function that returns an [Expression][pyoframe.Expression], not a class.
        However, for consistency with other modeling frameworks, we provide it as a class-like function (i.e. an uppercase function).

    !!! tip "Smart naming"
        If a Param is not given a name (i.e. if it is not assigned to a model: `m.my_name = Param(...)`),
        then its [name][pyoframe._model_element.BaseBlock.name] is inferred from the name of the column in `data` that contains the parameter values.
        This makes debugging models with inline parameters easier.

    Args:
        data: The data to use for the parameter.

            If `data` is a polars or pandas `DataFrame`, the last column will be treated as the values of the parameter, and all other columns as labels.

            If `data` is a string or `Path`, it will be interpreted as a path to a CSV or Parquet file that will be read and used as a `DataFrame`. The file extension must be `.csv` or `.parquet`.

            If `data` is a `pandas.Series`, the index(es) will be treated as columns for labels and the series values as the parameter values.

            If `data` is of any other type (e.g. a dictionary), it will be used as if you had called `Param(pl.DataFrame(data))`.

    Returns:
        An Expression representing the parameter.

    Examples:
        >>> m = pf.Model()
        >>> m.fixed_cost = pf.Param({"plant": ["A", "B"], "cost": [1000, 1500]})
        >>> m.fixed_cost
        <Expression (parameter) height=2 terms=2>
        ┌───────┬────────────┐
        │ plant ┆ expression │
        │ (2)   ┆            │
        ╞═══════╪════════════╡
        │ A     ┆ 1000       │
        │ B     ┆ 1500       │
        └───────┴────────────┘

        Since `Param` simply returns an Expression, you can use it in building larger expressions as usual:

        >>> m.variable_cost = pf.Param(
        ...     pl.DataFrame({"plant": ["A", "B"], "cost": [50, 60]})
        ... )
        >>> m.total_cost = m.fixed_cost + m.variable_cost
        >>> m.total_cost
        <Expression (parameter) height=2 terms=2>
        ┌───────┬────────────┐
        │ plant ┆ expression │
        │ (2)   ┆            │
        ╞═══════╪════════════╡
        │ A     ┆ 1050       │
        │ B     ┆ 1560       │
        └───────┴────────────┘
    """
    if isinstance(data, pd.Series):
        data = data.to_frame().reset_index()
    if isinstance(data, pd.DataFrame):
        data = pl.from_pandas(data)

    if isinstance(data, (str, Path)):
        data = Path(data)
        if data.suffix.lower() == ".csv":
            data = pl.read_csv(data)
        elif data.suffix.lower() in {".parquet"}:
            data = pl.read_parquet(data)
        else:
            raise NotImplementedError(
                f"Could not create parameter. Unsupported file format: {data.suffix}"
            )

    if not isinstance(data, pl.DataFrame):
        data = pl.DataFrame(data)

    value_col = data.columns[-1]

    return Expression(
        data.rename({value_col: COEF_KEY})
        .drop_nulls(COEF_KEY)
        .with_columns(pl.lit(CONST_TERM).alias(VAR_KEY)),
        name=value_col,
    )