【问题标题】:Creating a matrix from CSV file从 CSV 文件创建矩阵
【发布时间】:2017-03-20 16:38:26
【问题描述】:

我已经在 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 列感兴趣。所以第一列和第二列基本上就像矩阵的坐标,然后用第三列的数据填充矩阵。

经过大量试验和错误,我意识到 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,但它似乎要求我的数据已经是矩阵形式,但事实并非如此。

【问题讨论】:

  • 我不明白最后两列的意思。前三个是明确的...(行、列、值)

标签: python csv parsing numpy matrix


【解决方案1】:

这是我仅使用 csv 库并使用 csv 中的索引\位置的解决方案(使用我用来在当前行上保持内存的偏移量)

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")

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

【讨论】:

  • 嘿,我尝试运行代码,第 7 行出现错误,显示“MemoryError”。有什么想法吗?
  • 您是使用之前发布的 csv 还是其他 csv 作为输入?一个更大的,也许?我没有在更大的例子上测试它
  • 可能您的 csv 太大而无法放入内存,因此您需要使用迭代器
  • 是的,CSV 文件大约 800mbs,所以它相当大。我过去曾尝试使用生成器/迭代器,但没有成功。也只使用列表理解,但也无法转换它:(所以我认为 numpy 是要走的路。如果需要,我可以发送 CSV 文件
  • 我不需要,以后我会尝试用迭代器写一些东西
【解决方案2】:

您应该认真考虑使用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 对象(将名称更改为对您的应用程序更有用的名称)。数据透视表创建您正在寻找的矩阵,并优雅地处理任何缺失的数据。

【讨论】:

  • 感谢您的评论。如果我发送 CSV 文件会有帮助吗?经过多次尝试,我无法让它工作。错误是:AttributeError: 'module' object has no attribute 'read_csv'
  • @dizzyLife:您使用的是哪个版本的 Pandas?如果您已将 pandas 作为 pd 导入,请在 python 中键入“pd.__version__”。我使用的是 pandas 0.18.0,所以也许你需要更新的 pandas 版本?
  • @dizzyLife:忽略之前的评论,read_csv 从一开始就在 pandas 中。您的错误可能意味着 pandas 未正确安装。运行“import pandas as pd”是否会产生任何异常?
  • 有没有办法让我能够使用该代码,然后跳过几行?很多我不想要的垃圾数据。
  • 如果您的意思是在文件的开头,您可以使用 read_csv 中的 skiprows 选项。否则,pivot_table 返回一个 Pandas DataFrame,它有许多用于切片和选择数据的选项。见这里:pandas.pydata.org/pandas-docs/stable/indexing.html
【解决方案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.]])

【讨论】:

  • 您好,首先感谢您的帮助。我尝试通过将 test.txt 替换为名为 file.csv 的 csv 文件来运行代码,但出现错误:IDLE 的子进程未建立连接。 IDLE 无法启动子进程或个人软件阻止了连接。难道我只需要把所有数据都放在记事本里吗?
  • @dizzyLife 当然可以,但请确保您只保留了有效数据,在这种情况下,我只保留了第三列,否则您将不得不这样做:l, c, v = np.loadtxt("file.csv", skiprows=1).T[:3, :] 将阅读限制为最多第三列(当转置到第三行时)
  • @dizzyLife 还要检查csv 文件中的分隔符是否与空格不同。如果是,您必须将delimiter="," 传递给loadtxt 函数(或您在那里拥有的另一个分隔符)
  • 文件太大,我无法将粘贴数据复制到单独的文件中,因此使用了 csv。有什么方法可以联系到你吗?
  • @dizzyLife 无需复制所有数据,只需使用l, c, v = np.loadtxt("file.csv", skiprows=1).T[:3, :] 加载,或在必要时传递delimiter
猜你喜欢
  • 1970-01-01
  • 2019-02-15
  • 2017-10-28
  • 2018-08-03
  • 2017-03-24
  • 2021-11-15
  • 1970-01-01
  • 2018-02-05
  • 1970-01-01
相关资源
最近更新 更多