Source code for galactic.filters
# there are 2 types of filter: stateless filter that can operate on only a single example,
# or a stateful filter (e.g. Bloom filter) where examples depend on each other.
import re
import json
import pybloom_live
from typing import Sequence
import logging
logger = logging.getLogger("galactic")
[docs]def apply_bloom_filter(self, fields: Sequence[str], inplace: bool = True):
"""
Applies a Bloom filter to the dataset to filter out duplicate examples based on the specified fields.
.. code-block:: python
# Example usage:
ds.apply_bloom_filter(fields=['field1', 'field2'], inplace=False)
:param fields: Sequence of field names used to apply the Bloom filter.
:param inplace: Whether to apply the filter in-place or return a new object. Defaults to True.
:return: If inplace is False, returns a new object of the same type with the filtered dataset.
:rtype: type(self) if not inplace else None
"""
bloom = pybloom_live.BloomFilter(
capacity=len(self.dataset)
if len(self.dataset) < int(1.0e9)
else int(1.0e9),
error_rate=0.001,
)
def bloom_filter(sample):
key = json.dumps({field: sample[field] for field in fields})
if key in bloom:
return False
else:
bloom.add(key)
return True
if inplace:
self.dataset = self.dataset.filter(bloom_filter)
logger.info(
f"Filtered dataset in-place with Bloom filter on fields: {fields}"
)
# return self for chaining
return self
else:
new_dataset = self.dataset.filter(bloom_filter)
logger.info(f"Filtered dataset with Bloom filter on fields: {fields}")
return type(self)(
new_dataset,
model=self.model,
emb_matrix=self.emb_matrix,
cluster_ids=self.cluster_ids,
cluster_centers=self.cluster_centers,
openai_api_key=self.openai_api_key,
)
# these filters are methods to attach to the GalacticDataset class.
# each filter takes a list of fields which the filter will be (separately) applied to.
[docs]def filter_string(
self, fields: Sequence[str], values: Sequence[str], inplace: bool = True
):
"""
Filters the dataset by removing examples that contain any of the specified strings in the specified fields.
.. code-block:: python
# Example usage:
ds.filter_string(fields=['field1', 'field2'], values=['value1', 'value2'], inplace=False)
:param fields: Sequence of field names to apply the filter on.
:param values: Sequence of string values to filter out from the specified fields.
:param inplace: Whether to apply the filter in-place or return a new object. Defaults to True.
:return: If inplace is False, returns a new object of the same type with the filtered dataset.
:rtype: type(self) if not inplace else None
"""
# make a regexp that matches any of the fields
regexp = re.compile("|".join([re.escape(val) for val in values]))
def filter_(sample):
for field in fields:
if field in sample:
if isinstance(sample[field], str):
if regexp.search(sample[field]):
return False
else:
if regexp.search(str(sample[field])):
return False
return True
if inplace:
self.dataset = self.dataset.filter(filter_)
logger.info(
f"Filtered dataset in-place with exact string matching on fields: {fields}"
)
# return self for chaining
return self
else:
new_dataset = self.dataset.filter(filter_)
logger.info(
f"Filtered dataset with exact string matching on fields: {fields}"
)
return type(self)(
new_dataset,
model=self.model,
emb_matrix=self.emb_matrix,
cluster_ids=self.cluster_ids,
cluster_centers=self.cluster_centers,
openai_api_key=self.openai_api_key,
)
[docs]def filter_regex(
self, fields: Sequence[str], regex: str, inplace: bool = True
):
"""
Filters the dataset by removing examples that match the specified regex pattern in the specified fields.
.. code-block:: python
# Example usage:
ds.filter_regex(fields=['field1', 'field2'], regex='[0-9]+', inplace=False)
:param fields: Sequence of field names to apply the regex filter on.
:param regex: The regex pattern used to filter out matching examples from the specified fields.
:param inplace: Whether to apply the filter in-place or return a new object. Defaults to True.
:return: If inplace is False, returns a new object of the same type with the filtered dataset.
:rtype: type(self) if not inplace else None
"""
# make a regexp that matches any of the fields
regexp = re.compile(regex)
def filter_(sample):
for field in fields:
if field in sample:
if isinstance(sample[field], str):
if regexp.search(sample[field]):
return False
else:
if regexp.search(str(sample[field])):
return False
return True
if inplace:
self.dataset = self.dataset.filter(filter_)
logger.info(
f"Filtered dataset in-place with regex matching on fields: {fields}"
)
# return self for chaining
return self
else:
new_dataset = self.dataset.filter(filter_)
logger.info(
f"Filtered dataset with regex matching on fields: {fields}"
)
return type(self)(
new_dataset,
model=self.model,
emb_matrix=self.emb_matrix,
cluster_ids=self.cluster_ids,
cluster_centers=self.cluster_centers,
openai_api_key=self.openai_api_key,
)