schrodinger.seam.transforms.grouping module¶
- class schrodinger.seam.transforms.grouping.GroupIntoBins(bin_key_func: Callable[[V], float], bin_width: int)¶
Bases:
PTransformBins (key, value)’s into ((key, bin_index), [values]) tuples based on a given
bin_width.The “bin index” is calculated by 1) First passing the value into
bin_key_funto get a bin value, 2) Then, dividing the bin value by the bin width and rounding down to the nearest integer.- Parameters:
bin_key_func – A function that takes a value and returns a value to bin by. If not specified, the value itself is used.
bin_width – The width of each bin.
Example usage:
>>> import apache_beam as beam >>> from schrodinger.application.transforms.dock import Dock >>> from schrodinger.seam.io import chemio >>> from schrodinger.test import mmshare_data_file >>> with beam.Pipeline() as p: ... input_data = [('a', 1), ('a', 2), ('a', 6), ('b', 5), ('b', 9)] ... result = ( ... p ... | beam.Create(input_data) ... | GroupIntoBins(bin_key_func=lambda x: x, bin_width=3) ... | beam.Map(print)) (('a', 0), [1, 2]) (('a', 2), [6]) (('b', 1), [5]) (('b', 3), [9])
- __init__(bin_key_func: Callable[[V], float], bin_width: int)¶
- expand(pcoll: PCollection[Tuple[K, V]]) PCollection[Tuple[Tuple[K, int], Iterable[V]]]¶
- class schrodinger.seam.transforms.grouping.GroupIntoBinsByMemoryConfig(*, target_bin_bytes: float, bytes_func: Callable[[Any], float], key_func: Callable[[Any], Any], max_bin_count: Optional[int] = None, min_bin_count: int = 1)¶
Bases:
BaseModelValidated configuration for
GroupIntoBinsByMemory. See that transform for what each field means.- model_config: ClassVar[ConfigDict] = {'frozen': True}¶
Configuration for the model, should be a dictionary conforming to [
ConfigDict][pydantic.config.ConfigDict].
- target_bin_bytes: float¶
- bytes_func: Callable[[Any], float]¶
- key_func: Callable[[Any], Any]¶
- max_bin_count: Optional[int]¶
- min_bin_count: int¶
- class schrodinger.seam.transforms.grouping.GroupIntoBinsByMemory(*, _config: pydantic.main.BaseModel | None = None, **kwargs)¶
Bases:
PTransformWithConfigGroups (key, value) pairs into ((key, bin_index), [values]) based on an estimate of how much memory the values in a bin will need.
A bin is cut when the estimated memory of its values reaches
target_bin_bytes, so a bin holds many small values or few large ones, which keeps the memory needed to process one bin roughly constant regardless of how large the values are.max_bin_countadditionally caps the number of values in a bin. It is useful as a guard on how long a single bin takes to process, whichtarget_bin_bytesalone does not bound.min_bin_countis the floor: a bin holds at least that many values even if they overruntarget_bin_bytes, except for the last bin of a key group, which holds whatever values are left over. With the default of 1, a bin overruns the budget only when a single value exceeds it on its own, which no binning can avoid. A larger floor gives up that memory bound in exchange for bins big enough to be worth processing, so it should be set no higher than the available memory allows. Settingmin_bin_countequal tomax_bin_countgives fixed-size bins, ignoring the byte budget entirely.This transform: 1) Adds a random UUID to each value’s sort key to break ties 2) Extracts sort keys and sizes from all values 3) Sorts the extracted keys to compute bin boundaries 4) Assigns each value to a bin based on these boundaries
This approach avoids loading all values into memory for sorting - only the extracted keys and sizes need to be sorted, which is much more memory-efficient for large objects like Structure instances. The UUID also means that the limits are strictly enforced even when there are ties in
key_func.- Parameters:
target_bin_bytes – Estimated memory a bin’s values should add up to. This is a target rather than a cap, since
min_bin_countmay push a bin over it.bytes_func – A function that takes a value and returns its estimated memory in bytes.
key_func – A function that takes a value and returns a sortable key.
max_bin_count – Maximum number of values per bin, if any.
min_bin_count – Minimum number of values per bin.
Example usage:
>>> import apache_beam as beam >>> with beam.Pipeline() as p: ... # Each value is (energy, estimated_bytes). ... input_data = [ ... ('grp', (1.0, 40)), ... ('grp', (2.0, 40)), ... ('grp', (3.0, 30)), ... ('grp', (4.0, 150)), ... ] ... result = ( ... p ... | beam.Create(input_data) ... | GroupIntoBinsByMemory( ... target_bin_bytes=100, ... bytes_func=lambda x: x[1], ... key_func=lambda x: x[0]) ... | beam.Map(print)) (('grp', 0), [(1.0, 40), (2.0, 40)]) (('grp', 1), [(3.0, 30)]) (('grp', 2), [(4.0, 150)]) # oversized, so it overruns the budget
- config_class¶
alias of
GroupIntoBinsByMemoryConfig
- expand(pcoll)¶
- class schrodinger.seam.transforms.grouping.UnbinAndPartitionBoundaryValues(k: int, key_func: Optional[Callable[[V], float]] = None)¶
Bases:
PTransformUnbins and partitions the input into two pcollections of boundary and non-boundary values.
The boundary values are the first and last
kvalues in each bin after sorting. The non-boundary values are the rest of the values in each bin.Example usage:
>>> import apache_beam as beam >>> from schrodinger.seam.transforms.grouping import UnbinAndPartitionBoundaryValues >>> with beam.Pipeline() as p: ... bins = [ ... ('a', [1, 2, 3]) ... ] ... pcoll = p | beam.Create(bins) ... split = pcoll | UnbinAndPartitionBoundaryValues(k=1) ... _ = split.boundary_values | beam.Map(lambda x: print("Boundary", x)) ... _ = split.nonboundary_values | beam.Map(lambda x: print("NonBoundary", x)) Boundary ('a', 1) NonBoundary ('a', 2) Boundary ('a', 3)
- BOUNDARY_TAG = 'boundary_values'¶
- NON_BOUNDARY_TAG = 'nonboundary_values'¶
- __init__(k: int, key_func: Optional[Callable[[V], float]] = None)¶
- Parameters:
k – Used to define the first and last
kelements as boundary valueskey_func – Sorting key used to sort a list of values
- expand(pcoll)¶
- class schrodinger.seam.transforms.grouping.AssignNearestBinKey(bin_key_func: Callable[[V], float], bin_width: float)¶
Bases:
PTransformAssigns the nearest bin key to each element in the input PCollection.
The bin key is calculated by dividing the value by the bin width and rounding to the nearest integer.
- Parameters:
bin_key_func – A function that takes a value and returns a value to bin by. If not specified, the value itself is used.
bin_width – The width of each bin.
Example usage:
>>> import apache_beam as beam >>> from schrodinger.seam.transforms.grouping import AssignNearestBinKey >>> with beam.Pipeline() as p: ... input_data = [('a', 7), ('a', 12), ('a', 22), ('b', 4), ('b', 25)] ... result = ( ... p ... | beam.Create(input_data) ... | AssignNearestBinKey(bin_key_func=lambda x: x, bin_width=10) ... ) ... _ = result | beam.Map(print) (('a', 1), 7) (('a', 1), 12) (('a', 2), 22) (('b', 0), 4) (('b', 2), 25)
- __init__(bin_key_func: Callable[[V], float], bin_width: float)¶
- expand(pcoll: PCollection[Tuple[K, V]]) PCollection[Tuple[Tuple[K, int], V]]¶
- class schrodinger.seam.transforms.grouping.UnbinAndPartitionBoundaryValuesByMemoryConfig(*, target_boundary_bytes: float, bytes_func: ~typing.Callable[[~typing.Any], float], key_func: ~typing.Callable[[~typing.Any], ~typing.Any] = <function UnbinAndPartitionBoundaryValuesByMemoryConfig.<lambda>>, max_boundary_count: ~typing.Optional[int] = None, min_boundary_count: int = 1)¶
Bases:
BaseModelValidated configuration for
UnbinAndPartitionBoundaryValuesByMemory. See that transform for what each field means.- model_config: ClassVar[ConfigDict] = {'frozen': True}¶
Configuration for the model, should be a dictionary conforming to [
ConfigDict][pydantic.config.ConfigDict].
- target_boundary_bytes: float¶
- bytes_func: Callable[[Any], float]¶
- key_func: Callable[[Any], Any]¶
- max_boundary_count: Optional[int]¶
- min_boundary_count: int¶
- class schrodinger.seam.transforms.grouping.UnbinAndPartitionBoundaryValuesByMemory(*, _config: pydantic.main.BaseModel | None = None, **kwargs)¶
Bases:
PTransformWithConfigUnbins and partitions the input into boundary and non-boundary values, sizing each boundary by the estimated memory of its values.
Each bin’s values are sorted by
key_func, and its lowest and highest values become boundary values. Indices are remapped so that bins and boundaries never share one:bin N, sorted: [ low boundary | middle | high boundary ] output index: 2N 2N + 1 2N + 2
so boundary index 2N + 2 collects the high boundary of bin N and the low boundary of bin N + 1. Boundary values go to
boundary_valuesand middle values tononboundary_values.A boundary takes values until
target_boundary_bytesormax_boundary_countwould be exceeded, but always at leastmin_boundary_count. When a bin’s two boundaries would overlap, the overlapping values go only to the low boundary, so a bin that small sends nothing to index 2N + 2 (see DESMOND-17832).- Parameters:
target_boundary_bytes – Estimated memory one boundary’s values should add up to; a boundary index collects two boundaries. This is a target rather than a cap, since
min_boundary_countmay push a boundary over it.bytes_func – A function that takes a value and returns its estimated memory in bytes.
key_func – Sorting key used to sort values within each bin.
max_boundary_count – Maximum number of values at one boundary, if any.
min_boundary_count – Minimum number of values at one boundary.
Example usage:
>>> import apache_beam as beam >>> with beam.Pipeline() as p: ... # Each value is (energy, estimated_bytes). ... bins = [ ... (('a', 0), [(1.0, 30), (2.0, 30), (3.0, 30), (4.0, 30)]), ... ] ... pcoll = p | beam.Create(bins) ... split = pcoll | UnbinAndPartitionBoundaryValuesByMemory( ... target_boundary_bytes=60, ... bytes_func=lambda x: x[1], ... key_func=lambda x: x[0]) ... _ = split.boundary_values | beam.Map(lambda x: print("Boundary", x)) ... _ = split.nonboundary_values | beam.Map(lambda x: print("NonBoundary", x)) Boundary (('a', 0), (1.0, 30)) Boundary (('a', 0), (2.0, 30)) Boundary (('a', 2), (3.0, 30)) Boundary (('a', 2), (4.0, 30))
- BOUNDARY_TAG = 'boundary_values'¶
- NON_BOUNDARY_TAG = 'nonboundary_values'¶
- config_class¶
- expand(pcoll)¶