【问题标题】:Time-Efficient Wide to Long Conversion Pandas高效的宽到长转换 Pandas
【发布时间】:2016-10-18 12:25:18
【问题描述】:

我有一个大约 5400 万行的数据集,我需要从制表符分隔的文本文件中读取,从宽格式转换为长格式,然后写入新的文本文件。数据太大而无法放入内存,所以我一直在使用迭代器。我想将三个单独的变量从宽移到长,所以我一直在使用其中三个单独的迭代器

import pandas as pd
import itertools as it

filename = "C:/example.txt"
iter_a = pd.read_table(filename, iterator=True, usecols=col_list_1, chunksize=100000)
iter_b = pd.read_table(filename, iterator=True, usecols=col_list_2, chunksize=100000)
iter_c = pd.read_table(filename, iterator=True, usecols=col_list_3, chunksize=100000)

所有 usecols 列表都包含一个公共标识符和不同的列。列名基于年份和属性,因此列列表可能如下所示:

col_list_1 = ['Key', 'A90', 'A91', 'A92']
col_list_2 = ['Key', 'B90', 'B91', 'B92']
col_list_3 = ['Key', 'C90', 'C91', 'C92']

并且我想将所有列名更改为没有前导字符/字符的年份,并且仅在年份上融化。

new_colnames = ['Key', '1990', '1991', '1992']
melt_values = ['1990', '1991', '1992']

for achunk, bchunk, cchunk in it.izip(iter_a, iter_b, iter_c):
    achunk.columns = new_colnames
    bchunk.columns = new_colnames
    cchunk.columns = new_colnames

    melted_a = pd.melt(achunk, id_vars='Key', value_vars=melt_values, var_name='Year', value_name='A').set_index(['Key', 'Year']).sort_index()
    melted_b = pd.melt(bchunk, id_vars='Key', value_vars=melt_values, var_name='Year', value_name='B').set_index(['Key', 'Year']).sort_index()
    melted_c = pd.melt(cchunk, id_vars='Key', value_vars=melt_values, var_name='Year', value_name='C').set_index(['Key', 'Year']).sort_index()

    join1 = melted_a.join(melted_b, how='outer')
    join2 = join1.join(melted_c, how='outer')
    join2.dropna(inplace=True, how='all')

    join2.to_csv('C:/output_example.txt', sep='\t')

虽然这确实有效,但需要很长时间。我在 15 秒时用 100,000 行块记录了一次迭代。假设它是线性扩展的,我似乎在看 2.25 小时的运行时间。有什么好方法可以加快速度吗?也许使用 numpy 数组或多处理?

【问题讨论】:

  • 我们可以假设输入文件都具有相同的键和相同的顺序吗? (否则,分块连接没有多大意义..)另外,你有 value_name='A' 三次,这是一个错字吗?数据是数字的吗?缺失数据如何表示?
  • @morningsun 所有输入文件都具有相同的键和相同的顺序。 value_name='A' 很好,这是一个错字。数据不一定都是数字的。一列总是具有相同的类型,但不同的列可以是数字或字符串。
  • 啊,现在我看到你有 3 个迭代器在同一个文件上,有道理。

标签: python performance pandas numpy bigdata


【解决方案1】:

pandas csv 解析器确实很快,但您可以尝试纯 python 解决方案,因为 pandas 正在做一堆您并不真正关心的事情(类型推断和转换、所有连接对齐、索引等)。

这只是一个开始,但这里有一个非常简单的从宽到长的示例。您必须对其进行测试,但我猜它可能比您在上面所做的更快。

In [30]: %%file tmp.csv
    ...: Key,A90,A91,A92,B90,B91,B92
    ...: a,1,2,3,4,5,6
    ...: b,7,8,9,10,11,12

In [32]: with open('tmp.csv') as f, open('out.csv', 'w') as f2:
    ...:     f2.write('Key,Group,Year,Value\n')
    ...:     for i, line in enumerate(f):
    ...:         if i == 0:
    ...:             _, *headers = line.strip().split(',')
    ...:             headers = [(h[0], '19' + h[1:]) for h in headers]
    ...:         else:
    ...:             key, *rest = line.strip().split(',')
    ...:             for (group, year), value in zip(headers, rest):
    ...:                 f2.write(','.join([key, group, year, value]) + '\n')

In [33]: print(open('out.csv').read())
Key,Group,Year,Value
a,A,1990,1
a,A,1991,2
a,A,1992,3
a,B,1990,4
a,B,1991,5
a,B,1992,6
b,A,1990,7
b,A,1991,8
b,A,1992,9
b,B,1990,10
b,B,1991,11
b,B,1992,12

【讨论】:

  • 我忘了说我使用的是 python 2.7,有没有一个简单的解决方法来解压 *headers?
  • 当然:l = line.strip().split(','); _, header = l[0], l[1:]
  • 我绝对喜欢纯 python 方法的想法,但我现在意识到我对我正在寻找的输出格式不够清楚,这更像是@root 所拥有的每个唯一组被捕获在列中而不是在行中
猜你喜欢
  • 2020-05-31
  • 1970-01-01
  • 2017-07-31
  • 2016-10-05
  • 2017-04-19
  • 2022-10-30
  • 2013-07-16
  • 1970-01-01
  • 2022-01-24
相关资源
最近更新 更多