title: Caveats while checking dtype in pandas DataFrame
body: <p>Guided by <a href="https://stackoverflow.com/questions/22697773/how-to-check-the-dtype-of-a-column-in-python-pandas/45568211#45568211">this</a> answer I started to build up pipe for processing columns of dataframe based on its dtype. But after getting some unexpected output and some debugging i ended up with test dataframe and test dtype checking:</p>
  
  <pre class="lang-py prettyprint-override"><code># Creating test dataframe
  test = pd.DataFrame({'bool' :[False, True], 'int':[-1,2],'float': [-2.5, 3.4],
                       'compl':np.array([1-1j, 5]),
                       'dt'   :[pd.Timestamp('2013-01-02'), pd.Timestamp('2016-10-20')],
                       'td'   :[pd.Timestamp('2012-03-02')- pd.Timestamp('2016-10-20'),
                                pd.Timestamp('2010-07-12')- pd.Timestamp('2000-11-10')],
                       'prd'  :[pd.Period('2002-03','D'), pd.Period('2012-02-01', 'D')],
                       'intrv':pd.arrays.IntervalArray([pd.Interval(0, 0.1), pd.Interval(1, 5)]),
                       'str'  :['s1', 's2'],
                       'cat'  :[1, -1],
                       'obj'  :[[1,2,3], [5435,35,-52,14]]
                      })
  test['cat'] = test['cat'].astype('category')
  test
  test.dtypes
  
  # Testing types
  types = list(test.columns)
  df_types = pd.DataFrame(np.zeros((len(types),len(types)), dtype=bool),
                          index = ['is_'+el for el in types],
                          columns = types)
  for col in test.columns:
      df_types.at['is_bool', col] = pd.api.types.is_bool_dtype(test[col])
      df_types.at['is_int' , col] = pd.api.types.is_integer_dtype(test[col])
      df_types.at['is_float',col] = pd.api.types.is_float_dtype(test[col])
      df_types.at['is_compl',col] = pd.api.types.is_complex_dtype(test[col])
      df_types.at['is_dt'  , col] = pd.api.types.is_datetime64_dtype(test[col])
      df_types.at['is_td'  , col] = pd.api.types.is_timedelta64_dtype(test[col])
      df_types.at['is_prd' , col] = pd.api.types.is_period_dtype(test[col])
      df_types.at['is_intrv',col] = pd.api.types.is_interval_dtype(test[col])
      df_types.at['is_str' , col] = pd.api.types.is_string_dtype(test[col])
      df_types.at['is_cat' , col] = pd.api.types.is_categorical_dtype(test[col])
      df_types.at['is_obj' , col] = pd.api.types.is_object_dtype(test[col])
  
  # Styling func
  def coloring(df):
      clr_g = 'color : green'
      clr_r = 'color : red'
      mask = ~np.logical_xor(df.values, np.eye(df.shape[0], dtype=bool))
      # OUTPUT
      return pd.DataFrame(np.where(mask, clr_g, clr_r),
                          index = df.index,
                          columns = df.columns)
  
  # OUTPUT colored
  df_types.style.apply(coloring, axis=None)
  </code></pre>
  
  <p>OUTPUT:
  <a href="https://i.stack.imgur.com/nzzXb.png" rel="noreferrer"><img src="https://i.stack.imgur.com/nzzXb.png" alt="enter image description here"></a></p>
  
  <pre class="lang-py prettyprint-override"><code>bool                  bool
  int                  int64
  float              float64
  compl           complex128
  dt          datetime64[ns]
  td         timedelta64[ns]
  prd              period[D]
  intrv    interval[float64]
  str                 object
  cat               category
  obj                 object
  </code></pre>
  
  <p><a href="https://i.stack.imgur.com/H83ss.png" rel="noreferrer"><img src="https://i.stack.imgur.com/H83ss.png" alt="enter image description here"></a></p>
  
  <p>Almost everything is good, but this test code produces two questions:  </p>
  
  <ol>
  <li>The most strange here is that <code>pd.api.types.is_string_dtype</code> fires
  on <code>category</code> dtype. Why is that? Should it be treated as 'expected'
  behavior? </li>
  <li>Why <code>is_string_dtype</code> and  <code>is_object_dtype</code> fires on each
  other? This is a bit expected, because even in <code>.dtypes</code> both types
  are noted as <code>object</code>, but it would be better if someone clarify it
  step by step.</li>
  </ol>
  
  <p>P.s.: Bonus question - am i right when thinking that pandas has its internal tests that should be passed when building new release (like df_types from test code, but not with 'coloring in red' rather 'recording info about errors')?</p>
  
  <p>EDIT: pandas version <code>0.24.2</code>.</p>