Skip to content

Commit 43d895c

Browse files
committed
ENH: add orient option to Panel.from_dict, GH #359
1 parent 20b043b commit 43d895c

File tree

3 files changed

+41
-10
lines changed

3 files changed

+41
-10
lines changed

RELEASE.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ pandas 0.5.1
4747
- Add `Series.mad`, mean absolute deviation, matching DataFrame
4848
- Add `QuarterEnd` DateOffset (PR #321)
4949
- Add matrix multiplication function `dot` to DataFrame (GH #65)
50+
- Add `orient` option to `Panel.from_dict` to ease creation of mixed-type
51+
Panels (GH #359)
5052
5153
**Improvements to existing features**
5254

pandas/core/panel.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ def shape(self):
269269
return len(self.items), len(self.major_axis), len(self.minor_axis)
270270

271271
@classmethod
272-
def from_dict(cls, data, intersect=False, dtype=float):
272+
def from_dict(cls, data, intersect=False, orient='items', dtype=float):
273273
"""
274274
Construct Panel from dict of DataFrame objects
275275
@@ -278,11 +278,31 @@ def from_dict(cls, data, intersect=False, dtype=float):
278278
data : dict
279279
{field : DataFrame}
280280
intersect : boolean
281+
Intersect indexes of input DataFrames
282+
orient : {'items', 'minor'}, default 'items'
283+
The "orientation" of the data. If the keys of the passed dict
284+
should be the items of the result panel, pass 'items'
285+
(default). Otherwise if the columns of the values of the passed
286+
DataFrame objects should be the items (which in the case of
287+
mixed-dtype data you should do), instead pass 'minor'
288+
281289
282290
Returns
283291
-------
284292
Panel
285293
"""
294+
from collections import defaultdict
295+
296+
orient = orient.lower()
297+
if orient == 'minor':
298+
new_data = defaultdict(dict)
299+
for col, df in data.iteritems():
300+
for item, s in df.iteritems():
301+
new_data[item][col] = s
302+
data = new_data
303+
elif orient != 'items': # pragma: no cover
304+
raise ValueError('only recognize items or minor for orientation')
305+
286306
data, index, columns = _homogenize_dict(data, intersect=intersect,
287307
dtype=dtype)
288308
items = Index(sorted(data.keys()))

pandas/tests/test_panel.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
assert_series_equal,
2222
assert_almost_equal)
2323
import pandas.core.panel as panelm
24-
import pandas.util.testing as common
24+
import pandas.util.testing as tm
2525

2626
class PanelTests(object):
2727
panel = None
@@ -42,7 +42,7 @@ def test_repr(self):
4242
foo = repr(self.panel)
4343

4444
def test_iter(self):
45-
common.equalContents(list(self.panel), self.panel.items)
45+
tm.equalContents(list(self.panel), self.panel.items)
4646

4747
def test_count(self):
4848
f = lambda s: notnull(s).sum()
@@ -218,7 +218,7 @@ def _test_op(panel, op):
218218
assert_frame_equal(result['ItemA'], op(panel['ItemA'], 1))
219219

220220
def test_keys(self):
221-
common.equalContents(self.panel.keys(), self.panel.items)
221+
tm.equalContents(self.panel.keys(), self.panel.items)
222222

223223
def test_iteritems(self):
224224
"""Test panel.iteritems(), aka panel.iterkv()"""
@@ -526,8 +526,8 @@ def assert_panel_equal(x, y):
526526
assert_panel_equal(x, y)
527527

528528
def setUp(self):
529-
self.panel = common.makePanel()
530-
common.add_nans(self.panel)
529+
self.panel = tm.makePanel()
530+
tm.add_nans(self.panel)
531531

532532
def test_constructor(self):
533533
# with BlockManager
@@ -608,8 +608,17 @@ def test_ctor_dict(self):
608608
result = Panel(d, dtype=int)
609609
expected = Panel(dict((k, v.astype(int)) for k, v in d.iteritems()))
610610

611-
def test_from_dict_mixed(self):
612-
pass
611+
def test_from_dict_mixed_orient(self):
612+
df = tm.makeDataFrame()
613+
df['foo'] = 'bar'
614+
615+
data = {'k1' : df,
616+
'k2' : df}
617+
618+
panel = Panel.from_dict(data, orient='minor')
619+
620+
self.assert_(panel['foo'].values.dtype == np.object_)
621+
self.assert_(panel['A'].values.dtype == np.float64)
613622

614623
def test_values(self):
615624
self.assertRaises(Exception, Panel, np.random.randn(5, 5, 5),
@@ -872,8 +881,8 @@ def test_rename(self):
872881
class TestLongPanel(unittest.TestCase):
873882

874883
def setUp(self):
875-
panel = common.makePanel()
876-
common.add_nans(panel)
884+
panel = tm.makePanel()
885+
tm.add_nans(panel)
877886

878887
self.panel = panel.to_long()
879888
self.unfiltered_panel = panel.to_long(filter_observations=False)

0 commit comments

Comments
 (0)