Skip to content

Commit 4175bf4

Browse files
committed
Merge pull request #807 from changhiskhan/master
Issue #806 DataFrame/Series.align can now specify fill_value or fill_method
2 parents aca268f + 6a1381f commit 4175bf4

File tree

4 files changed

+68
-26
lines changed

4 files changed

+68
-26
lines changed

pandas/core/frame.py

+29-19
Original file line numberDiff line numberDiff line change
@@ -1669,7 +1669,8 @@ def lookup(self, row_labels, col_labels):
16691669
#----------------------------------------------------------------------
16701670
# Reindexing and alignment
16711671

1672-
def align(self, other, join='outer', axis=None, level=None, copy=True):
1672+
def align(self, other, join='outer', axis=None, level=None, copy=True,
1673+
fill_value=None, fill_method=None):
16731674
"""
16741675
Align two DataFrame object on their index and columns with the
16751676
specified join method for each axis Index
@@ -1683,6 +1684,11 @@ def align(self, other, join='outer', axis=None, level=None, copy=True):
16831684
level : int or name
16841685
Broadcast across a level, matching Index values on the
16851686
passed MultiIndex level
1687+
copy : boolean, default True
1688+
Always returns new objects. If copy=False and no reindexing is
1689+
required then original objects are returned.
1690+
fill_value : object, default None
1691+
fill_method : str, default None
16861692
16871693
Returns
16881694
-------
@@ -1691,15 +1697,19 @@ def align(self, other, join='outer', axis=None, level=None, copy=True):
16911697
"""
16921698
if isinstance(other, DataFrame):
16931699
return self._align_frame(other, join=join, axis=axis, level=level,
1694-
copy=copy)
1700+
copy=copy,
1701+
fill_value=fill_value,
1702+
fill_method=fill_method)
16951703
elif isinstance(other, Series):
16961704
return self._align_series(other, join=join, axis=axis, level=level,
1697-
copy=copy)
1705+
copy=copy,
1706+
fill_value=fill_value,
1707+
fill_method=fill_method)
16981708
else: # pragma: no cover
16991709
raise TypeError('unsupported type: %s' % type(other))
17001710

17011711
def _align_frame(self, other, join='outer', axis=None, level=None,
1702-
copy=True):
1712+
copy=True, fill_value=None, fill_method=None):
17031713
# defaults
17041714
join_index, join_columns = None, None
17051715
ilidx, iridx = None, None
@@ -1721,10 +1731,15 @@ def _align_frame(self, other, join='outer', axis=None, level=None,
17211731
join_columns, clidx, copy)
17221732
right = other._reindex_with_indexers(join_index, iridx,
17231733
join_columns, cridx, copy)
1724-
return left, right
1734+
fill_na = (fill_value is not None) or (fill_method is not None)
1735+
if fill_na:
1736+
return (left.fillna(fill_value, method=fill_method),
1737+
right.fillna(fill_value, method=fill_method))
1738+
else:
1739+
return left, right
17251740

17261741
def _align_series(self, other, join='outer', axis=None, level=None,
1727-
copy=True):
1742+
copy=True, fill_value=None, fill_method=None):
17281743
fdata = self._data
17291744
if axis == 0:
17301745
join_index = self.index
@@ -1753,7 +1768,13 @@ def _align_series(self, other, join='outer', axis=None, level=None,
17531768

17541769
left_result = DataFrame(fdata)
17551770
right_result = other if ridx is None else other.reindex(join_index)
1756-
return left_result, right_result
1771+
1772+
fill_na = (fill_value is not None) or (fill_method is not None)
1773+
if fill_na:
1774+
return (left_result.fillna(fill_value, fill_method=fill_method),
1775+
right_result.fillna(fill_value, fill_method=fill_method))
1776+
else:
1777+
return left_result, right_result
17571778

17581779
def reindex(self, index=None, columns=None, method=None, level=None,
17591780
copy=True):
@@ -4080,18 +4101,6 @@ def _to_sdict(data, columns):
40804101
else: # pragma: no cover
40814102
raise TypeError('No logic to handle %s type' % type(data[0]))
40824103

4083-
def _list_to_sdict(data, columns):
4084-
if len(data) > 0 and isinstance(data[0], tuple):
4085-
content = list(lib.to_object_array_tuples(data).T)
4086-
elif len(data) > 0:
4087-
# list of lists
4088-
content = list(lib.to_object_array(data).T)
4089-
else:
4090-
if columns is None:
4091-
columns = []
4092-
return {}, columns
4093-
return _convert_object_array(content, columns)
4094-
40954104
def _list_of_series_to_sdict(data, columns):
40964105
from pandas.core.index import _get_combined_index
40974106

@@ -4117,6 +4126,7 @@ def _list_of_series_to_sdict(data, columns):
41174126
else:
41184127
return values, columns
41194128

4129+
41204130
def _list_of_dict_to_sdict(data, columns):
41214131
if columns is None:
41224132
gen = (x.keys() for x in data)

pandas/core/series.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -1786,7 +1786,8 @@ def apply(self, func):
17861786
mapped = lib.map_infer(self.values, func)
17871787
return Series(mapped, index=self.index, name=self.name)
17881788

1789-
def align(self, other, join='outer', level=None, copy=True):
1789+
def align(self, other, join='outer', level=None, copy=True,
1790+
fill_value=None, fill_method=None):
17901791
"""
17911792
Align two Series object with the specified join method
17921793
@@ -1800,6 +1801,8 @@ def align(self, other, join='outer', level=None, copy=True):
18001801
copy : boolean, default True
18011802
Always return new objects. If copy=False and no reindexing is
18021803
required, the same object will be returned (for better performance)
1804+
fill_value : object, default None
1805+
fill_method : str, default 'pad'
18031806
18041807
Returns
18051808
-------
@@ -1812,7 +1815,12 @@ def align(self, other, join='outer', level=None, copy=True):
18121815

18131816
left = self._reindex_indexer(join_index, lidx, copy)
18141817
right = other._reindex_indexer(join_index, ridx, copy)
1815-
return left, right
1818+
fill_na = (fill_value is not None) or (fill_method is not None)
1819+
if fill_na:
1820+
return (left.fillna(fill_value, method=fill_method),
1821+
right.fillna(fill_value, method=fill_method))
1822+
else:
1823+
return left, right
18161824

18171825
def _reindex_indexer(self, new_index, indexer, copy):
18181826
if indexer is not None:

pandas/tests/test_frame.py

+17-2
Original file line numberDiff line numberDiff line change
@@ -3190,8 +3190,15 @@ def test_align(self):
31903190

31913191
# axis = 0
31923192
other = self.frame.ix[:-5, :3]
3193-
af, bf = self.frame.align(other, axis=0)
3194-
self.assert_(bf.columns.equals(other.columns))
3193+
af, bf = self.frame.align(other, axis=0, fill_value=-1)
3194+
self.assert_(bf.columns.equals(other.columns))
3195+
#test fill value
3196+
join_idx = self.frame.index.join(other.index)
3197+
diff_a = self.frame.index.diff(join_idx)
3198+
diff_b = other.index.diff(join_idx)
3199+
diff_a_vals = af.reindex(diff_a).values
3200+
diff_b_vals = bf.reindex(diff_b).values
3201+
self.assert_((diff_a_vals == -1).all())
31953202

31963203
af, bf = self.frame.align(other, join='right', axis=0)
31973204
self.assert_(bf.columns.equals(other.columns))
@@ -3204,6 +3211,14 @@ def test_align(self):
32043211
self.assert_(bf.columns.equals(self.frame.columns))
32053212
self.assert_(bf.index.equals(other.index))
32063213

3214+
#test fill value
3215+
join_idx = self.frame.index.join(other.index)
3216+
diff_a = self.frame.index.diff(join_idx)
3217+
diff_b = other.index.diff(join_idx)
3218+
diff_a_vals = af.reindex(diff_a).values
3219+
diff_b_vals = bf.reindex(diff_b).values
3220+
self.assert_((diff_a_vals == -1).all())
3221+
32073222
af, bf = self.frame.align(other, join='inner', axis=1)
32083223
self.assert_(bf.columns.equals(other.columns))
32093224

pandas/tests/test_series.py

+12-3
Original file line numberDiff line numberDiff line change
@@ -1783,10 +1783,18 @@ def test_apply(self):
17831783
assert_series_equal(result, self.ts * 2)
17841784

17851785
def test_align(self):
1786-
def _check_align(a, b, how='left'):
1787-
aa, ab = a.align(b, join=how)
1788-
1786+
def _check_align(a, b, how='left', fill=None):
1787+
aa, ab = a.align(b, join=how, fill_value=fill)
1788+
17891789
join_index = a.index.join(b.index, how=how)
1790+
if fill is not None:
1791+
diff_a = aa.index.diff(join_index)
1792+
diff_b = ab.index.diff(join_index)
1793+
if len(diff_a) > 0:
1794+
self.assert_((aa.reindex(diff_a) == fill).all())
1795+
if len(diff_b) > 0:
1796+
self.assert_((ab.reindex(diff_b) == fill).all())
1797+
17901798
ea = a.reindex(join_index)
17911799
eb = b.reindex(join_index)
17921800

@@ -1795,6 +1803,7 @@ def _check_align(a, b, how='left'):
17951803

17961804
for kind in JOIN_TYPES:
17971805
_check_align(self.ts[2:], self.ts[:-5])
1806+
_check_align(self.ts[2:], self.ts[:-5], -1)
17981807

17991808
# empty left
18001809
_check_align(self.ts[:0], self.ts[:-5])

0 commit comments

Comments
 (0)