Skip to content

Commit cf673a4

Browse files
committed
ENH: add na_action='ignore' option to Series.map close #1661
1 parent e32ccf9 commit cf673a4

File tree

4 files changed

+62
-3
lines changed

4 files changed

+62
-3
lines changed

RELEASE.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pandas 0.8.2
3636
- Add ``flags`` option for ``re.compile`` in some Series.str methods (#1659)
3737
- Parsing of UTC date strings in read_* functions (#1693)
3838
- Handle generator input to Series (#1679)
39+
- Add `na_action='ignore'` to Series.map to quietly propagate NAs (#1661)
3940

4041
**API Changes**
4142

pandas/core/series.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,14 +1900,16 @@ def unstack(self, level=-1):
19001900
#----------------------------------------------------------------------
19011901
# function application
19021902

1903-
def map(self, arg):
1903+
def map(self, arg, na_action=None):
19041904
"""
19051905
Map values of Series using input correspondence (which can be
19061906
a dict, Series, or function)
19071907
19081908
Parameters
19091909
----------
19101910
arg : function, dict, or Series
1911+
na_action : {None, 'ignore'}
1912+
If 'ignore', propagate NA values
19111913
19121914
Examples
19131915
--------
@@ -1931,15 +1933,24 @@ def map(self, arg):
19311933
y : Series
19321934
same index as caller
19331935
"""
1936+
values = self.values
1937+
1938+
if na_action == 'ignore':
1939+
mask = isnull(values)
1940+
def map_f(values, f):
1941+
return lib.map_infer_mask(values, f, mask.view(np.uint8))
1942+
else:
1943+
map_f = lib.map_infer
1944+
19341945
if isinstance(arg, (dict, Series)):
19351946
if isinstance(arg, dict):
19361947
arg = Series(arg)
19371948

1938-
indexer = arg.index.get_indexer(self.values)
1949+
indexer = arg.index.get_indexer(values)
19391950
new_values = com.take_1d(arg.values, indexer)
19401951
return Series(new_values, index=self.index, name=self.name)
19411952
else:
1942-
mapped = lib.map_infer(self.values, arg)
1953+
mapped = map_f(values, arg)
19431954
return Series(mapped, index=self.index, name=self.name)
19441955

19451956
def apply(self, func, convert_dtype=True):

pandas/src/inference.pyx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,45 @@ def maybe_convert_bool(ndarray[object] arr):
664664
return result.view(np.bool_)
665665

666666

667+
def map_infer_mask(ndarray arr, object f, ndarray[uint8_t] mask,
668+
bint convert=1):
669+
'''
670+
Substitute for np.vectorize with pandas-friendly dtype inference
671+
672+
Parameters
673+
----------
674+
arr : ndarray
675+
f : function
676+
677+
Returns
678+
-------
679+
mapped : ndarray
680+
'''
681+
cdef:
682+
Py_ssize_t i, n
683+
ndarray[object] result
684+
object val
685+
686+
n = len(arr)
687+
result = np.empty(n, dtype=object)
688+
for i in range(n):
689+
if mask[i]:
690+
val = util.get_value_at(arr, i)
691+
else:
692+
val = f(util.get_value_at(arr, i))
693+
694+
# unbox 0-dim arrays, GH #690
695+
if is_array(val) and PyArray_NDIM(val) == 0:
696+
# is there a faster way to unbox?
697+
val = val.item()
698+
699+
result[i] = val
700+
701+
if convert:
702+
return maybe_convert_objects(result, try_float=0,
703+
convert_datetime=0)
704+
705+
return result
667706
def map_infer(ndarray arr, object f, bint convert=1):
668707
'''
669708
Substitute for np.vectorize with pandas-friendly dtype inference
@@ -700,6 +739,7 @@ def map_infer(ndarray arr, object f, bint convert=1):
700739

701740
return result
702741

742+
703743
def to_object_array(list rows):
704744
cdef:
705745
Py_ssize_t i, j, n, k, tmp

pandas/tests/test_series.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2295,6 +2295,13 @@ def test_map_decimal(self):
22952295
self.assert_(result.dtype == np.object_)
22962296
self.assert_(isinstance(result[0], Decimal))
22972297

2298+
def test_map_na_exclusion(self):
2299+
s = Series([1.5, np.nan, 3, np.nan, 5])
2300+
2301+
result = s.map(lambda x: x * 2, na_action='ignore')
2302+
exp = s * 2
2303+
assert_series_equal(result, exp)
2304+
22982305
def test_apply(self):
22992306
assert_series_equal(self.ts.apply(np.sqrt), np.sqrt(self.ts))
23002307

0 commit comments

Comments
 (0)