Skip to content

Commit 73c4fd3

Browse files
committed
Added code for group_fillna
1 parent dfcb534 commit 73c4fd3

File tree

1 file changed

+70
-1
lines changed

1 file changed

+70
-1
lines changed

pandas/_libs/groupby_helper.pxi.in

+70-1
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ def group_ohlc_{{name}}(ndarray[{{dest_type2}}, ndim=2] out,
317317
{{endfor}}
318318

319319
#----------------------------------------------------------------------
320-
# group_nth, group_last, group_rank
320+
# group_nth, group_last, group_rank, group_fillna
321321
#----------------------------------------------------------------------
322322

323323
{{py:
@@ -618,6 +618,75 @@ def group_rank_{{name}}(ndarray[float64_t, ndim=2] out,
618618
for i in range(N):
619619
out[i, 0] = out[i, 0] / grp_sizes[i, 0]
620620
{{endif}}
621+
622+
@cython.wraparound(False)
623+
@cython.boundscheck(False)
624+
def group_fillna_{{name}}(ndarray[{{dest_type2}}, ndim=2] out,
625+
ndarray[{{c_type}}, ndim=2] values,
626+
ndarray[int64_t] labels,
627+
object method,
628+
int64_t limit):
629+
"""Fills values forwards or backwards within a group
630+
631+
Parameters
632+
----------
633+
out : array of {{dest_type2}} values which this method will write its
634+
results to
635+
values : array of {{c_type}} values which may require filling
636+
labels : array containing unique label for each group, with its ordering
637+
matching up to the corresponding record in `values`
638+
method : {'ffill', 'bfill'}
639+
Direction for fill to be applied (forwards or backwards, respectively)
640+
limit : Consecutive values to fill before stopping, or -1 for no limit
641+
642+
Notes
643+
-----
644+
This method modifies the `out` parameter rather than returning an object
645+
"""
646+
cdef:
647+
Py_ssize_t i, N
648+
ndarray[uint8_t] mask
649+
ndarray[int64_t] sorted_labels
650+
{{dest_type2}} curr_fill_val = {{nan_val}}
651+
int64_t idx, filled_vals=0
652+
653+
N, K = (<object> values).shape
654+
655+
{{if name=='int64'}}
656+
mask = (values[:, 0] == {{nan_val}}).astype(np.uint8)
657+
{{elif name=='object'}}
658+
mask = np.array([x != x for x in values[:, 0]]).astype(np.uint8)
659+
{{else}}
660+
mask = np.isnan(values[:, 0]).astype(np.uint8)
661+
{{endif}}
662+
663+
sorted_labels = np.argsort(labels)
664+
if method == 'bfill':
665+
sorted_labels[::-1].sort()
666+
667+
{{if name == 'object'}}
668+
if True: # make templating happy
669+
{{else}}
670+
with nogil:
671+
{{endif}}
672+
for i in range(N):
673+
idx = sorted_labels[i]
674+
if mask[idx]: # is missing
675+
if limit == -1 or filled_vals < limit:
676+
out[idx, 0] = curr_fill_val
677+
else:
678+
out[idx, 0] == {{nan_val}}
679+
filled_vals += 1
680+
else: # reset items when not missing
681+
filled_vals = 0
682+
curr_fill_val = values[idx, 0]
683+
out[idx, 0] = values[idx, 0]
684+
685+
# If we move to the next group, reset
686+
# the fill_val and counter
687+
if i == N - 1 or labels[idx] != labels[sorted_labels[i+1]]:
688+
curr_fill_val = {{nan_val}}
689+
filled_vals = 0
621690
{{endfor}}
622691

623692

0 commit comments

Comments
 (0)