【问题标题】:Filtering a nested list过滤嵌套列表
【发布时间】:2018-11-19 19:43:20
【问题描述】:

我有如下嵌套列表:-

 list = [['A:1','B:(null)','C:3','D:4'],
        ['A:1','B:abc','C:6','D:7'],
        ['A:1','B:def','C:2','G:44','E: 600','F: 6600'],
        ['A:1','B:ghi','C:33','D:44']]

我想把它转换成一个数据框,这样before : 就是column nameafter : 的值

这里我有两种类型的数据,一种是:-

[['A:1','B:(null)','C:3','D:4'],
  ['A:1','B:abc','C:6','D:7'],
  ['A:1','B:ghi','C:33','D:44']]

其中一项是不同的,即

['A:1','B:def','C:2','G:44','E: 600','F: 6600']

预期输出:-

df1 =

和 df2 =

Q.1) 到目前为止,我只有两种数据,所以我想要两个数据框。 Q.2)我们可以让它动态化,以便它根据列表中的项目创建多个 dfs。

【问题讨论】:

    标签: python python-3.x pandas dataframe lambda


    【解决方案1】:

    IIUC,第一次将您的list 转换为dictlist(也不要将您的列表命名为列表,它会覆盖python 函数),第二次创建数据框,使用isnulldot创建组键,然后构建字典,我不建议动态创建数据框,您可以将它们放入dict,如果有问题请查看local

    [dict(tuple(y.split(":")) for y in x )for x in l] # make you list to list of dict 
    Out[11]: 
    [{'A': '1', 'B': '(null)', 'C': '3', 'D': '4'},
     {'A': '1', 'B': 'abc', 'C': '6', 'D': '7'},
     {'A': '1', 'B': 'def', 'C': '2', 'E': ' 600', 'F': ' 6600', 'G': '44'},
     {'A': '1', 'B': 'ghi', 'C': '33', 'D': '44'}]
    newl=[dict(tuple(y.split(":")) for y in x )for x in l]
    pd.DataFrame(newl)
    Out[13]: 
       A       B   C    D     E      F    G
    0  1  (null)   3    4   NaN    NaN  NaN
    1  1     abc   6    7   NaN    NaN  NaN
    2  1     def   2  NaN   600   6600   44
    3  1     ghi  33   44   NaN    NaN  NaN
    newdf=pd.DataFrame(newl)
    s=newdf.isnull().dot(newdf.columns)# using dot create the groupby key 
    s
    Out[16]: 
    0    EFG
    1    EFG
    2      D
    3    EFG
    dtype: object
    

    {x: y for x , y  in newdf.groupby(s)}# using group by create the dict 
    Out[17]: 
    {'D':    A    B  C    D     E      F   G
     2  1  def  2  NaN   600   6600  44, 'EFG':    A       B   C   D    E    F    G
     0  1  (null)   3   4  NaN  NaN  NaN
     1  1     abc   6   7  NaN  NaN  NaN
     3  1     ghi  33  44  NaN  NaN  NaN}
    d={x: y for x , y  in newdf.groupby(s)}
    d['D'].dropna(1,thresh=1)
    # result can using dict selection
    # dropna here means atleast one column should have at least one not null value , 
    # if it is all null , then we drop the entire columns  
    Out[19]: 
       A    B  C    E      F   G
    2  1  def  2  600   6600  44
    
    d['EFG'].dropna(1,thresh=1)
    Out[21]: 
       A       B   C   D
    0  1  (null)   3   4
    1  1     abc   6   7
    3  1     ghi  33  44
    

    不推荐local

    d={x: y.dropna(1,thresh=1) for x , y  in newdf.groupby(s)}
    variables = locals()
    for i,j in enumerate(d.values()):
        variables["df{0}".format(i+1)] = j
    df1
    Out[26]: 
       A    B  C     E      F   G
    2  1  def  2   600   6600  44
    df2
    Out[27]: 
       A       B   C   D
    0  1  (null)   3   4
    1  1     abc   6   7
    3  1     ghi  33  44
    

    【讨论】:

    • 哇......我的意思是那个工作的人。非常感谢...我不知道为什么有些人不明白这个问题时为什么会投反对票....非常感谢男人
    • @ak333 这是一个很好的问题 :-) 值得在未来重新检查 :-)
    • @PatrickArtner 我尝试了很多方法,但是通过使用 lambda 表达式,我总是卡在某个地方。我一步一步做的非常努力。如果我伤害了你的感情,我很抱歉。我在寻找动态的东西。
    • @W-B 感谢您的评论。我正在尝试解析命令行输出以进行语音日志分析及其痛苦。这样做是因为最初的程序员为输出编写了一些糟糕的代码。
    • @PatrickArtner 我是 stackoverflow 的新手。将来我一定会牢记这一点。非常感谢您的建议。
    【解决方案2】:

    你可以:

    1. 从您的列表中创建字典(我选择将 "(null)" 替换为 None
    2. 通过collections.defaultdict按排序键分组dicts
    3. 从组中创建和生成数据框

    from collections import defaultdict
    import pandas as pd
    
    # convert to dictionaries        
    def makeDict(inner): 
        return {k: (v if v!= "(null)" else None) for k,v in (p.split(":") for p in inner)}
    
    # group and yield dfs
    def makeIt(l):
        # collect data as dicts
        dicts = []
        for inner in l:
            dicts.append( makeDict(inner))
    
        # group by sorted keys
        t = defaultdict(list)
        for d in dicts:
            t[tuple(sorted(d.keys()))].append(d)
    
        # create dataframes from groups and yield them
        for k in t:
            df = pd.DataFrame(t[k])
            yield df
    

    用法:

    l = [['A:1','B:(null)','C:3','D:4'],
         ['A:1','B:abc','C:6','D:7'],
         ['A:1','B:def','C:2','G:44','E: 600','F: 6600'],
         ['A:1','B:ghi','C:33','D:44']]
    
    dfs = list(makeIt(l))
    
    for df in dfs:
        print("-"*20)
        print(df)
    

    输出:

    --------------------
       A     B   C   D
    0  1  None   3   4
    1  1   abc   6   7
    2  1   ghi  33  44
    
    --------------------
       A    B  C     E      F   G
    0  1  def  2   600   6600  44
    

    【讨论】:

    • 感谢您的回答,但是当我执行 dfs = list(makeIt(l)) ... 我收到错误 TypeError: 'list' object is not callable
    • 没关系.. 一个小问题。我如何为这些数据框分配名称。所以我现在可以调用它只是打印那些。
    • @ak333 它们在一个列表中,您可以使用 dfs[0], ... ,dfs[len(dfs)-1] 来获取单个 dfs - 如果您知道有多少个,您可以将列表分解为变量其中:df1,df2,df3,df4 = dfs(如果 dfs 包含 4 个列表)等 - 正常列表规则适用。你可以for df in dfs: 然后像我在打印时那样反复使用它们...
    • @ak333 为您使用本地更新,但不推荐
    • 为什么不推荐..它可能会导致任何问题。
    猜你喜欢
    • 1970-01-01
    • 2023-02-11
    • 2021-07-10
    • 1970-01-01
    • 2019-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多