docstr: Perturbs data according to some function
  
  Parameters
  ----------
  data : list
      List of examples, could be strings, tuples, dicts, spacy docs, whatever
  perturb_fn : function
      Arguments: (example, *args, **kwargs)
      Returns: list of examples, or (examples, meta) if meta=True in **kwargs.
      Can also return None if perturbation does not apply, and it will be ignored.
  keep_original : bool
      if True, include original example (from data) in output
  nsamples : int
      number of examples in data to perturb
  meta : bool
      if True, perturb_fn returns (examples, meta), and meta is added to ret.meta
  
  Returns
  -------
  MunchWithAdd
      will have .data and .meta (if meta=True in **kwargs)
docstr_tok: ["Perturbs","data","according","to","some","function","Parameters","--","--","--","--","--","data",":","list","List","of","examples",",","could","be","strings",",","tuples",",","dicts",",","spacy","docs",",","whatever","perturb_fn",":","function","Arguments",":","(","example",",","*","args",",","*","*","kwargs",")","Returns",":","list","of","examples",",","or","(","examples",",","meta",")","if","meta=True","in","*","*","kwargs",".","Can","also","return","None","if","perturbation","does","not","apply",",","and","it","will","be","ignored",".","keep_original",":","bool","if","True",",","include","original","example","(","from","data",")","in","output","nsamples",":","int","number","of","examples","in","data","to","perturb","meta",":","bool","if","True",",","perturb_fn","returns","(","examples",",","meta",")",",","and","meta","is","added","to","ret.meta","Returns","--","--","--","-","MunchWithAdd","will","have",".data","and",".meta","(","if","meta=True","in","*","*","kwargs",")"]
code: def perturb(
      data,
      perturb_fn,
      keep_original=True,
      nsamples=None,
      *args,
      **kwargs,
  ):
      """Perturbs data according to some function
  
      Parameters
      ----------
      data : list
          List of examples, could be strings, tuples, dicts, spacy docs, whatever
      perturb_fn : function
          Arguments: (example, *args, **kwargs)
          Returns: list of examples, or (examples, meta) if meta=True in **kwargs.
          Can also return None if perturbation does not apply, and it will be ignored.
      keep_original : bool
          if True, include original example (from data) in output
      nsamples : int
          number of examples in data to perturb
      meta : bool
          if True, perturb_fn returns (examples, meta), and meta is added to ret.meta
  
      Returns
      -------
      MunchWithAdd
          will have .data and .meta (if meta=True in **kwargs)
  
      """
      ret = MunchWithAdd()
      use_meta = kwargs.get("meta", False)
      ret_data = []
      meta = []
      order = list(range(len(data)))
      samples = 0
      if nsamples:
          np.random.shuffle(order)
      for i in order:
          d = data[i]
          t = []
          add = []
          if keep_original:
              org = recursive_apply(d, str)
              t.append(org)
              add.append(None)
          p = perturb_fn(d, *args, **kwargs)
          a = []
          x = []
          if not p or all([not x for x in p]):
              continue
          if use_meta:
              p, a = p
          if type(p) in [np.array, list]:
              t.extend(p)
              add.extend(a)
          else:
              t.append(p)
              add.append(a)
          ret_data.append(t)
          meta.append(add)
          samples += 1
          if nsamples and samples == nsamples:
              break
      ret.data = ret_data
      if use_meta:
          ret.meta = meta
      return ret
  
imports: import numpy
  import collections
  import re
  import os
  import json
  import pattern
  from pattern.en import tenses
  from .editor import recursive_apply, MunchWithAdd
label_desc: Use image node_id 1 for calling the Perturb obj's underlying member method code with example usage: obj.perturb(data, perturb_fn, keep_original, nsamples) and returns: ret