【问题标题】:Transforming a List to a Pivot Table with Python使用 Python 将列表转换为数据透视表
【发布时间】:2014-03-02 12:51:53
【问题描述】:

我有以下格式的列表:

listA = [[142L, u'Work Load', [57.35, 19.57]],
[142L, u'Days', [84.0, 44.0]],
[142L, u'Payed', [5684.0, 3944.0]],
[547L, u'Work Load', [87.25, 12.70]],
[547L, u'Days', [98.0, 128.0]],
[547L, u'Payed', [3247.0, 4712.0]],
...]

我想将其转换为:

listB = [['id', u'Work Load', u'Days', u'Payed'],
[142L, 57.35, 84.0, 5684.0],
[142L, 19.57, 44.0, 3944.0],
[547L, 87.25, 98.0, 3247.0],
[547L, 12.70, 128.0, 4712.0],
...]

如何将它们分组?我这样做的原因是因为我试图将列表导出到 csv。 有任何想法吗?谢谢!

【问题讨论】:

  • 所有元素都按id排序?
  • 是的,但并不总是知道 heders 顺序。

标签: python list grouping pivot-table


【解决方案1】:

由于您显示的列表是按“id”排序的,因此您可以直接使用itertools.groupbyzip

In [189]: lst  #if not sorted, lst.sort(key=lambda x: x[0]) first
Out[189]: 
[[142L, u'Work Load', [57.35, 19.57]],
 [142L, u'Days', [84.0, 44.0]],
 [142L, u'Payed', [5684.0, 3944.0]],
 [547L, u'Work Load', [87.25, 12.7]],
 [547L, u'Days', [98.0, 128.0]],
 [547L, u'Payed', [3247.0, 4712.0]]]

In [190]: lstB=[['id', u'Work Load', u'Days', u'Payed'],]
     ...: for k, g in itertools.groupby(lst, lambda x: x[0]):
     ...:     t=zip(*(i[-1] for i in g))
     ...:     for i in t:
     ...:         lstB.append([k]+list(i))

#outputs:
In [587]: lstB
Out[587]: 
[['id', u'Work Load', u'Days', u'Payed'],
 [142L, 57.35, 84.0, 5684.0],
 [142L, 19.57, 44.0, 3944.0],
 [547L, 87.25, 98.0, 3247.0],
 [547L, 12.7, 128.0, 4712.0]]

【讨论】:

  • 谢谢。尽管标题的顺序并非总是已知的,但也并非所有数据都具有一个或多个标题的值。例如:列表可以是:[[142L, u'Work Load', [57.35, 19.57]], [142L, u'Days', [84.0, 44.0]], [142L, u'Payed', [5684.0]] , [547L, u'Work Load', [87.25, 12.7]], [547L, u'Days', [98.0, 128.0]], ],但可以接受空数据(即 0 或 '')。我试过了,但没有按预期工作。
  • @VasilisKasapidis 那么 unutbu 的答案可能会更好
【解决方案2】:

使用pandas:

import pandas as pd

listA = [[142L, u'Work Load', [57.35, 19.57]],
[142L, u'Days', [84.0, 44.0]],
[142L, u'Payed', [5684.0, 3944.0]],
[547L, u'Work Load', [87.25, 12.70]],
[547L, u'Days', [98.0, 128.0]],
[547L, u'Payed', [3247.0, 4712.0]]]

dfA = pd.DataFrame(listA)
dfA.columns = ['id','field','data']

dfB = dfA.groupby('id').apply(
    lambda grp: pd.DataFrame(zip(*grp['data']), columns=grp['field']))
dfB.index = dfB.index.droplevel(-1)
print(dfB)

产生数据帧

field  Work Load  Days  Payed
id                           
142        57.35    84   5684
142        19.57    44   3944
547        87.25    98   3247
547        12.70   128   4712

然后您可以使用将 DataFrame 写入 CSV

dfB.to_csv('/tmp/test.csv', sep=',')

看起来像这样:

id,Work Load,Days,Payed
142,57.35,84.0,5684.0
142,19.57,44.0,3944.0
547,87.25,98.0,3247.0
547,12.7,128.0,4712.0

【讨论】:

  • 如何将 dfB 转换回列表?
  • dfB.to_records().tolist()
  • 你能提供一个可运行的例子来演示这个问题吗?
  • 设法解决了它,否则使用 to_csv 和 streamIO。贝娄是我的代码。
【解决方案3】:

这是我的问题的有效解决方案:

    import pandas as pd
    dt = [[142L, u'Work Load', [57.35, 19.57]],
          [142L, u'Days', [84.0, 44.0]],
          [142L, u'Payed', [5684.0, 3944.0]],
          [547L, u'Work Load', [87.25, 12.70]],
          [547L, u'Days', [98.0, 128.0]],
          [547L, u'Payed', [3247.0, 4712.0]]]
    dfA = pd.DataFrame(dt)
    dfA.columns = [u'id','field','data']
    dfB = dfA.groupby(u'id').apply(
        lambda grp: pd.DataFrame(zip(*grp['data']), columns=grp['field']))
    dfB.index = dfB.index.droplevel(-1)
    data = StringIO()
    dfB.to_csv(data, sep=';', encoding='utf-8')
    self.response = HttpResponse(data.getvalue(), mimetype='text/csv')
    self.add_response_headers()
    self.response.close()
    self.response.flush()
    return self.response

感谢您的帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-25
    • 2012-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-03
    • 1970-01-01
    相关资源
    最近更新 更多