1

给定以下格式的制表符分隔文件,我需要按列方式执行操作。我知道的最简单的解决方案是使用 pandas 包,但是我的文件是几个演出,我很难阅读它。所以我决定使用普通的流媒体方法。

在这里,我想动态生成列变量(列数约为 500),每个变量都将存储该特定列中的所有值,包括空格。例如:变量a将是一个列表[11,22,31,,42,555]

a   b   c   d   e   f
11      9   9   1   6
22  8   0   8   2   
31  7       7   3   5
    6   1   6       4
42  6   2   5   2   3
555     3   4   1   2

如何通过一次读取整个文件来生成这些变量?

4

6 回答 6

2

你真的把两个问题合二为一了。


我知道的最简单的解决方案是使用 pandas 包,但是我的文件是几个演出,我很难阅读它。所以我决定使用普通的流媒体方法。

不要那样做。与纯 Python 编写的任何东西相比,Pandas 可以用更少的内存和时间来处理大量数据。而且也不那么冗长。可以想象,numpy在阅读后下降到然后对结果进行熊猫化会有所帮助,但下降到纯 Python 肯定会让事情变得更糟。

如果您的代码有问题,请向我们展示您的代码(以及生成等效示例数据的足够信息)。


在这里,我想动态生成列变量(列数约为 500),每个变量都将存储该特定列中的所有值,包括银行。例如:变量 a 将是一个列表 [11,22,31,,42,555]。

绝对不要那样做。你几乎不想像这样动态地生成变量。它没有任何好处,而且有很多缺点。

这正是字典的用途。而不是这个:

for column in columns:
    create_variable_named(column[0]).set_to(column[1:])

只需这样做:

column_dict = {column[0]: column[1:] for column in columns}

然后你可以像这样访问它:

column_dict['a']

而且,如果你想遍历所有列,而不是这样:

for col in a, b, c, d, …, zz, aaa, …:

你可以这样做:

for col in column_dict.values():

如果您真的非常想创建动态变量,您可以。根据您要将它们添加到的范围或命名空间,它是以下之一:

globals()[name] = value
locals()[name] = value
setattr(module, name, value)
setattr(obj, name, value)
setattr(cls, name, value)

… 等等。

于 2013-05-08T01:19:17.990 回答
1

来自评论:

它无法将整个文件加载到内存中,并且似乎永远加载。

如果这是你的问题,那么你攻击它是错误的。如果您没有足够的内存一次保存整个文件,那么您可能也没有足够的内存一次保存整个数组。如果您使用的是纯 Python 对象,您肯定不会,但可能甚至pandasnumpy不会。

因此,您需要做的是即时将其从一种基于磁盘的格式转换为另一种,然后重写代码以比原始文件更快地处理磁盘上的数据。

一个明显的可能性是您可以通过随机访问查找或映射的文件。例如,假设您有 500 列,其中的值都适合range(0, 1<<32),并且您不知道您有多少行。

迭代 csv 一次以计算行数,然后创建一个4 * 500 * rows字节文件,然后再次迭代 csv 以使用struct模块填充它。mmap然后你可以通过创建一个视图来访问任何列4 * rows * col, 4 * rows * (col+1)

或者,或者,即时转置。这会更简单,并且有一半的 I/O,但可能会更慢(因为内存和磁盘缓存的影响)。

如果您只需要按列随机访问,而不是按行,只需为每列创建一个文件,并处理任何列,只需mmap适当的文件,或者通过 or 读取它structarray或者只使用pandasornumpy来读取/写入每个(或者可能只是pickle一个pandas表/numpy数组直接)。

另一种可能性是使用键值数据库并在其中存储大 blob,相当于文件。(事实上​​,如果您计划使用腌制表/数组,则 ashelve.shelf是一个键值数据库,其中的值通过腌制进行持久化。)

要任意选择这些想法,以下是创建单独文件、动态转置和使用以下方式存储数据的方法struct

让我举一个带有单独文件的示例,并且struct

import csv
import struct

# You may want to check whether the column_foo.dat files already exist and are
# at least as new as input.csv, so you don't re-generate them unless the input
# data changes. That's obviously only a worthwhile optimization if you run the
# script multiple times on the exact same input.

with open('input.csv', 'rb') as f:
    reader = csv.reader(f, delimiter='\t'):
    column_names = next(reader)
    column_files = [open('column_{}.dat'.format(column_name), 'wb')
                    for column_name in column_names]
    for row in reader:
        for i, col in enumerate(row):
            value = int(col)
            column_files[i].write(struct.pack('!I', value))
    for f in column_files:
        f.close()

现在,稍后访问列:

def get_column(name):
    with open('column_{}.dat'.format(name), 'rb') as f:
        fsize = os.path.getsize(f.fileno())
        length = fsize / 4
        fmt = '!{}I'.format(length)
        return struct.unpack(fmt, f.read())
于 2013-05-08T01:37:01.730 回答
1

如果您真的不想使用 pandas,最好使用 numpy,因为 numpy 确实具有转置效果,因此您可以更改它,使列成为索引!

import csv
import numpy as np
with open('file_name.csv', 'rb') as f:
    reading = csv.reader(f,delimiter='\t')
    columns = reading.next()
    hold_files = []
    for row in reading:
        hold_files.append(row)
    data = np.array(hold_files)
    data = data.T

nowdata是一个数组,其中每个项目都是一个数组,其中包含每列中的每个项目!仍然很昂贵,熊猫在所有这些方面仍然更好,但这确实回答了您的问题!

另外,我建议使用pickle将其保存到磁盘!这将花费更多时间,但您不必再次遍历它!以下是您将如何执行此操作:

import pickle
def pickleSave(data, pickleFile):
    output = open(pickleFile, 'wb')
    pickle.dump(data, output)
    output.close()
    print "file has been saved to %s" % (pickleFile)
def pickleLoad(pickleFile):
    pkl_file = open(pickleFile, 'rb')
    data = pickle.load(pkl_file)
    pkl_file.close()
    return data

这会将 中的任何内容data、数组、数据框等保存到您想要的任何文件名中:pickleFile

以下将保存我刚刚制作的数组!

file_name = "my_array.txt"
pickleSave(data,file_name)

现在,每当您想使用该数组时,您都可以保存它并可以使用以下内容加载它:

loaded_data = pickleLoad("my_array.txt")

现在变量loaded_data包含我之前创建的数组!您可以在任何类型的文件上使用它!

于 2013-05-08T01:17:36.253 回答
0

您可以使用csv模块和生成器阅读它:

import csv

def get_column(name):
    with open('filename', 'r') as handle:
        reader = csv.DictReader(handle, delimiter='\t')

        for row in reader:
            yield row[name]

但是一旦你开始用这些数据做一些事情,Pandas 可能会更快。

于 2013-05-08T01:09:16.483 回答
0

尝试列表字典:

with open('myfile.txt', 'r') as infile:
    header = infile.readline()
    col_values = {var:[] for var in header.split()}
    var_idx_dict = {idx:var for idx,var in enumerate(header.split())}

    for line in infile:
        values = line.split('\t')

        for idx,value in enumerate(values):
            var = var_idx_dict[idx]
            col_values [var].append(value)

col_values应该包含列标题的字符串键,每个键指向该列中所有值的列表。

编辑:鉴于您的文件非常大,而且我不知道您的环境,并且您在使用 pandas 时遇到问题,请考虑尝试使用 PyTables。我可以提供一些帮助...这取决于您的最终目标(基本数学?统计?数据格式?)。

于 2013-05-08T01:02:32.757 回答
-1
def readAsCloumVec(fileName):
    reader = open(fileName,'r')
    text = reader.read()
    lines = text.split('\n')#Split the text into lines
    matrix = []
    for i in range(1,len(lines)):
        if(len(lines[i])>0):#Ignore the last useless line
            line = lines[i].split('\t')#The tag is depend on your file format
            matrix.append(line)
    cloumMatrix = []
    cloums = len(matrix[0])
    row = len(matrix)
    print  matrix    
    for j in range(cloums):#transposition the matrix
        cloum = []
        for i in range(row):            
            cloum.append(matrix[i][j])
        cloumMatrix.append(cloum)
    return cloumMatrix

if __name__ == "__main__":
    print readAsCloumVec('test.txt')
于 2013-05-08T01:26:35.487 回答