# GroupBy#

“Group by” refers to an implementation of the “split-apply-combine” approach known from pandas and xarray. Scipp currently supports only a limited number of operations that can be applied.

## Grouping based on label values#

Suppose we have measured data for a number of parameter values, potentially repeating measurements with the same parameter multiple times:

[1]:

import numpy as np
import scipp as sc

np.random.seed(0)

[2]:

param = sc.Variable(dims=['x'], values=[1,3,1,1,5,3])
values = sc.Variable(dims=['x', 'y'], values=np.random.rand(6,16))
values += 1.0 + param


If we store this data as a data array we obtain the following plot:

[3]:

data = sc.DataArray(
values,
coords={
'x': sc.Variable(dims=['x'], values=np.arange(6)),
'y': sc.Variable(dims=['y'], values=np.arange(16))
})
sc.plot(data)

[3]:


Note that we chose the “measured” values such that the three distinct values of the underlying parameter are visible. We can now use the split-apply-combine mechanism to transform our data into a more useful representation. We start by storing the parameter values (or any value to be used for grouping) as a non-dimension coordinate:

[4]:

data.coords['param'] = param


Next, we call scipp.groupby to split the data and call mean on each of the groups:

[5]:

grouped = sc.groupby(data, group='param').mean('x')
sc.plot(grouped)

[5]:


Apart from mean, groupby also supports sum, concat, and more. See GroupByDataArray and GroupByDataset for a full list.

## Grouping based on binned label values#

Grouping based on non-dimension coordinate values (also known as labels) is most useful when labels are strings or integers. If labels are floating-point values or cover a wide range, it is more convenient to group values into bins, i.e., all values within certain bounds are mapped into the same group. We modify the above example to use a contiuously-valued parameter:

[6]:

param = sc.Variable(dims=['x'], values=np.random.rand(16))
values = sc.Variable(dims=['x', 'y'], values=np.random.rand(16,16))
values += 1.0 + 5.0*param

[7]:

data = sc.DataArray(
values,
coords={
'x': sc.Variable(dims=['x'], values=np.arange(16)),
'y': sc.Variable(dims=['y'], values=np.arange(16))
})
sc.plot(data)

[7]:


We create a variable defining the desired binning:

[8]:

bins = sc.Variable(dims=["z"], values=np.linspace(0.0, 1.0, 10))


As before, we can now use groupby and mean to transform the data:

[9]:

data.coords['param'] = param
grouped = sc.groupby(data, group='param', bins=bins).mean('x')
sc.plot(grouped)

[9]:


The values in the white rows are NaN. This is the result of empty bins, which do not have a meaningful mean value.

Alternatively, grouping can be done based on groups defined as Variables rather than strings. This, however, requires bins to be specified, since bins define the new dimension label.

[10]:

grouped = sc.groupby(data, group=param, bins=bins).mean('x') # note the lack of quotes around param!
sc.plot(grouped)

[10]: