class_docstr: Data manager for sampling data, use reservoir sampling.
      
docstr: Add an scalar item to bucket, replacing an old item with probability.
  
  Use reservoir sampling to add a new item to sampling bucket,
  each item in a steam has same probability stay in the bucket.
  
  use _last_special mark to improve performance when data is monotonous
  
  Args:
      item: The item to add to reservoir bucket.
docstr_tok: ["Add","an","scalar","item","to","bucket",",","replacing","an","old","item","with","probability",".","Use","reservoir","sampling","to","add","a","new","item","to","sampling","bucket",",","each","item","in","a","steam","has","same","probability","stay","in","the","bucket",".","use","_last_special","mark","to","improve","performance","when","data","is","monotonous","Args",":","item",":","The","item","to","add","to","reservoir","bucket","."]
code: def add_scalar_item(self, item):
      """Add an scalar item to bucket, replacing an old item with probability.
  
      Use reservoir sampling to add a new item to sampling bucket,
      each item in a steam has same probability stay in the bucket.
  
      use _last_special mark to improve performance when data is monotonous
  
      Args:
          item: The item to add to reservoir bucket.
      """
      with self._mutex:
          # save max and min value
          if not self.max_scalar or self.max_scalar.value < item.value:
              self.max_scalar = item
          if not self.min_scalar or self.min_scalar.value > item.value:
              self.min_scalar = item
  
          if len(self._items) < self._max_size or self._max_size == 0:
              # capacity is valid, append directly
              self._items.append(item)
          else:
              if self._last_special:
                  if (
                      self._items[-1].id == self.min_scalar.id
                      or self._items[-1].id == self.max_scalar.id
                  ):
                      # data is not monotonous, set special to False
                      self._last_special = False
                  else:
                      # data is monotonous, drop last item by reservoir algorithm
                      r = self._random.randint(1, self._num_items_index)
                      if r >= self._max_size:
                          self._items.pop(-1)
                          self._items.append(item)
                          self._num_items_index += 1
                          return
              if (
                  item.id == self.min_scalar.id
                  or item.id == self.max_scalar.id
              ):
                  # this item is max or min, should be reserved
                  r = self._random.randint(1, self._max_size - 1)
                  self._last_special = True
              else:
                  # drop by reservoir algorithm
                  r = self._random.randint(1, self._num_items_index)
                  self._last_special = False
              if r < self._max_size:
                  if (
                      self._items[r].id == self.min_scalar.id
                      or self._items[r].id == self.max_scalar.id
                  ):
                      # reserve max and min point
                      if r - 1 > 0:
                          r = r - 1
                      elif r + 1 < self._max_size:
                          r = r + 1
                  self._items.pop(r)
                  self._items.append(item)
  
          self._num_items_index += 1
  
imports: import collections
  import random
  import threading
label_desc: Use image node_id 3 for calling the _ReservoirBucket obj's underlying member method code with example usage: obj.add_scalar_item(item) without return types