Return the number of features in an array-like X. This helper function tries hard to avoid to materialize an array version of X unless necessary. For instance, if X is a list of lists, this function will return the length of the first element, assuming that subsequent elements are a
(X)
| 310 | |
| 311 | |
| 312 | def _num_features(X): |
| 313 | """Return the number of features in an array-like X. |
| 314 | |
| 315 | This helper function tries hard to avoid to materialize an array version |
| 316 | of X unless necessary. For instance, if X is a list of lists, |
| 317 | this function will return the length of the first element, assuming |
| 318 | that subsequent elements are all lists of the same length without |
| 319 | checking. |
| 320 | Parameters |
| 321 | ---------- |
| 322 | X : array-like |
| 323 | array-like to get the number of features. |
| 324 | |
| 325 | Returns |
| 326 | ------- |
| 327 | features : int |
| 328 | Number of features |
| 329 | """ |
| 330 | type_ = type(X) |
| 331 | if type_.__module__ == "builtins": |
| 332 | type_name = type_.__qualname__ |
| 333 | else: |
| 334 | type_name = f"{type_.__module__}.{type_.__qualname__}" |
| 335 | message = f"Unable to find the number of features from X of type {type_name}" |
| 336 | if not hasattr(X, "__len__") and not hasattr(X, "shape"): |
| 337 | if not hasattr(X, "__array__"): |
| 338 | raise TypeError(message) |
| 339 | # Only convert X to a numpy array if there is no cheaper, heuristic |
| 340 | # option. |
| 341 | X = np.asarray(X) |
| 342 | |
| 343 | if hasattr(X, "shape"): |
| 344 | if not hasattr(X.shape, "__len__") or len(X.shape) <= 1: |
| 345 | message += f" with shape {X.shape}" |
| 346 | raise TypeError(message) |
| 347 | return X.shape[1] |
| 348 | |
| 349 | first_sample = X[0] |
| 350 | |
| 351 | # Do not consider an array-like of strings or dicts to be a 2D array |
| 352 | if isinstance(first_sample, (str, bytes, dict)): |
| 353 | message += f" where the samples are of type {type(first_sample).__qualname__}" |
| 354 | raise TypeError(message) |
| 355 | |
| 356 | try: |
| 357 | # If X is a list of lists, for instance, we assume that all nested |
| 358 | # lists have the same length without checking or converting to |
| 359 | # a numpy array to keep this function call as cheap as possible. |
| 360 | return len(first_sample) |
| 361 | except Exception as err: |
| 362 | raise TypeError(message) from err |
| 363 | |
| 364 | |
| 365 | def _num_samples(x): |
no outgoing calls
searching dependent graphs…