【问题标题】:How to convert csv into nested json in python pandas?python - 如何将csv转换为python pandas中的嵌套json?
【发布时间】:2019-07-21 23:53:45
【问题描述】:

我有一个这样的 csv:

    Art        Category  LEVEL 2    LEVEL 3 LEVEL 4 LEVEL 5 Location
0   PRINTMAKING VISUAL  CONTEMPORARY    2D  NaN NaN NaN
1   PAINTING    VISUAL  CONTEMPORARY    2D  NaN NaN NaN
2   AERIAL  VISUAL  CONTEMPORARY    2D  PHOTOGRAPHY AERIAL  NaN
3   WILDLIFE    VISUAL  CONTEMPORARY    2D  PHOTOGRAPHY WILDLIFE    NaN
4   NATURE  VISUAL  CONTEMPORARY    2D  PHOTOGRAPHY NATURE  NaN

艺术和类别将在那里,但从 l1 到 l6 的级别可以为空。 我想要达到的效果是这样的:

art: PRINTMAKING
category: VISUAL
tags: [CONTEMPORARY, 2D]

级别基本上是特定艺术的标签,将存储在数组中。

我是 python 新手,到目前为止我已经编写了以下代码。我怎样才能做到这一点。

import pandas as pd
import json
data = pd.read_excel("C:\\Users\\Desktop\\visual.xlsx")
rec = {}
rec['art'] = data['Art']
rec['category'] = data['Category']
rec['tags'] = data['LEVEL 2'] + ',' + data['LEVEL 3'] + ',' + data['LEVEL 4'] + ',' + data['LEVEL 5']

我猜这不是正确的做法。

【问题讨论】:

  • 不清楚你在问什么
  • 你可以这样理解。每一种艺术都属于一个类别并有标签。标签位于需要存储为数组的列中。
  • 如果您显示您的数据框目前的外观以及您的预期输出是什么样的,将会更容易理解
  • 你有什么问题?
  • 我不知道如何处理当前代码。我已经编辑了这个问题以便更好地理解。

标签: python json pandas csv


【解决方案1】:

对于将tags 的值转换为没有NaNs 的列表,请使用:

df['tags'] = df.filter(like='LEVEL').apply(lambda x: x.dropna().tolist(), axis=1)
#alternative, should be faster
#df['tags'] = [[y for y in x if isinstance(y, str)] for x in
#                 df.filter(like='LEVEL').values]

d = df[['Art','Category','tags']].to_dict(orient='records')

[{
    'Art': 'PRINTMAKING',
    'Category': 'VISUAL',
    'tags': ['CONTEMPORARY', '2D']
}, {
    'Art': 'PAINTING',
    'Category': 'VISUAL',
    'tags': ['CONTEMPORARY', '2D']
}, {
    'Art': 'AERIAL',
    'Category': 'VISUAL',
    'tags': ['CONTEMPORARY', '2D', 'PHOTOGRAPHY', 'AERIAL']
}, {
    'Art': 'WILDLIFE',
    'Category': 'VISUAL',
    'tags': ['CONTEMPORARY', '2D', 'PHOTOGRAPHY', 'WILDLIFE']
}, {
    'Art': 'NATURE',
    'Category': 'VISUAL',
    'tags': ['CONTEMPORARY', '2D', 'PHOTOGRAPHY', 'NATURE']
}]

【讨论】:

  • 有没有办法全部转成小写?
  • @KaranGupta - 当然,将 .apply(lambda x: x.dropna().tolist(), axis=1) 更改为 .apply(lambda x: x.str.lower().dropna().tolist(), axis=1)
  • @KaranGupta - 但如果所有值都是字符串或 NaN (None)s 则工作
  • 所有值都不为空...有些可以为空。我没找到你
  • @KaranGupta - 好的,我认为如果某些数值它不应该工作
【解决方案2】:

df

   Art     Category   LEVEL             2 LEVEL.1            3   LEVEL.2   4  \
0    0  PRINTMAKING  VISUAL  CONTEMPORARY      2D          NaN       NaN NaN   
1    1     PAINTING  VISUAL  CONTEMPORARY      2D          NaN       NaN NaN   
2    2       AERIAL  VISUAL  CONTEMPORARY      2D  PHOTOGRAPHY    AERIAL NaN   
3    3     WILDLIFE  VISUAL  CONTEMPORARY      2D  PHOTOGRAPHY  WILDLIFE NaN   
4    4       NATURE  VISUAL  CONTEMPORARY      2D  PHOTOGRAPHY    NATURE NaN   

   LEVEL.3   5  Location  
0      NaN NaN       NaN  
1      NaN NaN       NaN  
2      NaN NaN       NaN  
3      NaN NaN       NaN  
4      NaN NaN       NaN  

df = df.set_index(['Art','Category']).apply(lambda x: [','.join([str(a) for a in x.values if str(a) != 'nan'])], axis=1)

print(df.reset_index(name='tags'))

   Art     Category                                           tags
0    0  PRINTMAKING                       [VISUAL,CONTEMPORARY,2D]
1    1     PAINTING                       [VISUAL,CONTEMPORARY,2D]
2    2       AERIAL    [VISUAL,CONTEMPORARY,2D,PHOTOGRAPHY,AERIAL]
3    3     WILDLIFE  [VISUAL,CONTEMPORARY,2D,PHOTOGRAPHY,WILDLIFE]
4    4       NATURE    [VISUAL,CONTEMPORARY,2D,PHOTOGRAPHY,NATURE]

听写

df.to_dict(orient='records')

输出

[{'Art': 0, 'Category': 'PRINTMAKING', 'tags': ['VISUAL,CONTEMPORARY,2D']},
 {'Art': 1, 'Category': 'PAINTING', 'tags': ['VISUAL,CONTEMPORARY,2D']},
 {'Art': 2,
  'Category': 'AERIAL',
  'tags': ['VISUAL,CONTEMPORARY,2D,PHOTOGRAPHY,AERIAL']},
 {'Art': 3,
  'Category': 'WILDLIFE',
  'tags': ['VISUAL,CONTEMPORARY,2D,PHOTOGRAPHY,WILDLIFE']},
 {'Art': 4,
  'Category': 'NATURE',
  'tags': ['VISUAL,CONTEMPORARY,2D,PHOTOGRAPHY,NATURE']}]

【讨论】:

  • 我需要问题中描述的字典
  • AttributeError: 'Series' 对象没有属性 'set_index'
【解决方案3】:

这可能会解决您的问题:

from io import StringIO
import csv
# help(csv)
categories="""art,category, l1, l2, l3, l4, l5, l6
a1,c1,abc,def
a2,c2,,,,xyz,pqr,
a3,c3,lmn,,,qwe,rtg,
"""

f=StringIO(categories)
rows=csv.DictReader(f,delimiter=',')
data=[]
for row in rows:
#     print(row)
    d={
        "cateory":row.get("category",''),
        "art":row.get("art",'')
    }
    try:
        del row["category"]
        del row["art"]
    except KeyError as ke:
        print(ke)
#     print(row)
    d["levels"]=list(row.values())
    print(d)

样本输出:

{'cateory': 'c1', 'art': 'a1', 'levels': ['abc', 'def', None, None, None, None]}
{'cateory': 'c2', 'art': 'a2', 'levels': ['', '', '', 'xyz', 'pqr', '']}
{'cateory': 'c3', 'art': 'a3', 'levels': ['lmn', '', '', 'qwe', 'rtg', '']}

【讨论】:

    【解决方案4】:

    您应该使用pd.Series.str.cat 结合functools.reduce 来连接所有标签:

    df = pd.DataFrame({
        'art': ['a1', 'a2', 'a3'],
        'category': ['c1', 'c2', 'c3'],
        'l1': ['abc', '', 'lmn'],
        'l2': ['def', 'xyz', 'qwe'],
    })
    
    from functools import reduce
    tag_cols = [x for x in df.columns if x not in ['art', 'category']]
    df['tags'] = reduce(lambda a, b: df[a].str.cat(df[b], sep=','), 
    tag_cols).apply(lambda x: [t for t in x.split(",") if t != ''])
    d = df.to_dict(orient='records')
    

    输出

      [{'art': 'a1',
      'category': 'c1',
      'l1': 'abc',
      'l2': 'def',
      'tags': ['abc', 'def']},
     {'art': 'a2', 'category': 'c2', 'l1': '', 'l2': 'xyz', 'tags': ['xyz']},
     {'art': 'a3',
      'category': 'c3',
      'l1': 'lmn',
      'l2': 'qwe',
      'tags': ['lmn', 'qwe']}]
    

    【讨论】:

    • 我需要一本字典兄弟
    • 是的,我错过了。用字典为你编辑了帖子。
    猜你喜欢
    • 2017-06-10
    • 1970-01-01
    • 2018-10-27
    • 2021-05-17
    • 2022-08-21
    • 1970-01-01
    • 1970-01-01
    • 2019-09-24
    相关资源
    最近更新 更多