Repository: pandas-dev/pandas

Issue:
BUG: np.array @ pd.Series swaps arguments
#### Code Sample, a copy-pastable example if possible

Input:
```python
np.zeros((1, 2)) @ pd.Series(np.zeros(2))
```

Output:
```python
  File "<ipython-input-83-3148232e4345>", line 1, in <module>
    np.zeros((1, 2)) @ pd.Series(np.zeros(2))
  File "pandas/core/series.py", line 2061, in __rmatmul__
    return self.dot(other)
  File "pandas/core/series.py", line 2043, in dot
    (lvals.shape, rvals.shape))
Exception: Dot product shape mismatch, (2,) vs (1, 2)
```

#### Problem description

Pandas v0.23.0 (#19035) adds support for expressions `np.array @ pd.Series`, but the support is implemented incorrectly, and instead evaluates `pd.Series @ np.array`, which is different. This is inconsistent with the behaviour of `@` when applied to two arrays, two pandas objects, or an array and a DataFrame. 

#### Expected Output

```python
array([ 0.])
```

#### Output of ``pd.show_versions()``

<details>


INSTALLED VERSIONS
------------------
commit: None
python: 3.6.5.final.0
python-bits: 64
OS: Linux
OS-release: 4.14.14-200.fc26.x86_64
machine: x86_64
processor: x86_64
byteorder: little
LC_ALL: C
LANG: C
LOCALE: None.None

pandas: 0.23.1
pytest: 3.6.0
pip: 10.0.1
setuptools: 39.2.0
Cython: 0.28.3
numpy: 1.13.3
scipy: 0.19.1
pyarrow: None
xarray: None
IPython: 4.2.1
sphinx: None
patsy: 0.5.0
dateutil: 2.7.3
pytz: 2018.4
blosc: None
bottleneck: 1.2.1
tables: 3.4.3
numexpr: 2.6.2
feather: None
matplotlib: 2.2.2
openpyxl: None
xlrd: 1.1.0
xlwt: None
xlsxwriter: None
lxml: None
bs4: 4.6.0
html5lib: 1.0.1
sqlalchemy: 1.2.8
pymysql: None
psycopg2: None
jinja2: 2.10
s3fs: None
fastparquet: 0.1.5
pandas_gbq: None
pandas_datareader: None
</details>



Discussion:
cc @TomAugspurger 
@bnaul
happy to give it a try.
@minggli : Go for it!

Resolving patch:
diff --git a/pandas/core/series.py b/pandas/core/series.py
--- a/pandas/core/series.py
+++ b/pandas/core/series.py
@@ -2066,7 +2066,7 @@ def __matmul__(self, other):
 
     def __rmatmul__(self, other):
         """ Matrix multiplication using binary `@` operator in Python>=3.5 """
-        return self.dot(other)
+        return self.dot(np.transpose(other))
 
     @Substitution(klass='Series')
     @Appender(base._shared_docs['searchsorted'])


Test patch:
diff --git a/pandas/tests/series/test_analytics.py b/pandas/tests/series/test_analytics.py
--- a/pandas/tests/series/test_analytics.py
+++ b/pandas/tests/series/test_analytics.py
@@ -849,11 +849,30 @@ def test_matmul(self):
         expected = np.dot(a.values, a.values)
         assert_almost_equal(result, expected)
 
-        # np.array @ Series (__rmatmul__)
+        # GH 21530
+        # vector (1D np.array) @ Series (__rmatmul__)
         result = operator.matmul(a.values, a)
         expected = np.dot(a.values, a.values)
         assert_almost_equal(result, expected)
 
+        # GH 21530
+        # vector (1D list) @ Series (__rmatmul__)
+        result = operator.matmul(a.values.tolist(), a)
+        expected = np.dot(a.values, a.values)
+        assert_almost_equal(result, expected)
+
+        # GH 21530
+        # matrix (2D np.array) @ Series (__rmatmul__)
+        result = operator.matmul(b.T.values, a)
+        expected = np.dot(b.T.values, a.values)
+        assert_almost_equal(result, expected)
+
+        # GH 21530
+        # matrix (2D nested lists) @ Series (__rmatmul__)
+        result = operator.matmul(b.T.values.tolist(), a)
+        expected = np.dot(b.T.values, a.values)
+        assert_almost_equal(result, expected)
+
         # mixed dtype DataFrame @ Series
         a['p'] = int(a.p)
         result = operator.matmul(b.T, a)