Repository: microsoft/qlib
File: qlib/utils/resam.py (Python)

Code before:
            return method_func(feature, **method_kwargs)
        elif isinstance(method, str):
            return getattr(feature, method)(**method_kwargs)
    return feature


def get_valid_value(series, last=True):
    """get the first/last not nan value of pd.Series with single level index
    Parameters
    ----------
    series : pd.Seires
        series should not be empty
    last : bool, optional
        wether to get the last valid value, by default True
        - if last is True, get the last valid value
        - else, get the first valid value

    Returns
    -------
    Nan | float
        the first/last valid value
    """
    return series.fillna(method="ffill").iloc[-1] if last else series.fillna(method="bfill").iloc[0]


def ts_data_last(ts_feature):
    """get the last not nan value of pd.Series|DataFrame with single level index"""
    if isinstance(ts_feature, pd.DataFrame):
        return ts_feature.apply(lambda column: get_valid_value(column, last=True))
    elif isinstance(ts_feature, pd.Series):
        return get_valid_value(ts_feature, last=True)
    else:
        raise TypeError(f"ts_feature should be pd.DataFrame/Series, not {type(ts_feature)}")


def ts_data_first(ts_feature):
    """get the first not nan value of pd.Series|DataFrame with single level index"""
    if isinstance(ts_feature, pd.DataFrame):
        return ts_feature.apply(lambda column: get_valid_value(column, last=False))
    elif isinstance(ts_feature, pd.Series):
        return get_valid_value(ts_feature, last=False)
    else:
        raise TypeError(f"ts_feature should be pd.DataFrame/Series, not {type(ts_feature)}")


Review comment (suggestion):
These two functions could be merged

```python
from functools import partial

def _ts_data(ts_feature, last=False):
    """get the first/last not nan value of pd.Series|DataFrame with single level index"""
    if isinstance(ts_feature, pd.DataFrame):
        return ts_feature.apply(lambda column: get_valid_value(column, last=last))
    elif isinstance(ts_feature, pd.Series):
        return get_valid_value(ts_feature, last=last)
    else:
        raise TypeError(f"ts_feature should be pd.DataFrame/Series, not {type(ts_feature)}")

ts_data_last = partial(_ts_data, last=False)
ts_data_first = partial(_ts_data, last=True)
```

Code after:
        if callable(method):
            method_func = method
            return method_func(feature, **method_kwargs)
        elif isinstance(method, str):
            return getattr(feature, method)(**method_kwargs)
    return feature


def get_valid_value(series, last=True):
    """get the first/last not nan value of pd.Series with single level index
    Parameters
    ----------
    series : pd.Seires
        series should not be empty
    last : bool, optional
        wether to get the last valid value, by default True
        - if last is True, get the last valid value
        - else, get the first valid value

    Returns
    -------
    Nan | float
        the first/last valid value
    """
    return series.fillna(method="ffill").iloc[-1] if last else series.fillna(method="bfill").iloc[0]


def _ts_data_valid(ts_feature, last=False):
    """get the first/last not nan value of pd.Series|DataFrame with single level index"""
    if isinstance(ts_feature, pd.DataFrame):
        return ts_feature.apply(lambda column: get_valid_value(column, last=last))
    elif isinstance(ts_feature, pd.Series):
        return get_valid_value(ts_feature, last=last)
    else:
        raise TypeError(f"ts_feature should be pd.DataFrame/Series, not {type(ts_feature)}")


ts_data_last = partial(_ts_data_valid, last=False)
ts_data_first = partial(_ts_data_valid, last=True)