Refactor sampling component from ObservationRecipe into SampleBuilder#334
Refactor sampling component from ObservationRecipe into SampleBuilder#334ph-kev wants to merge 4 commits into
Conversation
| ClimaCalibrateClimaAnalysisExt.SampleCollection | ||
| ClimaCalibrate.SampleBuilder.generate_samples | ||
| ClimaCalibrate.SampleBuilder.generate_samples_by_times | ||
| ClimaCalibrate.SampleBuilder.num_samples | ||
| ClimaCalibrate.SampleBuilder.reconstruct_col | ||
| ClimaCalibrateClimaAnalysisExt.ObservedSampleCollection |
There was a problem hiding this comment.
I don't like the names SampleCollection and ObservedSampleCollection and I think there are probably better names for these two structs. I am against names that include the word "matrix" in them since the structs don't implement the AbstractArray interface.
There was a problem hiding this comment.
How about StackedSamples or FlatStackedOutputVars. as a couple more options... for samples collection
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #334 +/- ##
==========================================
+ Coverage 60.64% 61.06% +0.42%
==========================================
Files 18 19 +1
Lines 1466 1482 +16
==========================================
+ Hits 889 905 +16
Misses 577 577 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
2018b80 to
96dd683
Compare
| You can exclude dimensions from these checks with the `ignore_dims` keyword | ||
| argument. This is useful when the samples are meant to differ along a dimension. |
There was a problem hiding this comment.
This feature might be needed for the GEnsembleBuilder but it is not needed right now.
nefrathenrici
left a comment
There was a problem hiding this comment.
Thank you, covariance and observation are much cleaner now!
| `ObservationRecipe.covariance` now take an `ObservedSampleCollection` (e.g | ||
| `observation(covar_estimator, osc)`) instead of | ||
| `(covar_estimator, vars, start_date, end_date)`. The `dims` keyword (flatten | ||
| order) is moved to `SampleBuilder.generate_samples`. |
odunbar
left a comment
There was a problem hiding this comment.
Hi @ph-kev This is great.
I have a few comments - that I would be keen to discus.
- Do we need a separate module for Samples builder?
- I'm not sure if we actually need a separate object for ObservaionCollection, is this actually useful? Or should it just be another argument in
observation(...) - I think the docs, and possibly the internal storage too, should separate between a "vector of (stacked-) vectors" and a matrix. As it seems we end up with needing lots of matrix return methods to interrogate the samples collection objects despite them fundamentally not being a matrix any more.
| machine learning algorithms, observations are represented as a vector of numbers | ||
| along with a covariance matrix describing the uncertainty of the observation. | ||
| However, the diagnostics of climate models are typically in the form of gridded | ||
| fields with named dimensions such as latitude, longitude, and time. |
There was a problem hiding this comment.
I think maybe it would be more helpful to say "On the other hand, diagnostics from ClimaAnalysis are stored as "OutputVars", which store them as e.g. ...(be more explicit)
| However, the diagnostics of climate models are typically in the form of gridded | ||
| fields with named dimensions such as latitude, longitude, and time. | ||
|
|
||
| The `SampleBuilder` module bridges this gap. It flattens one or more |
There was a problem hiding this comment.
"...to bridge this gap, three operations need to be performed.
- we flatten each
OutputVarinto a vector, and store information for the flattening/unflattening operation. This is implemented bySamplesBuilder.build_samplesconstructing aSampleBuilder.SampleCollection. - we construct the associated covariance matrix for the flattened samples. This is typically prescribed or estimated from the flattened samples. This is dispatched by defining
<: ObservationRecipe.AbstractCovarianceEstimatortypes - we combine these in an
EKP.Observation. Implemented by theObservationRecipe.observation"
| metadata and packages the result as a [`SampleCollection`](@ref | ||
| ClimaCalibrateClimaAnalysisExt.SampleCollection). From that matrix you pick one | ||
| column as the true observation to create an [`ObservedSampleCollection`](@ref | ||
| ClimaCalibrateClimaAnalysisExt.ObservedSampleCollection). The |
There was a problem hiding this comment.
The ObservedSampleCollection feels a bit cumbersome, i can't see why it is necessary to have this as an actual object. What you choose to take as an observation is a property of the experiment, not a property of the samples. For example, would it not feel more natural for this to be passed in as a third argument to ObsRecipe.observation?
i'm also thinking about things like how would minibatching fit into your framework here?
|
|
||
| ```math | ||
| \begin{pmatrix} | ||
| \mathrm{OV}_{11} & \cdots & \mathrm{OV}_{1m} \\ |
There was a problem hiding this comment.
I'd use V for the OutputVar not "OV" as in mathmode this looks like a product of two variables. also the "math" term for flatten is vec. e.g.
There was a problem hiding this comment.
I am a bit hung up on the the matrix idea. Would it be correct in thinking that really this is basically just a guard to ensure that the user provides a sample of each variable? If so, when presenting the math and describing the structure we should use maybe the following notations:
This clearly indicates n variable types and m samples of these variables. Removing the ambiguity of the dimensions, and highlighting why we would have a "matrix" of OutputVars in the first place.
| ClimaCalibrateClimaAnalysisExt.SampleCollection | ||
| ClimaCalibrate.SampleBuilder.generate_samples | ||
| ClimaCalibrate.SampleBuilder.generate_samples_by_times | ||
| ClimaCalibrate.SampleBuilder.num_samples | ||
| ClimaCalibrate.SampleBuilder.reconstruct_col | ||
| ClimaCalibrateClimaAnalysisExt.ObservedSampleCollection |
There was a problem hiding this comment.
How about StackedSamples or FlatStackedOutputVars. as a couple more options... for samples collection
| There are also getter functions such as [`get_obs`](@ref) for getting the | ||
| observation for the calibration, [`get_obs_metadata`](@ref) for getting the | ||
| metadata of the observation, [`get_samples`](@ref) for getting the matrix of | ||
| samples, [`get_metadata`](@ref) for getting the matrix of metadata. |
There was a problem hiding this comment.
It feels like really when dealing with the SamplesCollection objects we want to only get information about a sample or set of samples, (e.g. get a sample, get the metadata for the stacked sample etc.). But as we store it internally as a matrix - it leads to the need to do column indexing and return of matrix values. Would it not be cleaner to store internally as a vector of (stacked-) vectors?
closes #328 - This PR refactors the sampling part from
ObservationRecipeintoSampleBuilder.All relevant functions in
ObservationRecipetakes in aObservedSampleCollectionwhich does all the checks of theOutputVars. This eliminates most of the checks fromObservationRecipeand move them toSampleBuilder.The
SampleBuildermodule features aSampleCollectionstruct and anObservedSampleCollectionstruct. ASampleCollectionstruct features a matrix of samples and its associated metadata and anObservedSampleCollectionstruct also includes which sample will be the observation in the calibration. These two structs are separated to allow for future changes to how the observation is chosen without breaking changes.For the future, we might be interested in including
NaNs in the matrix of samples and lettingObservationRecipe.observationhandle theNaNs. In addition, we might also wanthcatandvcatto be define forObservedSampleCollectionto allow for more flexibility in constructing this object.TODO