docs: def rebuild_schema(doc, r, df):
      """Rebuild the schema for a resource based on a dataframe"""
      import numpy as np
  
      # Re-get the resource in the doc, since it may be different.
      try:
          r = doc.resource(r.name)
      except AttributeError:
          # Maybe r is actually a resource name
          r = doc.resource(r)
  
      def alt_col_name(name, i):
          import re
  
          if not name:
              return 'col{}'.format(i)
  
          return re.sub('_+', '_', re.sub('[^\w_]', '_', str(name)).lower()).rstrip('_')
  
      df_types = {
          np.dtype('O'): 'text',
          np.dtype('int64'): 'integer',
          np.dtype('float64'): 'number'
      }
  
      try:
          df_index_frame = df.index.to_frame()
      except AttributeError:
          df_index_frame = None
  
      def get_col_dtype(c):
  
          c = str(c)
  
          try:
              return df_types[df[c].dtype]
          except KeyError:
              # Maybe it is in the index?
              pass
  
          try:
              return df_types[df_index_frame[c].dtype]
          except TypeError:
              # Maybe not a multi-index
              pass
  
          if c == 'id' or c == df.index.name:
              return df_types[df.index.dtype]
  
          return 'unknown'
  
      columns = []
      schema_term = r.schema_term[0]
  
      if schema_term:
  
          old_cols = {c['name'].value: c.properties for c in schema_term.children}
          for c in schema_term.children:
              schema_term.remove_child(c)
  
          schema_term.children = []
  
      else:
          old_cols = {}
          schema_term = doc['Schema'].new_term('Table', r.schema_name)
  
      index_names = [n if n else "id" for n in df.index.names]
  
      for i, col in enumerate(index_names + list(df.columns)):
          acn = alt_col_name(col, i) if alt_col_name(col, i) != str(col) else ''
  
          d = {'name': col, 'datatype': get_col_dtype(col), 'altname': acn}
  
          if col in old_cols.keys():
              lookup_name = col
          elif acn in old_cols.keys():
              lookup_name = acn
          else:
              lookup_name = None
  
          if lookup_name and lookup_name in old_cols:
  
              for k, v in schema_term.properties.items():
  
                  old_col = old_cols.get(lookup_name)
  
                  for k, v in old_col.items():
                      if k != 'name' and v:
                          d[k] = v
  
          columns.append(d)
  
      for c in columns:
          name = c['name']
          del c['name']
          datatype = c['datatype']
          del c['datatype']
          altname = c['altname']
          del c['altname']
  
          schema_term.new_child('Column', name, datatype=datatype, altname=altname, **c)