@@ -1520,15 +1520,21 @@ def from_dict(
1520
1520
----------
1521
1521
data : dict
1522
1522
Of the form {field : array-like} or {field : dict}.
1523
- orient : {'columns', 'index'}, default 'columns'
1523
+ orient : {'columns', 'index', 'tight' }, default 'columns'
1524
1524
The "orientation" of the data. If the keys of the passed dict
1525
1525
should be the columns of the resulting DataFrame, pass 'columns'
1526
1526
(default). Otherwise if the keys should be rows, pass 'index'.
1527
+ If 'tight', assume a dict with keys ['index', 'columns', 'data',
1528
+ 'index_names', 'column_names'].
1529
+
1530
+ .. versionadded:: 1.4.0
1531
+ 'tight' as an allowed value for the ``orient`` argument
1532
+
1527
1533
dtype : dtype, default None
1528
1534
Data type to force, otherwise infer.
1529
1535
columns : list, default None
1530
1536
Column labels to use when ``orient='index'``. Raises a ValueError
1531
- if used with ``orient='columns'``.
1537
+ if used with ``orient='columns'`` or ``orient='tight'`` .
1532
1538
1533
1539
Returns
1534
1540
-------
@@ -1539,6 +1545,7 @@ def from_dict(
1539
1545
DataFrame.from_records : DataFrame from structured ndarray, sequence
1540
1546
of tuples or dicts, or DataFrame.
1541
1547
DataFrame : DataFrame object creation using constructor.
1548
+ DataFrame.to_dict : Convert the DataFrame to a dictionary.
1542
1549
1543
1550
Examples
1544
1551
--------
@@ -1569,6 +1576,21 @@ def from_dict(
1569
1576
A B C D
1570
1577
row_1 3 2 1 0
1571
1578
row_2 a b c d
1579
+
1580
+ Specify ``orient='tight'`` to create the DataFrame using a 'tight'
1581
+ format:
1582
+
1583
+ >>> data = {'index': [('a', 'b'), ('a', 'c')],
1584
+ ... 'columns': [('x', 1), ('y', 2)],
1585
+ ... 'data': [[1, 3], [2, 4]],
1586
+ ... 'index_names': ['n1', 'n2'],
1587
+ ... 'column_names': ['z1', 'z2']}
1588
+ >>> pd.DataFrame.from_dict(data, orient='tight')
1589
+ z1 x y
1590
+ z2 1 2
1591
+ n1 n2
1592
+ a b 1 3
1593
+ c 2 4
1572
1594
"""
1573
1595
index = None
1574
1596
orient = orient .lower ()
@@ -1579,13 +1601,28 @@ def from_dict(
1579
1601
data = _from_nested_dict (data )
1580
1602
else :
1581
1603
data , index = list (data .values ()), list (data .keys ())
1582
- elif orient == "columns" :
1604
+ elif orient == "columns" or orient == "tight" :
1583
1605
if columns is not None :
1584
- raise ValueError ("cannot use columns parameter with orient='columns '" )
1606
+ raise ValueError (f "cannot use columns parameter with orient='{ orient } '" )
1585
1607
else : # pragma: no cover
1586
1608
raise ValueError ("only recognize index or columns for orient" )
1587
1609
1588
- return cls (data , index = index , columns = columns , dtype = dtype )
1610
+ if orient != "tight" :
1611
+ return cls (data , index = index , columns = columns , dtype = dtype )
1612
+ else :
1613
+ realdata = data ["data" ]
1614
+
1615
+ def create_index (indexlist , namelist ):
1616
+ index : Index
1617
+ if len (namelist ) > 1 :
1618
+ index = MultiIndex .from_tuples (indexlist , names = namelist )
1619
+ else :
1620
+ index = Index (indexlist , name = namelist [0 ])
1621
+ return index
1622
+
1623
+ index = create_index (data ["index" ], data ["index_names" ])
1624
+ columns = create_index (data ["columns" ], data ["column_names" ])
1625
+ return cls (realdata , index = index , columns = columns , dtype = dtype )
1589
1626
1590
1627
def to_numpy (
1591
1628
self ,
@@ -1675,13 +1712,19 @@ def to_dict(self, orient: str = "dict", into=dict):
1675
1712
- 'series' : dict like {column -> Series(values)}
1676
1713
- 'split' : dict like
1677
1714
{'index' -> [index], 'columns' -> [columns], 'data' -> [values]}
1715
+ - 'tight' : dict like
1716
+ {'index' -> [index], 'columns' -> [columns], 'data' -> [values],
1717
+ 'index_names' -> [index.names], 'column_names' -> [column.names]}
1678
1718
- 'records' : list like
1679
1719
[{column -> value}, ... , {column -> value}]
1680
1720
- 'index' : dict like {index -> {column -> value}}
1681
1721
1682
1722
Abbreviations are allowed. `s` indicates `series` and `sp`
1683
1723
indicates `split`.
1684
1724
1725
+ .. versionadded:: 1.4.0
1726
+ 'tight' as an allowed value for the ``orient`` argument
1727
+
1685
1728
into : class, default dict
1686
1729
The collections.abc.Mapping subclass used for all Mappings
1687
1730
in the return value. Can be the actual class or an empty
@@ -1731,6 +1774,10 @@ def to_dict(self, orient: str = "dict", into=dict):
1731
1774
>>> df.to_dict('index')
1732
1775
{'row1': {'col1': 1, 'col2': 0.5}, 'row2': {'col1': 2, 'col2': 0.75}}
1733
1776
1777
+ >>> df.to_dict('tight')
1778
+ {'index': ['row1', 'row2'], 'columns': ['col1', 'col2'],
1779
+ 'data': [[1, 0.5], [2, 0.75]], 'index_names': [None], 'column_names': [None]}
1780
+
1734
1781
You can also specify the mapping type.
1735
1782
1736
1783
>>> from collections import OrderedDict, defaultdict
@@ -1807,6 +1854,23 @@ def to_dict(self, orient: str = "dict", into=dict):
1807
1854
)
1808
1855
)
1809
1856
1857
+ elif orient == "tight" :
1858
+ return into_c (
1859
+ (
1860
+ ("index" , self .index .tolist ()),
1861
+ ("columns" , self .columns .tolist ()),
1862
+ (
1863
+ "data" ,
1864
+ [
1865
+ list (map (maybe_box_native , t ))
1866
+ for t in self .itertuples (index = False , name = None )
1867
+ ],
1868
+ ),
1869
+ ("index_names" , list (self .index .names )),
1870
+ ("column_names" , list (self .columns .names )),
1871
+ )
1872
+ )
1873
+
1810
1874
elif orient == "series" :
1811
1875
return into_c ((k , v ) for k , v in self .items ())
1812
1876
0 commit comments