Performing a Combination
Contents
Performing a Combination¶
We’ll demonstrate how a combination works by combining everything we’ve learned so far.
Loading the Workspace¶
To do so, we’ll use a simple workspace to demonstrate functionality of combinations.
import json
import pyhf
with open("data/2-bin_1-channel.json") as serialized:
spec = json.load(serialized)
workspace = pyhf.Workspace(spec)
Combine Workspaces¶
Let’s just try to combine naively right now.
pyhf.Workspace.combine(workspace, workspace)
---------------------------------------------------------------------------
InvalidWorkspaceOperation Traceback (most recent call last)
Input In [3], in <cell line: 1>()
----> 1 pyhf.Workspace.combine(workspace, workspace)
File /__t/Python/3.9.13/x64/lib/python3.9/site-packages/pyhf/workspace.py:728, in Workspace.combine(cls, left, right, join, merge_channels)
723 log.warning(
724 "You are using an unsafe join operation. This will silence exceptions that might be raised during a normal 'outer' operation."
725 )
727 new_version = _join_versions(join, left['version'], right['version'])
--> 728 new_channels = _join_channels(
729 join, left['channels'], right['channels'], merge=merge_channels
730 )
731 new_observations = _join_observations(
732 join, left['observations'], right['observations']
733 )
734 new_measurements = _join_measurements(
735 join, left['measurements'], right['measurements']
736 )
File /__t/Python/3.9.13/x64/lib/python3.9/site-packages/pyhf/workspace.py:125, in _join_channels(join, left_channels, right_channels, merge)
121 common_channels = {c['name'] for c in left_channels}.intersection(
122 c['name'] for c in right_channels
123 )
124 if common_channels:
--> 125 raise exceptions.InvalidWorkspaceOperation(
126 f"Workspaces cannot have any channels in common with the same name: {common_channels}. You can also try a different join operation: {Workspace.valid_joins}."
127 )
129 elif join == 'outer':
130 counted_channels = collections.Counter(
131 channel['name'] for channel in joined_channels
132 )
InvalidWorkspaceOperation: Workspaces cannot have any channels in common with the same name: {'singlechannel'}. You can also try a different join operation: ['none', 'outer', 'left outer', 'right outer'].
As we can see, we can’t just combine a workspace with itself if it has some channel names in common. We try very hard in pyhf
to make sure a combination “makes sense”.
Let’s go ahead and rename the channel (as well as the measurement). Then try to combine.
other_workspace = workspace.rename(
channels={"singlechannel": "othersinglechannel"},
modifiers={"uncorr_bkguncrt": "otheruncorr_bkguncrt"},
measurements={"Measurement": "OtherMeasurement"},
)
combined_workspace = pyhf.Workspace.combine(workspace, other_workspace)
And did we combine?
print(f" channels: {combined_workspace.channels}")
print(f" nbins: {combined_workspace.channel_nbins}")
print(f" samples: {combined_workspace.samples}")
print(f" modifiers: {combined_workspace.modifiers}")
print(f" parameters: {combined_workspace.parameters}")
print(f"measurements: {combined_workspace.measurement_names}")
channels: ['othersinglechannel', 'singlechannel']
nbins: {'othersinglechannel': 2, 'singlechannel': 2}
samples: ['background', 'signal']
modifiers: [('mu', 'normfactor'), ('otheruncorr_bkguncrt', 'shapesys'), ('uncorr_bkguncrt', 'shapesys')]
parameters: ['mu', 'otheruncorr_bkguncrt', 'uncorr_bkguncrt']
measurements: ['Measurement', 'OtherMeasurement']
Indeed. And at this point, we can just use all the same functionality we expect of pyhf, such as performing a fit:
model = workspace.model()
data = workspace.data(model)
test_poi = 1.0
pyhf.infer.hypotest(test_poi, data, model, test_stat="qtilde")
array(0.49567314)
other_model = other_workspace.model()
other_data = other_workspace.data(other_model)
pyhf.infer.hypotest(test_poi, other_data, other_model, test_stat="qtilde")
array(0.49567314)
combined_model = combined_workspace.model()
combined_data = combined_workspace.data(combined_model)
pyhf.infer.hypotest(test_poi, combined_data, combined_model, test_stat="qtilde")
multiple measurements defined. Taking the first measurement.
array(0.37128219)