Skip to content

Commit 88cffbe

Browse files
committed
BUG: tzinfo lost when concatenating multiindex arrays
1 parent de4a197 commit 88cffbe

File tree

5 files changed

+106
-0
lines changed

5 files changed

+106
-0
lines changed

doc/source/v0.14.1.txt

+1
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,4 @@ Bug Fixes
7070
- Bug in ``DataFrame`` and ``Series`` bar and barh plot raises ``TypeError`` when ``bottom``
7171
and ``left`` keyword is specified (:issue:`7226`)
7272
- BUG in ``DataFrame.hist`` raises ``TypeError`` when it contains non numeric column (:issue:`7277`)
73+
- Bug in ``MultiIndex.append``, ``concat`` and ``pivot_table`` don't preserve timezone (:issue:`6606`)

pandas/core/index.py

+8
Original file line numberDiff line numberDiff line change
@@ -2948,6 +2948,14 @@ def append(self, other):
29482948
if not isinstance(other, (list, tuple)):
29492949
other = [other]
29502950

2951+
if all((isinstance(o, MultiIndex) and o.nlevels >= self.nlevels) for o in other):
2952+
arrays = []
2953+
for i in range(self.nlevels):
2954+
label = self.get_level_values(i)
2955+
appended = [o.get_level_values(i) for o in other]
2956+
arrays.append(label.append(appended))
2957+
return MultiIndex.from_arrays(arrays, names=self.names)
2958+
29512959
to_concat = (self.values,) + tuple(k.values for k in other)
29522960
new_tuples = np.concatenate(to_concat)
29532961

pandas/tests/test_multilevel.py

+41
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# pylint: disable-msg=W0612,E1101,W0141
2+
import datetime
23
import nose
34

45
from numpy.random import randn
@@ -70,6 +71,46 @@ def test_append(self):
7071
result = a['A'].append(b['A'])
7172
tm.assert_series_equal(result, self.frame['A'])
7273

74+
def test_append_index(self):
75+
76+
idx1 = Index([1.1, 1.2, 1.3])
77+
idx2 = pd.date_range('2011-01-01', freq='D', periods=3, tz='Asia/Tokyo')
78+
idx3 = Index(['A', 'B', 'C'])
79+
80+
midx_lv2 = MultiIndex.from_arrays([idx1, idx2])
81+
midx_lv3 = MultiIndex.from_arrays([idx1, idx2, idx3])
82+
83+
result = idx1.append(midx_lv2)
84+
expected = Index([1.1, 1.2, 1.3,
85+
(1.1, datetime.datetime(2010, 12, 31, 15, 0)),
86+
(1.2, datetime.datetime(2011, 1, 1, 15, 0)),
87+
(1.3, datetime.datetime(2011, 1, 2, 15, 0))])
88+
self.assert_(result.equals(expected))
89+
90+
result = midx_lv2.append(idx1)
91+
expected = Index([(1.1, datetime.datetime(2010, 12, 31, 15, 0)),
92+
(1.2, datetime.datetime(2011, 1, 1, 15, 0)),
93+
(1.3, datetime.datetime(2011, 1, 2, 15, 0)),
94+
1.1, 1.2, 1.3])
95+
self.assert_(result.equals(expected))
96+
97+
result = midx_lv2.append(midx_lv2)
98+
expected = MultiIndex.from_arrays([idx1.append(idx1), idx2.append(idx2)])
99+
self.assert_(result.equals(expected))
100+
101+
result = midx_lv2.append(midx_lv3)
102+
self.assert_(result.equals(expected))
103+
104+
result = midx_lv3.append(midx_lv2)
105+
expected = Index._simple_new(
106+
np.array([(1.1, datetime.datetime(2010, 12, 31, 15, 0), 'A'),
107+
(1.2, datetime.datetime(2011, 1, 1, 15, 0), 'B'),
108+
(1.3, datetime.datetime(2011, 1, 2, 15, 0), 'C'),
109+
(1.1, datetime.datetime(2010, 12, 31, 15, 0)),
110+
(1.2, datetime.datetime(2011, 1, 1, 15, 0)),
111+
(1.3, datetime.datetime(2011, 1, 2, 15, 0))]), None)
112+
self.assert_(result.equals(expected))
113+
73114
def test_dataframe_constructor(self):
74115
multi = DataFrame(np.random.randn(4, 4),
75116
index=[np.array(['a', 'a', 'b', 'b']),

pandas/tools/tests/test_merge.py

+21
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import numpy as np
99
import random
1010

11+
import pandas as pd
1112
from pandas.compat import range, lrange, lzip, zip, StringIO
1213
from pandas import compat, _np_version_under1p7
1314
from pandas.tseries.index import DatetimeIndex
@@ -1497,6 +1498,26 @@ def test_concat_multiindex_with_keys(self):
14971498
tm.assert_frame_equal(result.ix[1], frame)
14981499
self.assertEqual(result.index.nlevels, 3)
14991500

1501+
def test_concat_multiindex_with_tz(self):
1502+
# GH 6606
1503+
df = DataFrame({'dt': [datetime(2014, 1, 1),
1504+
datetime(2014, 1, 2),
1505+
datetime(2014, 1, 3)],
1506+
'b': ['A', 'B', 'C'],
1507+
'c': [1, 2, 3], 'd': [4, 5, 6]})
1508+
df['dt'] = df['dt'].apply(lambda d: pd.Timestamp(d, tz='US/Pacific'))
1509+
df = df.set_index(['dt', 'b'])
1510+
1511+
exp_idx1 = pd.DatetimeIndex(['2014-01-01', '2014-01-02', '2014-01-03'] * 2,
1512+
tz='US/Pacific', name='dt')
1513+
exp_idx2 = Index(['A', 'B', 'C'] * 2, name='b')
1514+
exp_idx = pd.MultiIndex.from_arrays([exp_idx1, exp_idx2])
1515+
expected = DataFrame({'c': [1, 2, 3] * 2, 'd': [4, 5, 6] * 2},
1516+
index=exp_idx, columns=['c', 'd'])
1517+
1518+
result = concat([df, df])
1519+
tm.assert_frame_equal(result, expected)
1520+
15001521
def test_concat_keys_and_levels(self):
15011522
df = DataFrame(np.random.randn(1, 3))
15021523
df2 = DataFrame(np.random.randn(1, 4))

pandas/tools/tests/test_pivot.py

+35
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,41 @@ def test_pivot_timegrouper(self):
490490
values='Quantity', aggfunc=np.sum)
491491
tm.assert_frame_equal(result, expected.T)
492492

493+
def test_pivot_datetime_tz(self):
494+
dates1 = ['2011-07-19 07:00:00', '2011-07-19 08:00:00', '2011-07-19 09:00:00',
495+
'2011-07-19 07:00:00', '2011-07-19 08:00:00', '2011-07-19 09:00:00']
496+
dates2 = ['2013-01-01 15:00:00', '2013-01-01 15:00:00', '2013-01-01 15:00:00',
497+
'2013-02-01 15:00:00', '2013-02-01 15:00:00', '2013-02-01 15:00:00']
498+
df = DataFrame({'label': ['a', 'a', 'a', 'b', 'b', 'b'],
499+
'dt1': dates1, 'dt2': dates2,
500+
'value1': range(6), 'value2': [1, 2] * 3})
501+
df['dt1'] = df['dt1'].apply(lambda d: pd.Timestamp(d, tz='US/Pacific'))
502+
df['dt2'] = df['dt2'].apply(lambda d: pd.Timestamp(d, tz='Asia/Tokyo'))
503+
504+
exp_idx = pd.DatetimeIndex(['2011-07-19 07:00:00', '2011-07-19 08:00:00',
505+
'2011-07-19 09:00:00'], tz='US/Pacific', name='dt1')
506+
exp_col1 = Index(['value1', 'value1'])
507+
exp_col2 = Index(['a', 'b'], name='label')
508+
exp_col = MultiIndex.from_arrays([exp_col1, exp_col2])
509+
expected = DataFrame([[0, 3], [1, 4], [2, 5]],
510+
index=exp_idx, columns=exp_col)
511+
result = pivot_table(df, index=['dt1'], columns=['label'], values=['value1'])
512+
tm.assert_frame_equal(result, expected)
513+
514+
515+
exp_col1 = Index(['sum', 'sum', 'sum', 'sum', 'mean', 'mean', 'mean', 'mean'])
516+
exp_col2 = Index(['value1', 'value1', 'value2', 'value2'] * 2)
517+
exp_col3 = pd.DatetimeIndex(['2013-01-01 15:00:00', '2013-02-01 15:00:00'] * 4,
518+
tz='Asia/Tokyo', name='dt2')
519+
exp_col = MultiIndex.from_arrays([exp_col1, exp_col2, exp_col3])
520+
expected = DataFrame(np.array([[0, 3, 1, 2, 0, 3, 1, 2], [1, 4, 2, 1, 1, 4, 2, 1],
521+
[2, 5, 1, 2, 2, 5, 1, 2]]), index=exp_idx, columns=exp_col)
522+
523+
result = pivot_table(df, index=['dt1'], columns=['dt2'], values=['value1', 'value2'],
524+
aggfunc=[np.sum, np.mean])
525+
tm.assert_frame_equal(result, expected)
526+
527+
493528
class TestCrosstab(tm.TestCase):
494529

495530
def setUp(self):

0 commit comments

Comments
 (0)