class_docstr: Convert data from a columnar representation like Pandas and Numpy into values appropriate for
  element_data.py types.
  
  Args:
      name (str): the name of the argument for error messages
      default_type (hashable): the default type to use for data without a type
      type_column (hashable, optional): the name of the type column, if one is being used
      column_defaults (dict of hashable to any): any default values for columns (using names before renaming!)
      selected_columns (dict of hashable to hashable): renamings for columns, mapping original name to new name
      dtype (str or numpy dtype): the data type to use for the feature matrices
      transform_columns (dict of hashable to callable): column transformations, maps column name to transform
class_docstr_tok: ["Convert","data","from","a","columnar","representation","like","Pandas","and","Numpy","into","values","appropriate","for","element_data.py","types",".","Args",":","name","(","str",")",":","the","name","of","the","argument","for","error","messages","default_type","(","hashable",")",":","the","default","type","to","use","for","data","without","a","type","type_column","(","hashable",",","optional",")",":","the","name","of","the","type","column",",","if","one","is","being","used","column_defaults","(","dict","of","hashable","to","any",")",":","any","default","values","for","columns","(","using","names","before","renaming","!",")","selected_columns","(","dict","of","hashable","to","hashable",")",":","renamings","for","columns",",","mapping","original","name","to","new","name","dtype","(","str","or","numpy","dtype",")",":","the","data","type","to","use","for","the","feature","matrices","transform_columns","(","dict","of","hashable","to","callable",")",":","column","transformations",",","maps","column","name","to","transform"]
code: def _convert_pandas(self, type_name, data):
      assert isinstance(data, pd.DataFrame)
      existing = set(self.selected_columns).intersection(data.columns)
  
      ids = data.index
  
      # split the dataframe based on the columns we know about
      missing_columns = []
  
      def select_column(old_name):
          if old_name in data.columns:
              column = data[old_name].to_numpy()
          elif old_name in self.column_defaults:
              column = np.broadcast_to(
                  self.column_defaults[old_name], len(ids)
              )
          else:
              nonlocal missing_columns
              missing_columns.append(old_name)
              return None
  
          transform = self.transform_columns.get(old_name)
          if transform is not None:
              column = transform(column)
  
          return column
  
      columns = {
          new_name: select_column(old_name)
          for old_name, new_name in self.selected_columns.items()
      }
      if missing_columns:
          raise ValueError(
              f"{self.name(type_name)}: expected {comma_sep(self.selected_columns)} columns, found: {comma_sep(data.columns)}"
          )
  
      if len(existing) != len(data.columns):
          other = data.drop(columns=existing)
  
          # to_numpy returns an unspecified order but it's Fortran in practice. Row-level bulk
          # operations are more common (e.g. slicing out a couple of row, when sampling a few
          # nodes) than column-level ones so having rows be contiguous (C order) is much more
          # efficient.
          features = np.ascontiguousarray(
              other.to_numpy(dtype=self.dtype)
          )
      else:
          # if there's no extra columns we can save some effort and some memory usage by entirely
          # avoiding the Pandas tricks
          features = zero_sized_array((len(data), 0), self.dtype)
  
      return ids, columns, features
  
imports: from collections import defaultdict, namedtuple
  from typing import Iterable
  import warnings
  import numpy
  import pandas
  from ..globalvar import SOURCE, TARGET, WEIGHT, TYPE_ATTR_NAME
  from .element_data import NodeData, EdgeData
  from .indexed_array import IndexedArray
  from .validation import comma_sep, require_dataframe_has_columns
  from .utils import is_real_iterable, zero_sized_array, smart_array_concatenate, smart_array_index
label_desc: Use image node_id 4 for calling the ColumnarConverter obj's underlying member method code with example usage: obj._convert_pandas(type_name, data) and returns: ids,  columns,  features, column, None