Hey is this something you'd like to add to the library ?
Rationale
Bookeeping which examples have been labeled is no fun and error prone and verbose. I propose a "Manager" class that will do it for us, so that labeling looks like this:
User Experience
forindexinrange(10):
query_index, query_instance=learner.query(manager.unlabeld)
ix=query_index[0]
print(manager.remaining_sources[ix])
label= (ix,int(input()))
manager.add_labels(label)
In a notebook it works like this:

Idea
The idea is that the manager maintains masks for the labeled and unlabeled indices, and calculates offsets when adding new labels. End user shouldnt care about this stuff, and they can get the unlabeled examples from manager.unlabeled which is a view on the array.
This is some mock code, I haven't tested it properly yet
importtypingfromtypingimportList,Tuple,Any,UnionimportnumpyasnpLabel=Tuple[int, Any]
LabelList=List[Label]
Sources=List[Any]
classALManager():
def__init__(self, features:np.ndarray, labels:LabelList=None, sources:Sources=None):
''' :param features: An array of the features that will be used for AL. :param labels: Any prexesiting labels. Each label is a tuple(idx,label) :param source: A list of the original data '''iflabelsisNone:
labels= []
self.features=featuresiflabelsisNone:
self.labels= []
self.labels=labelsself.labeled_mask=np.zeros(self.features.shape[0],dtype=bool)
self.unlabeled_mask=np.ones(self.features.shape[0],dtype=bool)
self._update_masks(self.labels)
self.sources=np.array(sourcesifsourceselse [])
def_update_masks(self,labels:Union[LabelList,Label]):
forlabelinlabels:
self.labeled_mask[label[0]] =Trueself.unlabeled_mask[label[0]] =Falsedef_offset_new_labes(self,labels:LabelList):
iflen(self.labels)==0:
# Nothing to correct in this casereturnlabelscorrectLabels: LabelList= []
labeledIndices=self.labeled_mask.nonzero()[0]
forlabelinlabels:
#The argmax trick on a bool condition returns the index of the first labeled item which came before the new onenewLabel :Label= (np.argmax(labeledIndices<=label[0])+1+label[0],label[1])
correctLabels.append(newLabel)
returncorrectLabelsdefadd_labels(self, labels:LabelList):
ifisinstance(labels,tuple): # if this is a single examplelabels :LabelList= [labels]
elifisinstance(labels,list):
passelse:
raiseException("Malformed input. Please add either a tuple (ix,label) or a list [(ix,label),..]")
labels=self._offset_new_labes(labels)
self._update_masks(labels)
self.labels+=(labels)
@propertydefunlabeld(self):
''' :return: A view (in the numpy sense) of the features restricted to those that aren't labeled '''returnself.features[self.unlabeled_mask]
@propertydeflabeled(self):
''' :return: A view (in the numpy sense) of the features restricted to those that aren't labeled '''returnself.features[self.labeled_mask]
@propertydefremaining_sources(self):
''' :return: The original inputs, masked so that only unlabeled ones are returned '''returnself.sources[self.unlabeled_mask]
Hey is this something you'd like to add to the library ?
Rationale
Bookeeping which examples have been labeled is no fun and error prone and verbose. I propose a "Manager" class that will do it for us, so that labeling looks like this:
User Experience
In a notebook it works like this:

Idea
The idea is that the manager maintains masks for the labeled and unlabeled indices, and calculates offsets when adding new labels. End user shouldnt care about this stuff, and they can get the unlabeled examples from manager.unlabeled which is a view on the array.
This is some mock code, I haven't tested it properly yet