test_dot.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import numpy as np
  2. import pytest
  3. from pandas import (
  4. DataFrame,
  5. Series,
  6. )
  7. import pandas._testing as tm
  8. class DotSharedTests:
  9. @pytest.fixture
  10. def obj(self):
  11. raise NotImplementedError
  12. @pytest.fixture
  13. def other(self) -> DataFrame:
  14. """
  15. other is a DataFrame that is indexed so that obj.dot(other) is valid
  16. """
  17. raise NotImplementedError
  18. @pytest.fixture
  19. def expected(self, obj, other) -> DataFrame:
  20. """
  21. The expected result of obj.dot(other)
  22. """
  23. raise NotImplementedError
  24. @classmethod
  25. def reduced_dim_assert(cls, result, expected):
  26. """
  27. Assertion about results with 1 fewer dimension that self.obj
  28. """
  29. raise NotImplementedError
  30. def test_dot_equiv_values_dot(self, obj, other, expected):
  31. # `expected` is constructed from obj.values.dot(other.values)
  32. result = obj.dot(other)
  33. tm.assert_equal(result, expected)
  34. def test_dot_2d_ndarray(self, obj, other, expected):
  35. # Check ndarray argument; in this case we get matching values,
  36. # but index/columns may not match
  37. result = obj.dot(other.values)
  38. assert np.all(result == expected.values)
  39. def test_dot_1d_ndarray(self, obj, expected):
  40. # can pass correct-length array
  41. row = obj.iloc[0] if obj.ndim == 2 else obj
  42. result = obj.dot(row.values)
  43. expected = obj.dot(row)
  44. self.reduced_dim_assert(result, expected)
  45. def test_dot_series(self, obj, other, expected):
  46. # Check series argument
  47. result = obj.dot(other["1"])
  48. self.reduced_dim_assert(result, expected["1"])
  49. def test_dot_series_alignment(self, obj, other, expected):
  50. result = obj.dot(other.iloc[::-1]["1"])
  51. self.reduced_dim_assert(result, expected["1"])
  52. def test_dot_aligns(self, obj, other, expected):
  53. # Check index alignment
  54. other2 = other.iloc[::-1]
  55. result = obj.dot(other2)
  56. tm.assert_equal(result, expected)
  57. def test_dot_shape_mismatch(self, obj):
  58. msg = "Dot product shape mismatch"
  59. # exception raised is of type Exception
  60. with pytest.raises(Exception, match=msg):
  61. obj.dot(obj.values[:3])
  62. def test_dot_misaligned(self, obj, other):
  63. msg = "matrices are not aligned"
  64. with pytest.raises(ValueError, match=msg):
  65. obj.dot(other.T)
  66. class TestSeriesDot(DotSharedTests):
  67. @pytest.fixture
  68. def obj(self):
  69. return Series(
  70. np.random.default_rng(2).standard_normal(4), index=["p", "q", "r", "s"]
  71. )
  72. @pytest.fixture
  73. def other(self):
  74. return DataFrame(
  75. np.random.default_rng(2).standard_normal((3, 4)),
  76. index=["1", "2", "3"],
  77. columns=["p", "q", "r", "s"],
  78. ).T
  79. @pytest.fixture
  80. def expected(self, obj, other):
  81. return Series(np.dot(obj.values, other.values), index=other.columns)
  82. @classmethod
  83. def reduced_dim_assert(cls, result, expected):
  84. """
  85. Assertion about results with 1 fewer dimension that self.obj
  86. """
  87. tm.assert_almost_equal(result, expected)
  88. class TestDataFrameDot(DotSharedTests):
  89. @pytest.fixture
  90. def obj(self):
  91. return DataFrame(
  92. np.random.default_rng(2).standard_normal((3, 4)),
  93. index=["a", "b", "c"],
  94. columns=["p", "q", "r", "s"],
  95. )
  96. @pytest.fixture
  97. def other(self):
  98. return DataFrame(
  99. np.random.default_rng(2).standard_normal((4, 2)),
  100. index=["p", "q", "r", "s"],
  101. columns=["1", "2"],
  102. )
  103. @pytest.fixture
  104. def expected(self, obj, other):
  105. return DataFrame(
  106. np.dot(obj.values, other.values), index=obj.index, columns=other.columns
  107. )
  108. @classmethod
  109. def reduced_dim_assert(cls, result, expected):
  110. """
  111. Assertion about results with 1 fewer dimension that self.obj
  112. """
  113. tm.assert_series_equal(result, expected, check_names=False)
  114. assert result.name is None
  115. @pytest.mark.parametrize(
  116. "dtype,exp_dtype",
  117. [("Float32", "Float64"), ("Int16", "Int32"), ("float[pyarrow]", "double[pyarrow]")],
  118. )
  119. def test_arrow_dtype(dtype, exp_dtype):
  120. pytest.importorskip("pyarrow")
  121. cols = ["a", "b"]
  122. df_a = DataFrame([[1, 2], [3, 4], [5, 6]], columns=cols, dtype="int32")
  123. df_b = DataFrame([[1, 0], [0, 1]], index=cols, dtype=dtype)
  124. result = df_a.dot(df_b)
  125. expected = DataFrame([[1, 2], [3, 4], [5, 6]], dtype=exp_dtype)
  126. tm.assert_frame_equal(result, expected)