dict(mapping)
实际上做了什么?
背景
Python的文档建议在构建dict
时有three possible paths,其中一个是Mapping
。
大熊猫系列在某些方面类似于词典,并且强制使用dict可以按预期工作:
In [27]: series=pd.Series({'a':2,'b':3})
In [28]: dict(series)
Out[28]: {'a': 2, 'b': 3}
但是当进入ChainMap
时,这就出错了:
In [25]: dict(ChainMap(series))
...我认为应该相当于第一个表达式,而是......
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/pandas/core/index.py in get_value(self, series, key)
1789 try:
-> 1790 return self._engine.get_value(s, k)
1791 except KeyError as e1:
pandas/index.pyx in pandas.index.IndexEngine.get_value (pandas/index.c:3204)()
pandas/index.pyx in pandas.index.IndexEngine.get_value (pandas/index.c:2903)()
pandas/index.pyx in pandas.index.IndexEngine.get_loc (pandas/index.c:3843)()
pandas/hashtable.pyx in pandas.hashtable.PyObjectHashTable.get_item (pandas/hashtable.c:12265)()
pandas/hashtable.pyx in pandas.hashtable.PyObjectHashTable.get_item (pandas/hashtable.c:12216)()
KeyError: 2
During handling of the above exception, another exception occurred:
IndexError Traceback (most recent call last)
<ipython-input-25-ffe959c53a67> in <module>()
----> 1 dict(ChainMap(series))
/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/collections/__init__.py in __getitem__(self, key)
865 for mapping in self.maps:
866 try:
--> 867 return mapping[key] # can't use 'key in mapping' with defaultdict
868 except KeyError:
869 pass
/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/pandas/core/series.py in __getitem__(self, key)
555 def __getitem__(self, key):
556 try:
--> 557 result = self.index.get_value(self, key)
558
559 if not np.isscalar(result):
/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/pandas/core/index.py in get_value(self, series, key)
1794
1795 try:
-> 1796 return tslib.get_value_box(s, key)
1797 except IndexError:
1798 raise
pandas/tslib.pyx in pandas.tslib.get_value_box (pandas/tslib.c:16375)()
pandas/tslib.pyx in pandas.tslib.get_value_box (pandas/tslib.c:16126)()
IndexError: index out of bounds
FWIW这确实有效:
In [29]: dict(ChainMap(dict(series)))
Out[29]: {'a': 2, 'b': 3}
...所以ChainMap
似乎在调用dict
没有调用的系列界面的部分内容。我无法解决问题,因为我似乎无法找到复制dict(mapping)
所做内容的Python代码。
答案 0 :(得分:2)
看起来系列并不是真正的映射...请注意,迭代系列会产生值,而不是键:
>>> list(series)
[2, 3]
collections.ChainMap
依赖于迭代映射应该产生密钥的事实。
显然,dict
构造函数不依赖于这个事实(IIRC,它使用.keys
方法 - pandas为其返回合适的对象)。
答案 1 :(得分:0)
虽然dict(mapping)
代码不可用(已编译),但ChainMap
的代码是纯Python。但这是dict()
的问题还是使用ChainMap
的问题?
一个更简单的情况,dict
有效但ChainMap
没有可迭代
In [569]: dict([['a','b'],[1,2]])
Out[569]: {1: 2, 'a': 'b'}
In [570]: collections.ChainMap([['a','b'],[1,2]])
Out[570]: ChainMap([['a', 'b'], [1, 2]])
In [571]: collections.ChainMap([['a','b'],[1,2]])['a']
....
TypeError: list indices must be integers, not str
In [572]: collections.ChainMap(dict([['a','b'],[1,2]]))['a']
Out[572]: 'b'
在这种情况下,ChainMap
在被要求进行索引之前不会产生错误。它收集输入列表就好了。
尝试大熊猫系列:
In [591]: ps = pd.Series(dict(a=1,b=2))
In [592]: dict(ps)
Out[592]: {'b': 2, 'a': 1}
因此系列中的dict()
会产生一个普通的字典
In [593]: collections.ChainMap(ps)
Out[593]:
ChainMap(a 1
b 2
dtype: int64)
但是这个系列的ChainMap
是什么?
In [594]: collections.ChainMap(ps)[0]
Out[594]: 1
In [595]: collections.ChainMap(ps)['a']
Out[595]: 1
看起来它可以像系列
一样编入索引In [596]: collections.ChainMap(ps).maps
Out[596]:
[a 1
b 2
dtype: int64]
它的maps
属性只是一个元素列表,包含系列本身。现阶段没有变革
In [597]: collections.ChainMap(ps).maps[0]
Out[597]:
a 1
b 2
dtype: int64
In [598]: dict(collections.ChainMap(ps).maps[0])
Out[598]: {'b': 2, 'a': 1}
我可以从这一项构建一个字典,与dict(ps)
相同。
因此dict(collections.ChainMap([dict(ps)]))
中的错误产生于将pd.series的ChainMap
转换为常规字典的深处。换句话说,dict(ChainMap(...))
的工作方式有一些细微差别。
问题的根源在于这是对ChainMap
的误用。
对系列和字典的迭代会产生不同的结果:
In [614]: list(ps.__iter__())
Out[614]: [1, 2]
In [615]: list(dict(ps).__iter__())
Out[615]: ['b', 'a']
该系列确实有keys
方法,类似于字典,但不完全相同:
In [619]: ps.keys()
Out[619]: Index(['a', 'b'], dtype='object')
In [620]: dict(ps).keys()
Out[620]: dict_keys(['b', 'a'])
__iter__
的差异可能至关重要。使用词典理解:
In [623]: dd=dict(ps); {k:dd[k] for k in dd}
Out[623]: {'b': 2, 'a': 1}
但直接将相同的内容应用于该系列,我得到(我认为)相同的index out of bounds
错误 - 它来自于尝试ps[2]
。
In [624]: dd=ps; {k:dd[k] for k in dd}
...
/usr/lib/python3/dist-packages/pandas/core/series.py in __getitem__(self, key)
500 def __getitem__(self, key):
501 try:
--> 502 result = self.index.get_value(self, key)
503
504 if not np.isscalar(result):
/usr/lib/python3/dist-packages/pandas/core/index.py in get_value(self, series, key)
1404
1405 try:
-> 1406 return tslib.get_value_box(s, key)
1407 except IndexError:
1408 raise
/usr/lib/python3/dist-packages/pandas/tslib.cpython-34m-i386-linux-gnu.so in pandas.tslib.get_value_box (pandas/tslib.c:12835)()
/usr/lib/python3/dist-packages/pandas/tslib.cpython-34m-i386-linux-gnu.so in pandas.tslib.get_value_box (pandas/tslib.c:12638)()
IndexError: index out of bounds
注意使用ChainMap
时迭代的相同差异:
In [628]: [k for k in collections.ChainMap(ps)]
Out[628]: [1, 2]
In [629]: [k for k in collections.ChainMap(dict(ps))]
Out[629]: ['b', 'a']
或等效
In [651]: list(collections.ChainMap(ps).keys())
Out[651]: [1, 2]
In [652]: list(collections.ChainMap(dict(ps)).keys())
Out[652]: ['b', 'a']
似乎dict
尝试迭代keys()
,而ChainMap
则使用__iter__
。如果来源没有keys
,那么dict
会做什么?也许这就是触发它期待一个元组列表或类似2列数组的东西:
In [656]: dict(np.arange(6).reshape(3,2))
Out[656]: {0: 1, 2: 3, 4: 5}
此类数组上的 ChainMap
可以编入索引,但无法转换为dict
:
collections.ChainMap(np.arange(6).reshape(3,2))[0]
显然ChainMap
是一个相当“薄”的包装器,围绕着它的“地图”,当它们像字典一样时表现如预期,但是像列表,ndarray和pd.series这样的迭代物可以点击。 / p>