def aggregate(self, out_file: str = None, select: np.ndarray = None, group_by: Union[str, np.ndarray] = "Clusters", aggr_by: str = "mean", aggr_ca_by: Dict[str, str] = None) -> np.ndarray:
		"""
		Aggregate the Loom file by applying aggregation functions to the main matrix as well as to the column attributes

		Args:
			out_file	The name of the output Loom file (will be appended to if it exists)
			select		Bool array giving the columns to include (or None, to include all)
			group_by	The column attribute to group by, or an np.ndarray of integer group labels
			aggr_by 	The aggregation function for the main matrix
			aggr_ca_by	A dictionary of aggregation functions for the column attributes (or None to skip)

		Returns:
			m			Aggregated main matrix

		Remarks:
			aggr_by gives the aggregation function for the main matrix
			aggr_ca_by is a dictionary with column attributes as keys and aggregation functionas as values
			
			Aggregation functions can be any valid aggregation function from here: https://github.com/ml31415/numpy-groupies

			In addition, you can specify:
				"tally" to count the number of occurences of each value of a categorical attribute
		
		"""
		ca = {}  # type: Dict[str, np.ndarray]
		if select is not None:
			raise ValueError("The 'select' argument is deprecated")
		if isinstance(group_by, np.ndarray):
			labels = group_by
		else:
			labels = (self.ca[group_by]).astype('int')
		_, zero_strt_sort_noholes_lbls = np.unique(labels, return_inverse=True)
		n_groups = len(set(labels))
		if aggr_ca_by is not None:
			for key in self.ca.keys():
				if key not in aggr_ca_by:
					continue
				func = aggr_ca_by[key]
				if func == "tally":
					for val in set(self.ca[key]):
						if np.issubdtype(type(val), np.str_):
							valnew = val.replace("/", "-")  # Slashes are not allowed in attribute names
							valnew = valnew.replace(".", "_")  # Nor are periods
						ca[key + "_" + str(valnew)] = npg.aggregate(zero_strt_sort_noholes_lbls, (self.ca[key] == val).astype('int'), func="sum", fill_value=0)
				elif func == "mode":
					def mode(x):  # type: ignore
						return scipy.stats.mode(x)[0][0]
					ca[key] = npg.aggregate(zero_strt_sort_noholes_lbls, self.ca[key], func=mode, fill_value=0).astype('str')
				elif func == "mean":
					ca[key] = npg.aggregate(zero_strt_sort_noholes_lbls, self.ca[key], func=func, fill_value=0)
				elif func == "first":
					ca[key] = npg.aggregate(zero_strt_sort_noholes_lbls, self.ca[key], func=func, fill_value=self.ca[key][0])

		m = np.empty((self.shape[0], n_groups))
		for (_, selection, view) in self.scan(axis=0, layers=[""]):
			vals_aggr = npg.aggregate(zero_strt_sort_noholes_lbls, view[:, :], func=aggr_by, axis=1, fill_value=0)
			m[selection, :] = vals_aggr

		if out_file is not None:
			loompy.create(out_file, m, self.ra, ca)

		return m
Aggregate the Loom file by applying aggregation functions to the main matrix as well as to the column attributes

		Args:
			out_file	The name of the output Loom file (will be appended to if it exists)
			select		Bool array giving the columns to include (or None, to include all)
			group_by	The column attribute to group by, or an np.ndarray of integer group labels
			aggr_by 	The aggregation function for the main matrix
			aggr_ca_by	A dictionary of aggregation functions for the column attributes (or None to skip)

		Returns:
			m			Aggregated main matrix

		Remarks:
			aggr_by gives the aggregation function for the main matrix
			aggr_ca_by is a dictionary with column attributes as keys and aggregation functionas as values
			
			Aggregation functions can be any valid aggregation function from here: https://github.com/ml31415/numpy-groupies

			In addition, you can specify:
				"tally" to count the number of occurences of each value of a categorical attribute