读取制表符分隔文件,第一列为键,其余为值

时间:2015-04-28 13:07:58

标签: python csv numpy dictionary pandas

我有一个标签分隔文件,其中包含 10亿行(想象200列,而不是3列):

abc -0.123  0.6524  0.325
foo -0.9808 0.874   -0.2341 
bar 0.23123 -0.123124   -0.1232

我想创建一个字典,其中第一列中的字符串是键,其余是值。我一直在这样做,但计算成本很高:

import io

dictionary = {}

with io.open('bigfile', 'r') as fin:
    for line in fin:
        kv = line.strip().split()
        k, v = kv[0], kv[1:]
        dictionary[k] = list(map(float, v))

我怎样才能获得所需的字典?实际上,numpy数组比值的浮点数列表更合适。

5 个答案:

答案 0 :(得分:4)

你可以使用pandas加载df,然后根据需要构建一个新的df,然后调用to_dict

In [99]:

t="""abc -0.123  0.6524  0.325
foo -0.9808 0.874   -0.2341 
bar 0.23123 -0.123124   -0.1232"""
df = pd.read_csv(io.StringIO(t), sep='\s+', header=None)
df = pd.DataFrame(columns = df[0], data = df.ix[:,1:].values)
df.to_dict()
Out[99]:
{'abc': {0: -0.12300000000000001,
  1: -0.98080000000000001,
  2: 0.23123000000000002},
 'bar': {0: 0.32500000000000001, 1: -0.2341, 2: -0.1232},
 'foo': {0: 0.65239999999999998, 1: 0.87400000000000011, 2: -0.123124}}

修改

一种更动态的方法,可以减少构建临时df的需要:

In [121]:

t="""abc -0.123  0.6524  0.325
foo -0.9808 0.874   -0.2341 
bar 0.23123 -0.123124   -0.1232"""
# determine the number of cols, we'll use this in usecols
col_len = pd.read_csv(io.StringIO(t), sep='\s+', nrows=1).shape[1]
col_len
# read the first col we'll use this in names
cols = pd.read_csv(io.StringIO(t), sep='\s+', usecols=[0], header=None)[0].values
# now read and construct the df using the determined usecols and names from above
df = pd.read_csv(io.StringIO(t), sep='\s+', header=None, usecols = list(range(1, col_len)), names = cols)
df.to_dict()
Out[121]:
{'abc': {0: -0.12300000000000001,
  1: -0.98080000000000001,
  2: 0.23123000000000002},
 'bar': {0: 0.32500000000000001, 1: -0.2341, 2: -0.1232},
 'foo': {0: 0.65239999999999998, 1: 0.87400000000000011, 2: -0.123124}}

进一步更新

实际上你不需要第一次读取,列长度可以隐含地通过第一列中的列数得出:

In [128]:

t="""abc -0.123  0.6524  0.325
foo -0.9808 0.874   -0.2341 
bar 0.23123 -0.123124   -0.1232"""
cols = pd.read_csv(io.StringIO(t), sep='\s+', usecols=[0], header=None)[0].values
df = pd.read_csv(io.StringIO(t), sep='\s+', header=None, usecols = list(range(1, len(cols)+1)), names = cols)
df.to_dict()
Out[128]:
{'abc': {0: -0.12300000000000001,
  1: -0.98080000000000001,
  2: 0.23123000000000002},
 'bar': {0: 0.32500000000000001, 1: -0.2341, 2: -0.1232},
 'foo': {0: 0.65239999999999998, 1: 0.87400000000000011, 2: -0.123124}}

答案 1 :(得分:3)

如果指定列数,则可以使用numpy.genfromtxt()函数:

import numpy as np

a = np.genfromtxt('bigfile.csv',dtype=str,usecols=(0)) 
b = np.genfromtxt('bigfile.csv',dtype=float,delimiter='\t',usecols=range(1,4)) 
                                                                             #^enter # of cols here

d = dict(zip(a,b.tolist()))    #if you want a numpy array, just remove .tolist()

print d

<强>输出:

{'abc': [-0.123, 0.6524, 0.325], 'bar': [0.23123, -0.123124, -0.1232], 'foo': [-0.9808, 0.874, -0.2341]}

注意:要以编程方式查找您可以执行的cols的数量:

with open('bigfile.csv', 'r') as f:
    num_cols = len(f.readline().split())

然后使用num_cols作为usecols参数。

答案 2 :(得分:2)

您可以使用csv模块来读取文件,以便分割线然后使用np.array将浮点值转换为numpy数组对象:

import csv
import numpy as np
dictionary = {}
with open('bigfile.csv', 'rb') as csvfile:
     spamreader = csv.reader(csvfile, delimiter='\t',)
     for row in spamreader:
        k, v = row[0], row[1:] #in python3 do  k,*v = row
        dictionary[k] = np.array(map(float, v))

答案 3 :(得分:0)

使用Pandas的一种方法。假设你做df = pd.read_csv(file)df就像

In [220]: df
Out[220]:
     k       a1        a2      a3
0  abc -0.12300  0.652400  0.3250
1  foo -0.98080  0.874000 -0.2341
2  bar  0.23123 -0.123124 -0.1232

我添加了虚拟列名称,您可以灵活地在读取csv文件时更改它

然后你可以做到以下几点。

In [221]: df.set_index('k').T.to_dict('list')
Out[221]:
{'abc': [-0.12300000000000001, 0.65239999999999998, 0.32500000000000001],
 'bar': [0.23123000000000002, -0.123124, -0.1232],
 'foo': [-0.98080000000000001, 0.87400000000000011, -0.2341]}

答案 4 :(得分:0)

对不起,这不是一个真正的答案,但对评论来说太长了。

你说你有10亿行,有200列浮点数。它意味着

的最小记忆
  

10 9 * 200 * 8 = 1.6 10 12 bytes

它提供超过1.5 G不计算字典的开销。

当然,您可以尝试使用numpy数组而不是浮点数列表,但每个数组都很小(200个元素),因此我非常怀疑增益是否很重要。

恕我直言,对于这么多数据,你不应该考虑加载阶段而不管你如何处理数据,如果你真的需要一个包含10个记录的200个浮点值的字典,你当前实现是正确的,因为是一个numpy数组。

如果您可以将所有数据放在一个numpy数组中,并且确实将numpy用于处理部分,那么您可以获得进一步处理的重要收益,但不知道更多它只是推测。