首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python 学习手册
Python Cookbook
Python 基础教程
Python Sites
PyPI - Python Package Index
http://www.simple-is-better.com/
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
V2EX  ›  Python

请教一下 Python 中列表字典清洗数据的问题

  •  
  •   cyy564 · 260 天前 · 962 次点击
    这是一个创建于 260 天前的主题,其中的信息可能已经有所发展或是发生改变。
    有一个列表字典是这样的

    l = [{'name': 'aa', 'type': '游戏'}, {'name': 'bb', 'type': '游戏'}, {'name': 'cc', 'type': '学习'}]

    类似上述的列表包括含有类型的键的字典,如何过滤掉和大部分类型不一样的字典

    比如列表中一共有 8 个字典,6 个字典中类型是游戏,1 个字典中类型是学习,还有个字典中类型是玩耍,如何过滤后面两个

    当然类型是不确定的,数量多的不一定是游戏,还可能是吃饭。。或睡觉

    有木有大佬给思路
    10 回复  |  直到 2018-12-06 00:25:27 +08:00
        1
    ipwx   260 天前
    统计每个类型出现的百分比,然后根据 Zipf's Law 选一个阈值删掉百分比小的类型。
        2
    necomancer   260 天前
    数据少的话:
    lst = sorted(l, key=(lambda x : x.get('type')))
    ret = [[]]
    for prv, nxt in zip(lst[:-1], lst[1:]):
    ....tmp = ret[-1]
    ....tmp.append(prv)
    ....if prv['type']!=nxt['type']:
    ........ret.append([])
    tmp = ret[-1]
    tmp.append(t[-1])
    然后取 ret 里最多的,或者直接用 groupby
    [ list(g) for c, g in groupby(lst, key=(lambda x : x.get('type'))) ]
    但是都需要排序。

    或者用 pandas:
    import pandas as pd
    l= [{'name': 'aa', 'type': '游戏'},
    {'name': 'cc', 'type': '学习'},
    {'name': 'bb', 'type': '游戏'}] # 可以不用考虑顺序

    list(pd.DataFrame(l).groupby('type')) 可以搞定,输出是 n 个 categories 的 tuple 的 list

    [(分组名 1,分组 1 数据的 dataframe),(分组名 2,分组 2 数据的 dataframe)...],数据大小可以用 dataframe 的 shape 来确定。

    In [40]: list(pd.DataFrame(l).groupby('type'))
    Out[40]:
    [('学习', name type
    1 cc 学习), ('游戏', name type
    0 aa 游戏
    2 bb 游戏)]

    In [41]: p=list(pd.DataFrame(l).groupby('type'))[1][1]

    In [42]: p.shape
    Out[42]: (2, 2)

    In [43]: p
    Out[43]:
    name type
    0 aa 游戏
    2 bb 游戏

    对一定量的数据,pandas 就可以有很高的处理效率了,如果数据量再大,考虑上 #1 的方法吧。
        3
    cyy564   260 天前
    @ipwx 从第一步我就没想到好方法来统计每个类型出现的百分比
        4
    necomancer   260 天前
    from itertools import groupby
    [ list(g) for c, g in groupby(lst, key=(lambda x : x.get('type'))) ]
        5
    necomancer   260 天前
    @cyy564 百分比很好统计:

    ret = {}
    for i in l:
    ....if not ret.get(i['type']):
    ........ret[i['type']] = 0
    ...ret.get(i['type']) +=1

    基本上在不知道 type 有多少的情况下也能轻松统计
        6
    necomancer   260 天前   ♥ 1
    Sorry,

    ret = {}
    for i in l:
    ....if not ret.get(i['type']):
    ........ret[i['type']] = 0
    ...ret[i['type']] +=1
        7
    cyy564   260 天前
    @necomancer 谢谢,这个帮大忙了[ list(g) for c, g in groupby(lst, key=(lambda x : x.get('type'))) ]
        8
    cyy564   260 天前
    @necomancer

    额。。如果 l 变成[{'name': 'aa', 'type': '游戏'}, {'name': 'bb', 'type': '游戏'}, {'name': 'cc', 'type': '学习'}, {'name': 'dd', 'type': '游戏'}]

    用这个[list(g) for c,g in groupby(l, key=(lambda x: x.get('type')))]居然会拆开他们

    输出[[{'name': 'aa', 'type': '游戏'}, {'name': 'bb', 'type': '游戏'}], [{'name': 'cc', 'type': '学习'}], [{'name': 'dd', 'type': '游戏'}]]

    这就是我不想要的结果了,我还是看看 pandas 中的 group_by
        9
    necomancer   260 天前
    @cyy564 我在 #2 已经说了,这个需要先排序。pandas 可以无视顺序。所以数据量小考虑直接 python sorted + itertools.groupby,数据量大一些考虑 pandas.DataFrame.groupby,如果超超超大就考虑 #1 的办法。
        10
    darkTianTian   259 天前
    如果 name 没啥用的话可以
    from collections import Counter
    Counter([x['type'] for x in l]).most_common()
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3765 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 23ms · UTC 07:31 · PVG 15:31 · LAX 00:31 · JFK 03:31
    ♥ Do have faith in what you're doing.