Skip to content

Commit cc7037e

Browse files
committed
ENH:column-wise DataFrame.fillna
1 parent 50ae37d commit cc7037e

File tree

3 files changed

+41
-10
lines changed

3 files changed

+41
-10
lines changed

doc/source/whatsnew/v1.0.0.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,10 @@ Other enhancements
227227
- Added new writer for exporting Stata dta files in version 118, ``StataWriter118``. This format supports exporting strings containing Unicode characters (:issue:`23573`)
228228
- :meth:`Series.map` now accepts ``collections.abc.Mapping`` subclasses as a mapper (:issue:`29733`)
229229
- The ``pandas.datetime`` class is now deprecated. Import from ``datetime`` instead (:issue:`30296`)
230-
230+
- Added an experimental :attr:`~DataFrame.attrs` for storing global metadata about a dataset (:issue:`29062`)
231+
- :meth:`Timestamp.fromisocalendar` is now compatible with python 3.8 and above (:issue:`28115`)
232+
- :meth:`DataFrame.to_pickle` and :func:`read_pickle` now accept URL (:issue:`30163`)
233+
- :meth:`DataFrame.fillna` can fill NA values column-wise with a dictionary or :class:`Series` (:issue:`4514`)
231234

232235

233236
Build Changes

pandas/core/generic.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6023,14 +6023,14 @@ def fillna(
60236023
)
60246024

60256025
elif isinstance(value, (dict, ABCSeries)):
6026+
result = self if inplace else self.copy()
6027+
60266028
if axis == 1:
6027-
raise NotImplementedError(
6028-
"Currently only can fill "
6029-
"with dict/Series column "
6030-
"by column"
6031-
)
6029+
for label in self.columns:
6030+
obj = result[label]
6031+
obj.fillna(value, limit=limit, inplace=True, downcast=downcast)
6032+
return result if not inplace else None
60326033

6033-
result = self if inplace else self.copy()
60346034
for k, v in value.items():
60356035
if k not in result:
60366036
continue

pandas/tests/frame/test_missing.py

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -604,9 +604,15 @@ def test_fillna_dict_series(self):
604604
expected = df.fillna(df.max().to_dict())
605605
tm.assert_frame_equal(result, expected)
606606

607-
# disable this for now
608-
with pytest.raises(NotImplementedError, match="column by column"):
609-
df.fillna(df.max(1), axis=1)
607+
expected = DataFrame(
608+
{
609+
"a": [1.0, 1.0, 2.0, 3.0, 4.0],
610+
"b": [1.0, 2.0, 3.0, 3.0, 4.0],
611+
"c": [1.0, 1.0, 2.0, 3.0, 4.0],
612+
}
613+
)
614+
result = df.fillna(df.max(1), axis=1)
615+
tm.assert_frame_equal(expected, result)
610616

611617
def test_fillna_dataframe(self):
612618
# GH 8377
@@ -983,3 +989,25 @@ def test_interp_time_inplace_axis(self, axis):
983989
result = expected.interpolate(axis=0, method="time")
984990
expected.interpolate(axis=0, method="time", inplace=True)
985991
tm.assert_frame_equal(result, expected)
992+
993+
@pytest.mark.parametrize(
994+
"expected,fill_value",
995+
[
996+
(
997+
DataFrame([["a", "a"], ["b", 4], [5, 6]], columns=list("AB")),
998+
Series(["a", "b", "c"]),
999+
),
1000+
(
1001+
DataFrame([["a", "a"], [np.nan, 4], [5, 6]], columns=list("AB")),
1002+
{0: "a", 2: "c", 3: "d"},
1003+
),
1004+
],
1005+
)
1006+
def test_fillna_column_wise(self, expected, fill_value):
1007+
# GH 4514
1008+
df = DataFrame([[np.nan, np.nan], [np.nan, 4], [5, 6]], columns=list("AB"))
1009+
result = df.fillna(fill_value, axis=1)
1010+
tm.assert_frame_equal(expected, result)
1011+
1012+
df.fillna(fill_value, axis=1, inplace=True)
1013+
tm.assert_frame_equal(expected, df)

0 commit comments

Comments
 (0)