我已经在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,但看起来它需要我的数据已经是矩阵形式,而不是。
答案 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")
无论如何,你可能需要在块中处理矩阵(并进行交换),因为数据可能不适合二维数组