Skip to content

Commit 6d684e1

Browse files
committed
PERF: remove use of Panel & perf in rolling corr/cov
closes pandas-dev#17917
1 parent c271d4d commit 6d684e1

File tree

4 files changed

+70
-27
lines changed

4 files changed

+70
-27
lines changed

asv_bench/benchmarks/rolling.py

+22-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class Methods(object):
1111
[10, 1000],
1212
['int', 'float'],
1313
['median', 'mean', 'max', 'min', 'std', 'count', 'skew', 'kurt',
14-
'sum', 'corr', 'cov'])
14+
'sum'])
1515
param_names = ['contructor', 'window', 'dtype', 'method']
1616

1717
def setup(self, contructor, window, dtype, method):
@@ -23,6 +23,27 @@ def time_rolling(self, contructor, window, dtype, method):
2323
getattr(self.roll, method)()
2424

2525

26+
class Pairwise(object):
27+
28+
sample_time = 0.2
29+
params = ([10, 1000, None],
30+
['corr', 'cov'],
31+
[True, False])
32+
param_names = ['window', 'method', 'pairwise']
33+
34+
def setup(self, window, method, pairwise):
35+
N = 10**4
36+
arr = np.random.random(N)
37+
self.df = pd.DataFrame(arr)
38+
39+
def time_pairwise(self, window, method, pairwise):
40+
if window is None:
41+
r = self.df.expanding()
42+
else:
43+
r = self.df.rolling(window=window)
44+
getattr(r, method)(self.df, pairwise=pairwise)
45+
46+
2647
class Quantile(object):
2748

2849
sample_time = 0.2

pandas/core/indexes/base.py

+5
Original file line numberDiff line numberDiff line change
@@ -1108,6 +1108,11 @@ def _assert_can_do_op(self, value):
11081108
def nlevels(self):
11091109
return 1
11101110

1111+
@property
1112+
def levels(self):
1113+
""" return a list my levels """
1114+
return [list(self)]
1115+
11111116
def _get_names(self):
11121117
return FrozenList((self.name, ))
11131118

pandas/core/window.py

+30-17
Original file line numberDiff line numberDiff line change
@@ -1863,25 +1863,38 @@ def dataframe_from_int_dict(data, frame_template):
18631863
results[i][j] = f(*_prep_binary(arg1.iloc[:, i],
18641864
arg2.iloc[:, j]))
18651865

1866-
# TODO: not the most efficient (perf-wise)
1867-
# though not bad code-wise
1868-
from pandas import Panel, MultiIndex, concat
1869-
1870-
with warnings.catch_warnings(record=True):
1871-
p = Panel.from_dict(results).swapaxes('items', 'major')
1872-
if len(p.major_axis) > 0:
1873-
p.major_axis = arg1.columns[p.major_axis]
1874-
if len(p.minor_axis) > 0:
1875-
p.minor_axis = arg2.columns[p.minor_axis]
1876-
1877-
if len(p.items):
1866+
from pandas import MultiIndex, concat
1867+
1868+
result_index = arg1.index.union(arg2.index)
1869+
if len(result_index):
1870+
1871+
# construct result frame
18781872
result = concat(
1879-
[p.iloc[i].T for i in range(len(p.items))],
1880-
keys=p.items)
1873+
[concat([results[i][j]
1874+
for j, c in enumerate(arg2.columns)],
1875+
ignore_index=True)
1876+
for i, c in enumerate(arg1.columns)],
1877+
ignore_index=True,
1878+
axis=1)
1879+
result.columns = arg1.columns
1880+
1881+
# set the index and reorder
1882+
if arg2.columns.nlevels > 1:
1883+
result.index = MultiIndex.from_product(
1884+
arg2.columns.levels + result_index.levels)
1885+
result = result.reorder_levels([2, 0, 1]).sort_index()
1886+
else:
1887+
result.index = MultiIndex.from_product(
1888+
[range(len(arg2.columns)),
1889+
range(len(result_index))])
1890+
result = result.swaplevel(1, 0).sort_index()
1891+
result.index = MultiIndex.from_product(
1892+
result_index.levels + arg2.columns.levels)
18811893
else:
18821894

1895+
# empty result
18831896
result = DataFrame(
1884-
index=MultiIndex(levels=[arg1.index, arg1.columns],
1897+
index=MultiIndex(levels=[arg1.index, arg2.columns],
18851898
labels=[[], []]),
18861899
columns=arg2.columns,
18871900
dtype='float64')
@@ -1890,9 +1903,9 @@ def dataframe_from_int_dict(data, frame_template):
18901903
# reset our column names to arg2 names
18911904
# careful not to mutate the original names
18921905
result.columns = result.columns.set_names(
1893-
arg2.columns.names)
1906+
arg1.columns.names)
18941907
result.index = result.index.set_names(
1895-
arg1.index.names + arg1.columns.names)
1908+
result_index.names + arg2.columns.names)
18961909

18971910
return result
18981911

pandas/tests/test_window.py

+13-9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import pandas.tseries.offsets as offsets
1717
from pandas.core.base import SpecificationError
1818
from pandas.errors import UnsupportedFunctionCall
19+
from pandas.core.sorting import safe_sort
1920
import pandas.util.testing as tm
2021
import pandas.util._test_decorators as td
2122
from pandas.compat import range, zip, PY3
@@ -1814,7 +1815,7 @@ def compare(self, result, expected):
18141815
result = result.dropna().values
18151816
expected = expected.dropna().values
18161817

1817-
tm.assert_numpy_array_equal(result, expected)
1818+
tm.assert_numpy_array_equal(result, expected, check_dtype=False)
18181819

18191820
@pytest.mark.parametrize('f', [lambda x: x.cov(), lambda x: x.corr()])
18201821
def test_no_flex(self, f):
@@ -1839,15 +1840,19 @@ def test_no_flex(self, f):
18391840
def test_pairwise_with_self(self, f):
18401841

18411842
# DataFrame with itself, pairwise=True
1842-
results = [f(df) for df in self.df1s]
1843-
for (df, result) in zip(self.df1s, results):
1843+
# note that we may construct the 1st level of the MI
1844+
# in a non-motononic way, so compare accordingly
1845+
results = []
1846+
for i, df in enumerate(self.df1s):
1847+
result = f(df)
18441848
tm.assert_index_equal(result.index.levels[0],
18451849
df.index,
18461850
check_names=False)
1847-
tm.assert_index_equal(result.index.levels[1],
1848-
df.columns,
1849-
check_names=False)
1851+
tm.assert_numpy_array_equal(safe_sort(result.index.levels[1]),
1852+
safe_sort(df.columns.unique()))
18501853
tm.assert_index_equal(result.columns, df.columns)
1854+
results.append(df)
1855+
18511856
for i, result in enumerate(results):
18521857
if i > 0:
18531858
self.compare(result, results[0])
@@ -1885,9 +1890,8 @@ def test_pairwise_with_other(self, f):
18851890
tm.assert_index_equal(result.index.levels[0],
18861891
df.index,
18871892
check_names=False)
1888-
tm.assert_index_equal(result.index.levels[1],
1889-
self.df2.columns,
1890-
check_names=False)
1893+
tm.assert_numpy_array_equal(safe_sort(result.index.levels[1]),
1894+
safe_sort(self.df2.columns.unique()))
18911895
for i, result in enumerate(results):
18921896
if i > 0:
18931897
self.compare(result, results[0])

0 commit comments

Comments
 (0)