【问题标题】:How to read attributes of an object column, using Python Pandas如何使用 Python Pandas 读取对象列的属性
【发布时间】:2015-05-21 11:13:08
【问题描述】:

我有一个数据框,其中 'location' 列包含一个对象:

import pandas as pd

item1 = {
     'project': 'A',
     'location': {'country': 'united states', 'city': 'new york'},
     'raised_usd': 1.0}

item2 =  {
    'project': 'B',
    'location': {'country': 'united kingdom', 'city': 'cambridge'},
    'raised_usd': 5.0}

item3 =  {
    'project': 'C',
    'raised_usd': 10.0}

data = [item1, item2, item3]

df = pd.DataFrame(list(data))
df

我想创建一个额外的列 'project_country',其中仅包含国家/地区信息(如果有)。我尝试了以下方法:

def get_country(location):
    try:
        return location['country']
    except Exception:
        return 'n/a'

df['project_country'] = get_country(df['location'])
df

但这不起作用:

我应该如何导入这个字段?

【问题讨论】:

  • 严格来说,在 Python 中,这些是 items(属于 dict),而不是属性。回到原始 JSON 中,它们是属性。

标签: python python-3.x pandas


【解决方案1】:

使用apply 并将你的函数传递给它:

In [62]:

def get_country(location):
    try:
        return location['country']
    except Exception:
        return 'n/a'
​
df['project_country'] = df['location'].apply(get_country)
df
Out[62]:
                                            location project  raised_usd  \
0   {'country': 'united states', 'city': 'new york'}       A           1   
1  {'country': 'united kingdom', 'city': 'cambrid...       B           5   
2                                                NaN       C          10   

  project_country  
0   united states  
1  united kingdom  
2             n/a 

你原来的代码失败的原因是因为传递的是整列或者pandas系列:

In [64]:

def get_country(location):
    print(location)
    try:
        print(location['country'])
    except Exception:
        print('n/a')
​
get_country(df['location'])
0     {'country': 'united states', 'city': 'new york'}
1    {'country': 'united kingdom', 'city': 'cambrid...
2                                                  NaN
Name: location, dtype: object
n/a

因此,尝试使用整个 Series 查找密钥会引发 KeyError 并返回 'n/a'

【讨论】:

    【解决方案2】:

    EdChum 指出的正确方法是在“位置”列上使用apply。您可以在一行中压缩该代码:

    In [15]: df['location'].apply(lambda v: v.get('country') if isinstance(v, dict) else '')
    Out[15]: 
    0     united states
    1    united kingdom
    2                  
    Name: location, dtype: object
    

    然后,将其分配给一列:

    In [16]: df['country'] = df['location'].apply(lambda v: v.get('country') if isinstance(v, dict) else '')
    
    In [17]: df
    Out[17]: 
                                                location project  raised_usd  \
    0  {u'country': u'united states', u'city': u'new ...       A           1   
    1  {u'country': u'united kingdom', u'city': u'cam...       B           5   
    2                                                NaN       C          10   
    
              country  
    0   united states  
    1  united kingdom  
    2 
    

    【讨论】:

      【解决方案3】:

      使用apply,您可以使用operator.itemgetter。请注意,我们需要使用 dropna(),因为您的列包含 NaN:

      from operator import itemgetter
      df['location'].apply(itemgetter('country'))
      
      df['location'].dropna().apply(itemgetter('country'))
      0     united states
      1    united kingdom
      Name: location, dtype: object
      

      【讨论】:

        【解决方案4】:

        另一种方法 - 使用.str[<key>]。它隐式调用 __getitem__ 并为每个项目使用 key 参数:

        In [17]: df['location'].str['country']
        Out[17]: 
        0     united states
        1    united kingdom
        2               NaN
        Name: location, dtype: object
        

        如果出错则返回NaN,否则返回值。

        【讨论】:

        • 不幸的是,这似乎不再适用于最新版本的pandas。我收到“AttributeError: Can only use .str accessor with string values!`'.
        • @timgeb 您使用哪个版本?我现在正在使用 1.2.1 进行测试,它可以正常工作。
        【解决方案5】:

        读取csv文件时,可以使用converters选项:

        def string_to_dict(dict_string):`
            try:
                return json.loads(dict_string)
            except Exception:
                return "N/A"
        
         df = pd.read_csv('../data/data.csv', converters={'locations': string_to_dict})
        

        使用from pandas import json_normalize访问数据:

        normalized_locations = json_normalize(df['locations'])
        df['country'] = normalized_locations['country']
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-10-09
          • 1970-01-01
          • 2018-03-07
          • 1970-01-01
          • 1970-01-01
          • 2017-03-06
          • 2020-11-26
          相关资源
          最近更新 更多