@@ -489,25 +489,28 @@ def _binary_op(self, other, f, reflexive=False):
489
489
group = self ._original_group
490
490
name = group .name
491
491
dim = self ._group_dim
492
- # import IPython; IPython.core.debugger.set_trace()
492
+
493
493
try :
494
494
if self ._bins is not None :
495
- if self ._stacked_dim is not None :
496
- group = self ._group .unstack ()
497
- # idx = pd.factorize(group.data.ravel())[0]
498
- # group_idx = group.copy(data=idx.reshape(group.data.shape))
499
- other = other .sel ({f"{ name } _bins" : group })
500
- if isinstance (group , _DummyGroup ):
495
+ group = self ._maybe_unstack (self ._group )
496
+ other = other .sel ({f"{ name } _bins" : self ._group })
497
+ # TODO: vectorized indexing bug in .sel; name_bins is still an IndexVariable!
498
+ other [f"{ name } _bins" ] = other [f"{ name } _bins" ].variable .to_variable ()
499
+ if name == dim and dim not in obj .xindexes :
501
500
# When binning by unindexed coordinate we need to reindex obj.
502
501
# _full_index is IntervalIndex, so idx will be -1 where
503
502
# a value does not belong to any bin. Using IntervalIndex
504
503
# accounts for any non-default cut_kwargs passed to the constructor
505
504
idx = pd .cut (obj [dim ], bins = self ._full_index ).codes
506
- obj = obj .isel ({dim : np .arange (group .size )[idx != - 1 ]})
505
+ obj = obj .isel ({dim : np .arange (obj [dim ].size )[idx != - 1 ]})
506
+ else :
507
+ obj = self ._obj
508
+
507
509
else :
508
510
if isinstance (group , _DummyGroup ):
509
511
group = obj [dim ]
510
512
other = other .sel ({name : group })
513
+
511
514
except AttributeError :
512
515
raise TypeError (
513
516
"GroupBy objects only support binary ops "
@@ -523,7 +526,12 @@ def _binary_op(self, other, f, reflexive=False):
523
526
)
524
527
# some labels are absent i.e. other is not aligned
525
528
# so we align by reindexing and then rename dimensions.
526
- # TODO: probably need to copy some coordinates over
529
+ # Broadcast out scalars.
530
+ for var in other .coords :
531
+ if other [var ].ndim == 0 :
532
+ other [var ] = (
533
+ other [var ].drop (var ).expand_dims ({name : other .sizes [name ]})
534
+ )
527
535
other = (
528
536
other .reindex ({name : group .data })
529
537
.rename ({name : dim })
@@ -532,12 +540,13 @@ def _binary_op(self, other, f, reflexive=False):
532
540
533
541
result = g (obj , other )
534
542
535
- # backcompat:
536
- for var in set (obj .coords ) - set (obj .xindexes ):
537
- print (var )
538
- if dim not in obj [var ]:
539
- print (f"excluding { dim } , broadcasting { var } " )
540
- result [var ] = obj [var ].reset_coords (drop = True ).broadcast_like (result )
543
+ if group .ndim > 1 :
544
+ # backcompat:
545
+ for var in set (obj .coords ) - set (obj .xindexes ):
546
+ if set (obj [var ].dims ) < set (group .dims ):
547
+ result [var ] = obj [var ].reset_coords (drop = True ).broadcast_like (group )
548
+
549
+ result = self ._maybe_unstack (result ).transpose (* group .dims , ...)
541
550
return result
542
551
543
552
def _maybe_restore_empty_groups (self , combined ):
0 commit comments