将字符串转换为 dict,然后访问 key:values???如何在 Python 的<类“dict”>中访问数据?

Convert string to dict, then access key:values??? How to access data in a <class 'dict'> for Python?

提问人:Linwoodc3 提问时间:8/26/2016 最后编辑:Linwoodc3 更新时间:11/12/2019 访问量:44714

问:

我在访问字典中的数据时遇到问题。

系统:Macbook 2012
Python:Python 3.5.1 :: Continuum Analytics, Inc.

我正在使用从 csv 创建的 dask.dataframe

编辑问题

我是怎么走到这一步的

假设我从熊猫系列开始:

df.Coordinates
130      {u'type': u'Point', u'coordinates': [-43.30175...
278      {u'type': u'Point', u'coordinates': [-51.17913...
425      {u'type': u'Point', u'coordinates': [-43.17986...
440      {u'type': u'Point', u'coordinates': [-51.16376...
877      {u'type': u'Point', u'coordinates': [-43.17986...
1313     {u'type': u'Point', u'coordinates': [-49.72688...
1734     {u'type': u'Point', u'coordinates': [-43.57405...
1817     {u'type': u'Point', u'coordinates': [-43.77649...
1835     {u'type': u'Point', u'coordinates': [-43.17132...
2739     {u'type': u'Point', u'coordinates': [-43.19583...
2915     {u'type': u'Point', u'coordinates': [-43.17986...
3035     {u'type': u'Point', u'coordinates': [-51.01583...
3097     {u'type': u'Point', u'coordinates': [-43.17891...
3974     {u'type': u'Point', u'coordinates': [-8.633880...
3983     {u'type': u'Point', u'coordinates': [-46.64960...
4424     {u'type': u'Point', u'coordinates': [-43.17986...

问题是,这不是字典的真实数据帧。相反,它是一个充满字符串的列,看起来像字典。运行此显示它:

df.Coordinates.apply(type)
130      <class 'str'>
278      <class 'str'>
425      <class 'str'>
440      <class 'str'>
877      <class 'str'>
1313     <class 'str'>
1734     <class 'str'>
1817     <class 'str'>
1835     <class 'str'>
2739     <class 'str'>
2915     <class 'str'>
3035     <class 'str'>
3097     <class 'str'>
3974     <class 'str'>
3983     <class 'str'>
4424     <class 'str'>

我的目标:访问字典中的键和值。就是这样。但这是一个coordinatesstr

我使用将字符串转换为字典。eval

new = df.Coordinates.apply(eval)
130      {'coordinates': [-43.301755, -22.990065], 'typ...
278      {'coordinates': [-51.17913026, -30.01201896], ...
425      {'coordinates': [-43.17986794, -22.91000096], ...
440      {'coordinates': [-51.16376782, -29.95488677], ...
877      {'coordinates': [-43.17986794, -22.91000096], ...
1313     {'coordinates': [-49.72688407, -29.33757253], ...
1734     {'coordinates': [-43.574057, -22.928059], 'typ...
1817     {'coordinates': [-43.77649254, -22.86940539], ...
1835     {'coordinates': [-43.17132318, -22.90895217], ...
2739     {'coordinates': [-43.1958313, -22.98755333], '...
2915     {'coordinates': [-43.17986794, -22.91000096], ...
3035     {'coordinates': [-51.01583481, -29.63593292], ...
3097     {'coordinates': [-43.17891379, -22.96476163], ...
3974     {'coordinates': [-8.63388008, 41.14594453], 't...
3983     {'coordinates': [-46.64960938, -23.55902666], ...
4424     {'coordinates': [-43.17986794, -22.91000096], ...

接下来,我给对象类型发短信并得到:

130      <class 'dict'>
278      <class 'dict'>
425      <class 'dict'>
440      <class 'dict'>
877      <class 'dict'>
1313     <class 'dict'>
1734     <class 'dict'>
1817     <class 'dict'>
1835     <class 'dict'>
2739     <class 'dict'>
2915     <class 'dict'>
3035     <class 'dict'>
3097     <class 'dict'>
3974     <class 'dict'>
3983     <class 'dict'>
4424     <class 'dict'>

如果我尝试访问我的词典: new.apply(lambda x: x['坐标']

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-71-c0ad459ed1cc> in <module>()
----> 1 dfCombined.Coordinates.apply(coord_getter)

/Users/linwood/anaconda/envs/dataAnalysisWithPython/lib/python3.5/site-packages/pandas/core/series.py in apply(self, func, convert_dtype, args, **kwds)
   2218         else:
   2219             values = self.asobject
-> 2220             mapped = lib.map_infer(values, f, convert=convert_dtype)
   2221 
   2222         if len(mapped) and isinstance(mapped[0], Series):

pandas/src/inference.pyx in pandas.lib.map_infer (pandas/lib.c:62658)()

<ipython-input-68-748ce2d8529e> in coord_getter(row)
      1 import ast
      2 def coord_getter(row):
----> 3     return (ast.literal_eval(row))['coordinates']

TypeError: 'bool' object is not subscriptable

这是某种类型的类,因为当我运行时,我得到了一个对象的这个:dir

new.apply(lambda x: dir(x))[130]
130           __class__
130        __contains__
130         __delattr__
130         __delitem__
130             __dir__
130             __doc__
130              __eq__
130          __format__
130              __ge__
130    __getattribute__
130         __getitem__
130              __gt__
130            __hash__
130            __init__
130            __iter__
130              __le__
130             __len__
130              __lt__
130              __ne__
130             __new__
130          __reduce__
130       __reduce_ex__
130            __repr__
130         __setattr__
130         __setitem__
130          __sizeof__
130             __str__
130    __subclasshook__
130               clear
130                copy
130            fromkeys
130                 get
130               items
130                keys
130                 pop
130             popitem
130          setdefault
130              update
130              values
Name: Coordinates, dtype: object

我的问题:我只想访问字典。但是,对象是 .如何将其转换为常规字典或仅访问键:值对?<class 'dict'>

有什么想法吗??

Python Pandas 字典 数据操作 dask

评论

0赞 Blckknght 8/27/2016
您显示的异常与您所说的导致异常的代码不匹配。它显示了一个函数,该函数与您之前显示的功能不太相同。coord_getterlambda
0赞 bananafish 8/27/2016
您是否自己将 csv 读取到数据帧中?这个问题似乎可以通过首先改进从 csv 中读取数据的方式来解决。

答:

0赞 piRSquared 8/26/2016 #1

看起来你最终会得到这样的东西

s = pd.Series([
        dict(type='Point', coordinates=[1, 1]),
        dict(type='Point', coordinates=[1, 2]),
        dict(type='Point', coordinates=[1, 3]),
        dict(type='Point', coordinates=[1, 4]),
        dict(type='Point', coordinates=[1, 5]),
        dict(type='Point', coordinates=[2, 1]),
        dict(type='Point', coordinates=[2, 2]),
        dict(type='Point', coordinates=[2, 3]),        
    ])

s

0    {u'type': u'Point', u'coordinates': [1, 1]}
1    {u'type': u'Point', u'coordinates': [1, 2]}
2    {u'type': u'Point', u'coordinates': [1, 3]}
3    {u'type': u'Point', u'coordinates': [1, 4]}
4    {u'type': u'Point', u'coordinates': [1, 5]}
5    {u'type': u'Point', u'coordinates': [2, 1]}
6    {u'type': u'Point', u'coordinates': [2, 2]}
7    {u'type': u'Point', u'coordinates': [2, 3]}
dtype: object

溶液

df = s.apply(pd.Series)
df

enter image description here

然后访问坐标

df.coordinates

0    [1, 1]
1    [1, 2]
2    [1, 3]
3    [1, 4]
4    [1, 5]
5    [2, 1]
6    [2, 2]
7    [2, 3]
Name: coordinates, dtype: object

甚至

df.coordinates.apply(pd.Series)

enter image description here

评论

0赞 Linwoodc3 8/27/2016
感谢您@piRSquared帮助,但这给了我同样的错误。我在上面添加了更多信息。当我在对象上运行时,它是某种类型的类。 有什么建议吗?dir
7赞 andrew 8/27/2016 #2

我的第一反应是用 将字符串转换为字典。但是您发布的示例不遵循 json 标准,因为它使用单引号而不是双引号。因此,您必须先转换字符串。json.loads

第二种选择是仅使用正则表达式来解析字符串。如果您实际 DataFrame 中的 dict 字符串与我的示例不完全匹配,我希望正则表达式方法更加健壮,因为纬度/经度坐标相当标准。

import re
import pandasd as pd

df = pd.DataFrame(data={'Coordinates':["{u'type': u'Point', u'coordinates': [-43.30175, 123.45]}",
    "{u'type': u'Point', u'coordinates': [-51.17913, 123.45]}"],
    'idx': [130, 278]})


##
# Solution 1- use json.loads
##

def string_to_dict(dict_string):
    # Convert to proper json format
    dict_string = dict_string.replace("'", '"').replace('u"', '"')
    return json.loads(dict_string)

df.CoordDicts = df.Coordinates.apply(string_to_dict)
df.CoordDicts[0]['coordinates']
#>>> [-43.30175, 123.45]


##
# Solution 2 - use regex
##
def get_lat_lon(dict_string):
    # Get the coordinates string with regex
    rs = re.search("(\-?\d+(\.\d+)?),\s*(\-?\d+(\.\d+)?)", dict_string).group()
    # Cast to floats
    coords = [float(x) for x in rs.split(',')]
    return coords

df.Coords = df.Coordinates.apply(get_lat_lon)
df.Coords[0]
#>>> [-43.30175, 123.45]

评论

0赞 andrew 8/27/2016
@Linwoodc3,仅供参考,在我的系统上,您的使用方法适用于我的示例 DataFrame。我正在使用 Python 2.7。尽管存在版本差异,但我希望正则表达式解决方案仍然有效。eval
0赞 Linwoodc3 9/5/2016
对不起,刚回来。会检查!
0赞 Linwoodc3 9/6/2016
再次出现错误。“TypeError:预期的字符串或类似字节的对象”
0赞 szeitlin 1/20/2022
因此,引号的 string.replace 后跟 json.loads 在我的情况下有效。但是,我认为这不应该发生 - 就我而言,原始数据的格式正确为字典,只有在我将其写入 CSV 并读回后才被强制转换为字符串。
12赞 PySeeker 9/29/2019 #3

刚刚遇到了这个问题。我的解决方案:

import ast
import pandas as pd

df = pd.DataFrame(["{u'type': u'Point', u'coordinates': [-43,144]}","{u'type': u'Point', u'coordinates': [-34,34]}","{u'type': u'Point', u'coordinates': [-102,344]}"],columns=["Coordinates"])

df = df["Coordinates"].astype('str')
df = df.apply(lambda x: ast.literal_eval(x))
df = df.apply(pd.Series)
2赞 fpersyn 11/12/2019 #4

假设您从一系列字典开始,您可以使用 .tolist() 方法创建字典列表,并将其用作 DataFrame 的输入。此方法会将每个不同的键映射到一列。

您可以通过在 pd 中设置参数在创建时按键进行筛选。DataFrame(),在下面为您提供简洁的单行。希望能有所帮助。columns

# Starting assumption:
data = ["{'coordinates': [-43.301755, -22.990065], 'type': 'Point', 'elevation': 1000}",
        "{'coordinates': [-51.17913026, -30.01201896], 'type': 'Point'}"]
s = pd.Series(data).apply(eval)

# Create a DataFrame with a list of dicts with a selection of columns
pd.DataFrame(s.tolist(), columns=['coordinates'])
Out[1]: 
                    coordinates
0      [-43.301755, -22.990065]
1  [-51.17913026, -30.01201896]

评论

0赞 fpersyn 11/12/2019
注意 - 列表中的字典不需要具有相同的长度即可正常工作。字典可能会遗漏其他字典中存在的多个键,反之亦然。例如,当您运行时,您会注意到它在第二行中设置为。pd.DataFrame(s.tolist())elevationNaN