def nargsort(items, kind='<STR_LIT>', ascending=True, na_position='<STR_LIT>'):
<EOL>if is_categorical_dtype(items):<EOL><INDENT>if na_position not in {'<STR_LIT>', '<STR_LIT>'}:<EOL><INDENT>raise ValueError('<STR_LIT>'.format(na_position))<EOL><DEDENT>mask = isna(items)<EOL>cnt_null = mask.sum()<EOL>sorted_idx = items.argsort(ascending=ascending, kind=kind)<EOL>if ascending and na_position == '<STR_LIT>':<EOL><INDENT>sorted_idx = np.roll(sorted_idx, -cnt_null)<EOL><DEDENT>elif not ascending and na_position == '<STR_LIT>':<EOL><INDENT>sorted_idx = np.roll(sorted_idx, cnt_null)<EOL><DEDENT>return sorted_idx<EOL><DEDENT>with warnings.catch_warnings():<EOL><INDENT>warnings.filterwarnings(<EOL>"<STR_LIT:ignore>", category=FutureWarning,<EOL>message="<STR_LIT>")<EOL>items = np.asanyarray(items)<EOL><DEDENT>idx = np.arange(len(items))<EOL>mask = isna(items)<EOL>non_nans = items[~mask]<EOL>non_nan_idx = idx[~mask]<EOL>nan_idx = np.nonzero(mask)[<NUM_LIT:0>]<EOL>if not ascending:<EOL><INDENT>non_nans = non_nans[::-<NUM_LIT:1>]<EOL>non_nan_idx = non_nan_idx[::-<NUM_LIT:1>]<EOL><DEDENT>indexer = non_nan_idx[non_nans.argsort(kind=kind)]<EOL>if not ascending:<EOL><INDENT>indexer = indexer[::-<NUM_LIT:1>]<EOL><DEDENT>if na_position == '<STR_LIT>':<EOL><INDENT>indexer = np.concatenate([indexer, nan_idx])<EOL><DEDENT>elif na_position == '<STR_LIT>':<EOL><INDENT>indexer = np.concatenate([nan_idx, indexer])<EOL><DEDENT>else:<EOL><INDENT>raise ValueError('<STR_LIT>'.format(na_position))<EOL><DEDENT>return indexer<EOL>
This is intended to be a drop-in replacement for np.argsort which
handles NaNs. It adds ascending and na_position parameters.
GH #6399, #5231