Skip to content

Commit 67c57e8

Browse files
committed
ENH: Provide dict object for to_dict() pandas-dev#16122
1 parent 73acea0 commit 67c57e8

File tree

5 files changed

+72
-14
lines changed

5 files changed

+72
-14
lines changed

doc/source/whatsnew/v0.20.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,7 @@ Other Enhancements
515515
- Options added to allow one to turn on/off using ``bottleneck`` and ``numexpr``, see :ref:`here <basics.accelerate>` (:issue:`16157`)
516516
- ``DataFrame.style.bar()`` now accepts two more options to further customize the bar chart. Bar alignment is set with ``align='left'|'mid'|'zero'``, the default is "left", which is backward compatible; You can now pass a list of ``color=[color_negative, color_positive]``. (:issue:`14757`)
517517

518+
518519
.. _ISO 8601 duration: https://en.wikipedia.org/wiki/ISO_8601#Durations
519520

520521

pandas/core/common.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -481,10 +481,12 @@ def _dict_compat(d):
481481
for key, value in iteritems(d))
482482

483483

484-
def _standardize_mapping(into):
484+
def prep_maping_for_to_dict(into):
485485
"""
486486
Helper function to standardize the supplied mapping so it can
487487
be passed to the ``Series.to_dict()`` and ``DataFrame.to_dict()``
488+
489+
.. versionadded:: 0.21.0
488490
489491
Parameters
490492
----------
@@ -504,11 +506,11 @@ def _standardize_mapping(into):
504506
if len(into) > 0:
505507
raise ValueError(
506508
"to_dict() only accepts empty mappings.")
507-
elif type(into) == collections.defaultdict:
509+
elif isinstance(into, collections.defaultdict):
508510
return partial(
509511
collections.defaultdict, into.default_factory)
510512
else:
511-
return _standardize_mapping(type(into))
513+
return prep_maping_for_to_dict(type(into))
512514
elif not issubclass(into, collections.Mapping):
513515
raise TypeError('unsupported type: {}'.format(into))
514516
elif into == collections.defaultdict:

pandas/core/frame.py

+42-2
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
_values_from_object,
6565
_maybe_box_datetimelike,
6666
_dict_compat,
67-
_standardize_mapping)
67+
prep_maping_for_to_dict)
6868
from pandas.core.generic import NDFrame, _shared_docs
6969
from pandas.core.index import Index, MultiIndex, _ensure_index
7070
from pandas.core.indexing import (maybe_droplevels, convert_to_index_sliceable,
@@ -889,19 +889,59 @@ def to_dict(self, orient='dict', into=dict):
889889
instance of the mapping type you want. If you want a
890890
collections.defaultdict, you must pass an initialized
891891
instance.
892+
892893
.. versionadded:: 0.21.0
893894
894895
Returns
895896
-------
896897
result : collections.Mapping like {column -> {index -> value}}
897898
If ``into`` is collections.defaultdict, the return
898899
value's default_factory will be None.
900+
901+
Examples
902+
--------
903+
>>> from pandas import DataFrame
904+
>>> from collections import OrderedDict, defaultdict
905+
>>> df = DataFrame({'col1': [1, 2], 'col2': [0.5, 0.75]}, index=['a', 'b'])
906+
>>> df
907+
col1 col2
908+
a 1 0.1
909+
b 2 0.2
910+
>>> df.to_dict()
911+
{'col1': {'a': 1, 'b': 2}, 'col2': {'a': 0.5, 'b': 0.75}}
912+
913+
You can specify the return orientation.
914+
915+
>>> df.to_dict('series')
916+
{'col1': a 1
917+
b 2
918+
Name: col1, dtype: int64, 'col2': a 0.50
919+
b 0.75
920+
Name: col2, dtype: float64}
921+
>>> df.to_dict('split')
922+
{'columns': ['col1', 'col2'],
923+
'data': [[1.0, 0.5], [2.0, 0.75]],
924+
'index': ['a', 'b']}
925+
>>> df.to_dict('records')
926+
[{'col1': 1.0, 'col2': 0.5}, {'col1': 2.0, 'col2': 0.75}]
927+
>>> df.to_dict('index')
928+
{'a': {'col1': 1.0, 'col2': 0.5}, 'b': {'col1': 2.0, 'col2': 0.75}}
929+
930+
You can also specify the mapping type.
931+
932+
>>> df.to_dict(into=OrderedDict)
933+
OrderedDict([('col2', OrderedDict([('a', 0.5), ('b', 0.75)])),
934+
('col1', OrderedDict([('a', 1), ('b', 2)]))])
935+
>>> dd = defaultdict(list)
936+
>>> df.to_dict('records', into=dd)
937+
[defaultdict(list, {'col1': 1.0, 'col2': 0.5}),
938+
defaultdict(list, {'col1': 2.0, 'col2': 0.75})]
899939
"""
900940
if not self.columns.is_unique:
901941
warnings.warn("DataFrame columns are not unique, some "
902942
"columns will be omitted.", UserWarning)
903943
# GH16122
904-
into_c = _standardize_mapping(into)
944+
into_c = prep_maping_for_to_dict(into)
905945
if orient.lower().startswith('d'):
906946
return into_c(
907947
(k, v.to_dict(into)) for k, v in compat.iteritems(self))

pandas/core/series.py

+17-2
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
SettingWithCopyError,
4848
_maybe_box_datetimelike,
4949
_dict_compat,
50-
_standardize_mapping)
50+
prep_maping_for_to_dict)
5151
from pandas.core.index import (Index, MultiIndex, InvalidIndexError,
5252
Float64Index, _ensure_index)
5353
from pandas.core.indexing import check_bool_indexer, maybe_convert_indices
@@ -1085,16 +1085,31 @@ def to_dict(self, into=dict):
10851085
object. Can be the actual class or an empty
10861086
instance of the mapping type you want. If you want a
10871087
collections.defaultdict, you must pass an initialized
1088+
10881089
.. versionadded:: 0.21.0
10891090
10901091
Returns
10911092
-------
10921093
value_dict : collections.Mapping
10931094
If ``into`` is collections.defaultdict, the return
10941095
value's default_factory will be None.
1096+
1097+
Examples
1098+
--------
1099+
>>> from pandas import Series
1100+
>>> from collections import OrderedDict, defaultdict
1101+
>>> s = Series([1, 2, 3, 4])
1102+
>>> s.to_dict()
1103+
{0: 1, 1: 2, 2: 3, 3: 4}
1104+
>>> s.to_dict(OrderedDict)
1105+
OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1106+
>>> dd = defaultdict(list)
1107+
>>> s.to_dict(dd)
1108+
defaultdict(list, {0: 1, 1: 2, 2: 3, 3: 4})
1109+
10951110
"""
10961111
# GH16122
1097-
into_c = _standardize_mapping(into)
1112+
into_c = prep_maping_for_to_dict(into)
10981113
return into_c(compat.iteritems(self))
10991114

11001115
def to_frame(self, name=None):

pandas/tests/test_common.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -199,26 +199,26 @@ def test_dict_compat():
199199
assert (com._dict_compat(data_unchanged) == data_unchanged)
200200

201201

202-
def test_standardize_mapping():
202+
def test_prep_maping_for_to_dict():
203203
# No non-empty
204204
bad = {'bad': 'data'}
205205
with pytest.raises(ValueError):
206-
com._standardize_mapping(bad)
206+
com.prep_maping_for_to_dict(bad)
207207

208208
# No uninitialized defaultdicts
209209
with pytest.raises(TypeError):
210-
com._standardize_mapping(collections.defaultdict)
210+
com.prep_maping_for_to_dict(collections.defaultdict)
211211

212212
# No non-mapping subtypes, instance
213213
with pytest.raises(TypeError):
214-
com._standardize_mapping([])
214+
com.prep_maping_for_to_dict([])
215215

216216
# No non-mapping subtypes, class
217217
with pytest.raises(TypeError):
218-
com._standardize_mapping(list)
218+
com.prep_maping_for_to_dict(list)
219219

220220
# Convert instance to type
221-
assert (com._standardize_mapping({}) == dict)
221+
assert (com.prep_maping_for_to_dict({}) == dict)
222222

223223
dd = collections.defaultdict(list)
224-
assert (type(com._standardize_mapping(dd)) == partial)
224+
assert (type(com.prep_maping_for_to_dict(dd)) == partial)

0 commit comments

Comments
 (0)