util.py 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. import numpy as np
  2. from pandas.core.dtypes.common import is_list_like
  3. from pandas.core import common as com
  4. def cartesian_product(X):
  5. """
  6. Numpy version of itertools.product or pandas.compat.product.
  7. Sometimes faster (for large inputs)...
  8. Parameters
  9. ----------
  10. X : list-like of list-likes
  11. Returns
  12. -------
  13. product : list of ndarrays
  14. Examples
  15. --------
  16. >>> cartesian_product([list('ABC'), [1, 2]])
  17. [array(['A', 'A', 'B', 'B', 'C', 'C'], dtype='|S1'),
  18. array([1, 2, 1, 2, 1, 2])]
  19. See Also
  20. --------
  21. itertools.product : Cartesian product of input iterables. Equivalent to
  22. nested for-loops.
  23. pandas.compat.product : An alias for itertools.product.
  24. """
  25. msg = "Input must be a list-like of list-likes"
  26. if not is_list_like(X):
  27. raise TypeError(msg)
  28. for x in X:
  29. if not is_list_like(x):
  30. raise TypeError(msg)
  31. if len(X) == 0:
  32. return []
  33. lenX = np.fromiter((len(x) for x in X), dtype=np.intp)
  34. cumprodX = np.cumproduct(lenX)
  35. a = np.roll(cumprodX, 1)
  36. a[0] = 1
  37. if cumprodX[-1] != 0:
  38. b = cumprodX[-1] / cumprodX
  39. else:
  40. # if any factor is empty, the cartesian product is empty
  41. b = np.zeros_like(cumprodX)
  42. return [np.tile(np.repeat(np.asarray(com.values_from_object(x)), b[i]),
  43. np.product(a[i]))
  44. for i, x in enumerate(X)]