Repository: bids-standard/pybids

Issue:
FIX: Flexibly import _get_grouper from Pandas
Using a `try`/`except` block so we support both old and new Pandas.

Probably not great to be depending on a hidden function. Are there any alternatives?


Discussion:

Resolving patch:
diff --git a/bids/analysis/analysis.py b/bids/analysis/analysis.py
--- a/bids/analysis/analysis.py
+++ b/bids/analysis/analysis.py
@@ -193,13 +193,20 @@ def setup(self, input_nodes=None, identity_contrasts=True, **kwargs):
                 node_coll = self._concatenate_input_nodes(input_nodes)
                 colls.append(node_coll)
 
+            model = self.model or {}
+
+            variables = set(model.get('variables', []))
+            hrf_variables = set(model.get('HRF_variables', []))
+            if not variables >= hrf_variables:
+                raise ValueError("HRF_variables must be a subset ",
+                                 "of variables in BIDS model.")
+
             coll = merge_collections(colls) if len(colls) > 1 else colls[0]
 
-            model = self.model or {}
+            coll = apply_transformations(coll, self.transformations)
             if model.get('variables'):
                 transform.select(coll, model['variables'])
-                
-            coll = apply_transformations(coll, self.transformations)
+
             node = AnalysisNode(self.level, coll, self.contrasts, input_nodes,
                                 identity_contrasts)
 
diff --git a/bids/analysis/auto_model.py b/bids/analysis/auto_model.py
--- a/bids/analysis/auto_model.py
+++ b/bids/analysis/auto_model.py
@@ -63,7 +63,7 @@ def auto_model(layout, scan_length=None, one_vs_rest=False):
         trial_type_factors = ["trial_type." + tt for tt in trial_types]
 
         run_model = OrderedDict(HRF_variables=trial_type_factors,
-                                variables=['trial_type'])
+                                variables=trial_type_factors)
         run["model"] = run_model
 
         if one_vs_rest:
diff --git a/bids/variables/variables.py b/bids/variables/variables.py
--- a/bids/variables/variables.py
+++ b/bids/variables/variables.py
@@ -9,6 +9,11 @@
 from six import add_metaclass
 from bids.utils import matches_entities
 
+try:
+    from pandas.core.groupby import _get_grouper
+except ImportError:
+    from pandas.core.groupby.groupby import _get_grouper
+
 
 @add_metaclass(ABCMeta)
 class BIDSVariable(object):
@@ -151,7 +156,7 @@ def get_grouper(self, groupby='run'):
             A pandas Grouper object constructed from the specified columns
                 of the current index.
         '''
-        return pd.core.groupby._get_grouper(self.index, groupby)[0]
+        return _get_grouper(self.index, groupby)[0]
 
     def apply(self, func, groupby='run', *args, **kwargs):
         ''' Applies the passed function to the groups defined by the groupby


Test patch:
diff --git a/bids/analysis/tests/test_transformations.py b/bids/analysis/tests/test_transformations.py
--- a/bids/analysis/tests/test_transformations.py
+++ b/bids/analysis/tests/test_transformations.py
@@ -7,6 +7,11 @@
 import numpy as np
 import pandas as pd
 
+try:
+    from pandas.core.groupby import _get_grouper
+except ImportError:
+    from pandas.core.groupby.groupby import _get_grouper
+
 
 @pytest.fixture
 def collection():
@@ -41,7 +46,7 @@ def test_scale(collection):
     transform.scale(collection, variables=['RT', 'parametric gain'],
                     output=['RT_Z', 'gain_Z'], groupby=['run', 'subject'])
     ents = collection['RT'].index
-    groupby = pd.core.groupby._get_grouper(ents, ['run', 'subject'])[0]
+    groupby = _get_grouper(ents, ['run', 'subject'])[0]
     z1 = collection['RT_Z'].values
     z2 = collection['RT'].values.groupby(
         groupby).apply(lambda x: (x - x.mean()) / x.std())
@@ -68,7 +73,7 @@ def test_orthogonalize_dense(collection):
     vals = np.c_[rt.values, pg_pre.values, pg_post.values]
     df = pd.DataFrame(vals, columns=['rt', 'pre', 'post'])
     ents = rt.index
-    groupby = pd.core.groupby._get_grouper(ents, ['run', 'subject'])[0]
+    groupby = _get_grouper(ents, ['run', 'subject'])[0]
     pre_r = df.groupby(groupby).apply(lambda x: x.corr().iloc[0, 1])
     post_r = df.groupby(groupby).apply(lambda x: x.corr().iloc[0, 2])
     assert (pre_r > 0.2).any()
@@ -84,7 +89,7 @@ def test_orthogonalize_sparse(collection):
     vals = np.c_[rt.values, pg_pre.values, pg_post.values]
     df = pd.DataFrame(vals, columns=['rt', 'pre', 'post'])
     ents = collection['RT'].index
-    groupby = pd.core.groupby._get_grouper(ents, ['run', 'subject'])[0]
+    groupby = _get_grouper(ents, ['run', 'subject'])[0]
     pre_r = df.groupby(groupby).apply(lambda x: x.corr().iloc[0, 1])
     post_r = df.groupby(groupby).apply(lambda x: x.corr().iloc[0, 2])
     assert (pre_r > 0.2).any()