从CSV文件创建矩阵

时间:2016-11-07 10:54:34

标签: python csv parsing numpy matrix

我已经在Python上工作了大约2个月,所以我对它有了一个很好的理解。

我的目标是使用CSV数据创建矩阵,然后从该CSV文件的第3列中的数据填充该矩阵。

到目前为止我想出了这个代码:

import csv

import csv
def readcsv(csvfile_name):
      with open(csvfile_name) as csvfile:
      file=csv.reader(csvfile, delimiter=",")

#remove rubbish data in first few rows

      skiprows = int(input('Number of rows to skip? '))
           for i in range(skiprows):
                _ = next(file)

#change strings into integers/floats

            for z in file:
                 z[:2]=map(int, z[:2])
                 z[2:]=map(float, z[2:])
                 print(z[:2])
        return

使用上述代码删除垃圾数据后,CSV文件中的数据如下所示:

   Input:
   1  1  51 9 3 
   1  2  39 4 4
   1  3  40 3 9
   1  4  60 2 . 
   1  5  80 2 .
   2  1  40 6 .
   2  2  28 4 .
   2  3  40 2 .
   2  4  39 3 . 
   3  1  10 . .
   3  2  20 . .
   3  3  30 . .
   3  4  40 . .
   .  .   . . .

输出应如下所示:

      1   2   3   4  .  .
   1  51  39  40  60
   2  40  28  40  39
   3  10  20  30  40
   .
   .

此CSV文件中有大约几千行和列,但我只对CSV文件的前3列感兴趣。所以第一列和第二列基本上像矩阵的坐标,然后用第3列中的数据填充矩阵。

经过大量的反复试验,我意识到numpy是用矩阵的方式。这是我到目前为止尝试的示例数据:

  left_column =   [1, 2, 1, 2, 1, 2, 1, 2]
  middle_column = [1, 1, 3, 3, 2, 2, 4, 4]
  right_column =  [1., 5., 3., 7., 2., 6., 4., 8.]

  import numpy as np
  m = np.zeros((max(left_column), max(middle_column)), dtype=np.float)
  for x, y, z in zip(left_column, middle_column, right_column):
      x -= 1 # Because the indicies are 1-based
      y -= 1 # Need to be 0-based
      m[x, y] = z
  print(m)

  #: array([[ 1., 2., 3., 4.],
  #:        [ 5., 6., 7., 8.]])

但是,在我的脚本中指定所有数据以生成矩阵是不现实的。我尝试使用生成器从我的CSV文件中提取数据,但它对我来说效果不佳。

我尽可能地学会了numpy,但看起来它需要我的数据已经是矩阵形式,而不是。

3 个答案:

答案 0 :(得分:3)

您可以使用scipy.sparse.coo_matrix非常方便地加载此数据。

使用您的输入:

 Input:
   1  1  51 9 3 
   1  2  39 4 4
   1  3  40 3 9
   1  4  60 2 . 
   1  5  80 2 .
   2  1  40 6 .
   2  2  28 4 .
   2  3  40 2 .
   2  4  39 3 . 
   3  1  10 . .
   3  2  20 . .
   3  3  30 . .
   3  4  40 . .
   .  .   . . .

你可以这样做:

l, c, v = np.loadtxt('test.txt', skiprows=1).T
m = coo_matrix((v, (l-1, c-1)), shape=(l.max(), c.max()))

然后,您可以将coo_matrix转换为np.ndarray

In [9]: m.toarray()
Out[9]:
array([[ 51.,  39.,  40.,  60.,  80.],
       [ 40.,  28.,  40.,  39.,   0.],
       [ 10.,  20.,  30.,  40.,   0.]])

答案 1 :(得分:3)

您应该认真考虑使用pandas。它非常适合这类工作。我不能给你一个实际的解决方案,因为我没有你的数据,但我会尝试类似以下内容:

import pandas as pd
df = pd.read_csv('test.csv', usecols=[0,1,2], names=['A', 'B', 'C'])
pd.pivot_table(df, index='A', columns='B', values='C')

第二行将数据导入pandas DataFrame对象(将名称更改为对您的应用程序更有用的名称)。数据透视表创建您正在寻找的矩阵,并优雅地处理任何缺失的数据。

答案 2 :(得分:1)

这是我的解决方案,只使用csv库,并使用csv中的index \ position(使用我用来保存当前行内存的偏移量)

import csv

with open('test.csv', 'r') as csvfile:
    spamreader = csv.reader(csvfile, delimiter=',')
    list_of_list = []
    j=0
    lines = [line for line in spamreader]
    for i in range(len(lines)):
        list_ = []
        if(len(lines)<=i+j):
            break;
        first = lines[i+j][0]
        while(first == lines[i+j][0]):
            list_.append(lines[i+j][2])
            j+=1
            if(len(lines)<=i+j):
                break;
        j-=1
        list_of_list.append(list(map(float,list_)))

maxlen = len(max(list_of_list))
print("\t"+"\t".join([str(el) for el in range(1,maxlen+1)])+"\n")
for i in range(len(list_of_list)):
    print(str(i+1)+"\t"+"\t".join([str(el) for el in list_of_list[i]])+"\n")

无论如何,Saullo发布的解决方案更优雅

这是我的输出:

        1       2       3       4       5

1       51.0    39.0    40.0    60.0    80.0

2       40.0    28.0    40.0    39.0

3       10.0    20.0    30.0    40.0

我用迭代器编写了一个新版本的代码,因为csv太大而无法放入内存

import csv

with open('test.csv', 'r') as csvfile:
    spamreader = csv.reader(csvfile, delimiter=',')
    list_of_list = []

    line1 = next(spamreader)
    first = line1[0]
    list_ = [line1[2]]
    for line in spamreader:
        while(line[0] == first):
            list_.append(line[2])
            try:
                line = next(spamreader)
            except :
                break;
        list_of_list.append(list(map(float,list_)))
        list_ = [line[2]]
        first = line[0]

maxlen = len(max(list_of_list))
print("\t"+"\t".join([str(el) for el in range(1,maxlen+1)])+"\n")
for i in range(len(list_of_list)):
    print(str(i+1)+"\t"+"\t".join([str(el) for el in list_of_list[i]])+"\n")

无论如何,你可能需要在块中处理矩阵(并进行交换),因为数据可能不适合二维数组