docs: def aggregate_data(data, T=[0, inf], P=[0, inf], data_ranges=None,
                     merge="overlap", feature_type=None, impute=False,
                     scale_center=True):
      """
      Aggregates molecular data for model training
  
      Parameters
      ----------
      data: list
          density, cpt, and/or viscosity
      T: array
          desired min and max of temperature distribution
      P: array
          desired min and max of pressure distribution
      data_ranges: array
          desired min and max of property distribution(s)
      merge: str
          overlap or union, defaults to overlap. Merge type of property sets
      feature_type: str
          desired feature set, defaults to RDKit's 2D descriptor set
  
      Returns
      -----------
      devmodel: dev_model obj
          returns dev_model object containing scale/center information,
          data summary, and the data frame
      """
      data_files = []
      for i, string in enumerate(data):
          data_files.append(load_data("%s_premodel.csv" % string))
          if i == 0:
              merged = data_files[0]
          if i == 1:
              merged = pd.merge(data_files[0], data_files[1], sort=False,
                                how='outer')
          elif i > 1:
              merged = pd.merge(merged, data_files[-1], sort=False, how='outer')
      if merge == "overlap":
          merged.dropna(inplace=True)
      # select state variable and data ranges
      merged = merged.loc[merged["Temperature, K"] < T[1]]
      merged = merged.loc[merged["Temperature, K"] > T[0]]
      merged = merged.loc[merged["Pressure, kPa"] < P[1]]
      merged = merged.loc[merged["Pressure, kPa"] > P[0]]
      for i in range(1, len(data) + 1):
          merged = merged[merged.iloc[:, -i] != 0]  # avoid log(0) error
          if data_ranges:
              merged = merged[merged.iloc[:, -i] < data_ranges[::-1][i - 1][1]]
              merged = merged[merged.iloc[:, -i] > data_ranges[::-1][i - 1][0]]
      merged.reset_index(drop=True, inplace=True)
      # Create summary of dataset
      unique_salts = merged["smiles-cation"] + merged["smiles-anion"]
      unique_cations = repr(merged["smiles-cation"].unique())
      unique_anions = repr(merged["smiles-anion"].unique())
      actual_data_ranges = []
      for i in range(1, len(data) + 3):
          actual_data_ranges.append("{} - {}".format(
              str(merged.iloc[:, -i].min()), str(merged.iloc[:, -i].max())))
      a = np.array([len(unique_salts.unique()), unique_cations, unique_anions,
                   len(unique_salts)])
      a = np.concatenate((a, actual_data_ranges))
      cols1 = ["Unique salts", "Cations", "Anions", "Total datapoints"]
      cols2 = ["Temperature range (K)", "Pressure range (kPa)"]
      cols = cols1 + data[::-1] + cols2
      data_summary = pd.DataFrame(a, cols)
      # scale and center
      metaDf = merged.select_dtypes(include=["object"])
      dataDf = merged.select_dtypes(include=[np.number])
      cols = dataDf.columns.tolist()
      if impute:
          imp = Imputer(missing_values='NaN', strategy="median", axis=0)
          X = imp.fit_transform(dataDf)
          dataDf = pd.DataFrame(X, columns=cols)
      instance = StandardScaler()
      if scale_center:
          for i in range(1, len(data) + 1):
              dataDf.is_copy = False
              dataDf.iloc[:, -i] = dataDf.iloc[:, -i].apply(lambda x:
                                                            log(float(x)))
          scaled_data = pd.DataFrame(instance.
                                     fit_transform(dataDf.iloc[:, :-len(data)]),
                                     columns=cols[:-len(data)])
          df = pd.concat([scaled_data, dataDf.iloc[:, -len(data):], metaDf],
                         axis=1)
          mean_std_of_coeffs = pd.DataFrame([instance.mean_, instance.scale_],
                                            columns=cols[:-len(data)])
      else:
          instance.fit(dataDf.iloc[:, :-len(data)])
          df = pd.concat([dataDf, metaDf], axis=1)
          mean_std_of_coeffs = pd.DataFrame([instance.mean_, instance.scale_],
                                            columns=cols[:-len(data)])
      devmodel = dev_model(mean_std_of_coeffs, data_summary, df)
      return devmodel