def compute_ffill_by_group(<EOL>df,<EOL>id_cols: List[str],<EOL>reference_cols: List[str],<EOL>value_col: str<EOL>):
check_params_columns_duplicate(id_cols + reference_cols + [value_col])<EOL>df = df.sort_values(by=id_cols + reference_cols)<EOL>df = df.set_index(id_cols)<EOL>df['<STR_LIT>'] = <NUM_LIT:1> - df[value_col].isnull().astype(int)<EOL>df['<STR_LIT>'] = df.groupby(<EOL>level=list(range(<NUM_LIT:0>, len(id_cols) - <NUM_LIT:1>))<EOL>)['<STR_LIT>'].cumsum()<EOL>df[value_col] = df[value_col].ffill()<EOL>df.loc[df['<STR_LIT>'] == <NUM_LIT:0>, value_col] = None<EOL>del df['<STR_LIT>']<EOL>return df.reset_index()<EOL>
Compute `ffill` with `groupby`
Dedicated method as there is a performance issue with a simple groupby/fillna (2017/07)
The method `ffill` propagates last valid value forward to next values.

---

### Parameters

*mandatory :*
- `id_cols` (*list of str*): names of columns used to create each group.
- `reference_cols` (*list of str*): names of columns used to sort.
- `value_col` (*str*): name of the columns to fill.

---

### Example

**Input**

name | rank | value
:------:|:--------------:|:--------:
A | 1 | 2
A | 2 | 5
A | 3 | null
B | 1 | null
B | 2 | 7

```cson
compute_ffill_by_group:
  id_cols: ['name']
  reference_cols: ['rank']
  value_col: 'value'
```

**Ouput**

name | rank | value
:------:|:--------------:|:--------:
A | 1 | 2
A | 2 | 5
A | 3 | 5
B | 1 | null
B | 2 | 7