从csv文件创建矩阵-Python
我试图从.csv文件中读取一些数字,并使用Python将它们存储到矩阵中。输入文件如下所示 输入文件从csv文件创建矩阵-Python,python,parsing,csv,matrix,Python,Parsing,Csv,Matrix,我试图从.csv文件中读取一些数字,并使用Python将它们存储到矩阵中。输入文件如下所示 输入文件 B,1 A,1 A,1 B,1 A,3 A,2 B,1 B,2 B,2 输入将被操纵成一个矩阵,如- 输出文件 1 2 3 A 2 1 1 B 3 2 0 这里,输入文件的第一列变为行,第二列变为列,值为发生次数的计数。我应该如何实现这一点?我的输入文件的大小很大(1000000行),因此可以有大量的行(介于50到10000之间)和列(从1到50)以下解决方案仅使用标准Python模块
B,1
A,1
A,1
B,1
A,3
A,2
B,1
B,2
B,2
输入将被操纵成一个矩阵,如-
输出文件
1 2 3
A 2 1 1
B 3 2 0
这里,输入文件的第一列变为行,第二列变为列,值为发生次数的计数。我应该如何实现这一点?我的输入文件的大小很大(1000000行),因此可以有大量的行(介于50到10000之间)和列(从1到50)以下解决方案仅使用标准Python模块:
import csv, collections, itertools
with open('my.csv', 'r') as f_input:
counts = collections.Counter()
for cols in csv.reader(f_input):
counts[(cols[0], cols[1])] += 1
keys = set(key[0] for key in counts.keys())
values = set(counts.values())
d = {}
for k in itertools.product(keys, values):
d[(k[0], str(k[1]))] = 0
d.update(dict(counts))
with open('output.csv', 'wb') as f_output:
csv_output = csv.writer(f_output)
# Write the header, 'X' is whatever you want the first column called
csv_output.writerow(['X'] + sorted(values))
# Write the rows
for k, g in itertools.groupby(sorted(d.items()), key=lambda x: x[0][0]):
csv_output.writerow([k] + [col[1] for col in g])
这将为您提供一个输出CSV文件,如下所示:
X,1,2,3
A,2,1,1
B,3,2,0
对于大量的输入数据,我的解决方案似乎不是很有效,因为我正在手动完成很多工作,这些工作可能可以通过一些DataFrame方法完成 但是,这可以完成以下任务:
#!/usr/bin/env python3
# coding: utf-8
import pandas as pd
from collections import Counter
with open('foo.txt') as f:
l = f.read().splitlines()
numbers_list = []
letters_list = []
for element in l:
letter = element.split(',')[0]
number = element.split(',')[1]
if number not in numbers_list:
numbers_list.append(number)
if letter not in letters_list:
letters_list.append(letter)
c = Counter(l)
d = dict(c)
output = pd.DataFrame(columns=sorted(numbers_list), index=sorted(letters_list))
for col in numbers_list:
for row in letters_list:
key = '{},{}'.format(row, col)
if key in d:
output[col][row] = d[key]
else:
output[col][row] = 0
输出符合要求:
1 2 3
A 2 1 1
B 3 2 0
以下是使用标准模块的另一个变体:
import csv
import re
from collections import defaultdict
from itertools import chain
d = defaultdict(list)
with open('data.csv', 'rb') as f:
reader = csv.reader(f, delimiter=',')
for row in reader:
d[row[0]].append(row[1])
k = sorted(d.keys())
v = sorted(map(int,set(chain.from_iterable(d.values()))))
e = []
for i in d:
e.append([0]*len(v))
for j in d[i]:
e[-1][int(j)-1] += 1
print ' ', re.sub(r'[\[\],]','',str(v))
for i, j in enumerate(k):
print j, re.sub(r'[\[\],]','',str(e[i]))
给定data.csv包含问题中显示的输入文件内容,此脚本将以下内容打印为输出:
1 2 3
A 2 1 1
B 3 2 0
感谢@zyxue提供的纯熊猫解决方案。它所需的前期代码要少得多,问题在于如何选择它。然而,对于运行时性能而言,额外的编码并不一定是徒劳的。使用IPython中的timeit来测量我的代码与使用纯pandas的&zyzue代码之间的运行时差异,我发现我的方法在排除导入和输入IO的情况下运行快36倍,在排除输出IO(打印语句)的情况下运行快121倍。这些测试是用函数来封装代码块的。以下是使用Python 2.7.10和Pandas 0.16.2测试的函数:
def p(): # 1st pandas function
s = df.groupby(['label', 'value']).size()
m = s.unstack()
m.columns.name = None
m.index.name = None
m = m.fillna(0)
print m
def p1(): # 2nd pandas function - omitting print statement
s = df.groupby(['label', 'value']).size()
m = s.unstack()
m.columns.name = None
m.index.name = None
m = m.fillna(0)
def q(): # first std mods function
k = sorted(d.keys())
v = sorted(map(int,set(chain.from_iterable(d.values()))))
e = []
for i in d:
e.append([0]*len(v))
for j in d[i]:
e[-1][int(j)-1] += 1
print ' ', re.sub(r'[\[\],]','',str(v))
for i, j in enumerate(k):
print j, re.sub(r'[\[\],]','',str(e[i]))
def q1(): # 2nd std mods function - omitting print statements
k = sorted(d.keys())
v = sorted(map(int,set(chain.from_iterable(d.values()))))
e = []
for i in d:
e.append([0]*len(v))
for j in d[i]:
e[-1][int(j)-1] += 1
在测试之前,运行以下代码以导入模块、输入IO并初始化所有函数的变量:
import pandas as pd
df = pd.read_csv('data.csv', names=['label', 'value'])
import csv
from collections import defaultdict
from itertools import chain
import re
d = defaultdict(list)
with open('data.csv', 'rb') as f:
reader = csv.reader(f, delimiter=',')
for row in reader:
d[row[0]].append(row[1])
data.csv输入文件的内容为:
B,1
A,1
A,1
B,1
A,3
A,2
B,1
B,2
B,2
每个函数的测试命令行的格式如下:
%timeit fun()
以下是测试结果:
p():100个循环,每个循环最好3:4.47毫秒
p1():1000个循环,每个循环最好3:1.88毫秒
q():10000个循环,每个循环最好3:123µs
q1():100000个回路,每个回路最好为3:15.5µs
这些结果只是一个小数据集的提示性结果。特别是,我希望pandas在一定程度上对更大的数据集有更好的表现。有了pandas,这变得很容易,几乎只需要3行代码
import pandas as pd
df = pd.read_csv('example.csv', names=['label', 'value'])
# >>> df
# label value
# 0 B 1
# 1 A 1
# 2 A 1
# 3 B 1
# 4 A 3
# 5 A 2
# 6 B 1
# 7 B 2
# 8 B 2
s = df.groupby(['label', 'value']).size()
# >>> s
# label value
# A 1 2
# 2 1
# 3 1
# B 1 3
# 2 2
# dtype: int64
# ref1: http://stackoverflow.com/questions/15751283/converting-a-pandas-multiindex-dataframe-from-rows-wise-to-column-wise
# ref2: http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.unstack.html
m = s.unstack()
# >>> m
# value 1 2 3
# label
# A 2 1 1
# B 3 2 NaN
# Below are optional: just to make it look more like what you want
m.columns.name = None
m.index.name = None
m = m.fillna(0)
print m
# 1 2 3
# A 2 1 1
# B 3 2 0
这里有一种使用Hadoop流处理MapReduce的方法,其中mapper和reducer脚本都读取stdin 映射器脚本主要是一种输入机制,它过滤输入以删除不正确的数据,其优点是输入可以在多个映射器进程上拆分,总输出自动排序并转发到缩减器,还可以在映射器节点上本地运行合并器。组合器本质上是中间减缩器,用于通过集群上的并行性加速减缩
# mapper script
import sys
import re
# mapper
for line in sys.stdin:
line = line.strip()
word = line.split()[0]
if word and re.match(r'\A[a-zA-Z]+,[0-9]+',word):
print '%s\t%s' % (word)
reducer脚本在所有映射器上获得排序输出,为每个输入键(如A或B)构建一个中间dict,在代码中称为“前缀”,并以csv格式将结果输出到文件
# reducer script
from collections import defaultdict
import sys
def output(s,d):
"""
this function takes a string s and dictionary d with int keys and values
and sorts the keys then creates a string of comma-separate values ordered
by the keys with appropriate insertion of comma-separate zeros equal in
number to the difference between successive keys minus one
"""
v = sorted(d.keys())
o = str(s) + ','
lastk = 0
for k in v:
o += '0,'*(k-lastk-1) + str(d[k]) + ','
lastk = k
return o
prefix = ''
current_prefix = ''
d = defaultdict(int)
maxkey = 0
for line in sys.stdin:
line = line.strip()
prefix,value = line.split(',')
try:
value = int(value)
except ValueError:
continue
if current_prefix == prefix:
d[value] += 1
else:
if current_prefix:
if len(d) > 0:
print output(current_prefix,d)
t = max(d.keys())
if t > maxkey:
maxkey = t
d = defaultdict(int)
current_prefix = prefix
d[value] += 1
# output info for last prefix if needed
if current_prefix == prefix:
print output(prefix,d)
t = max(d.keys())
if t > maxkey:
maxkey = t
# output csv list of keys from 1 through maxkey
h = ' ,'
for i in range(1,maxkey+1):
h += str(i) + ','
print h
若要运行数据流处理,请在映射程序获得以下信息的情况下:
B,1
A,1
A,1
B,1
A,3
A,2
B,1
B,2
B,2
它直接输出相同的内容,然后对所有内容进行排序(洗牌)并发送到减速机。在本例中,减速器得到的是:
A,1
A,1
A,2
A,3
B,1
B,1
B,1
B,2
B,2
最后,减速器的输出为:
A,2,1,1,
B,3,2,
,1,2,3,
对于较大的数据集,输入文件将被拆分为包含某些键集的所有数据的部分,这些键集将被分别映射到不同的映射器。在每个映射器节点上使用组合器将节省总体排序时间。仍然需要一个单独的减速机,以便输出完全按键排序。如果不需要,可以使用多个减速器
出于实际原因,我做了两个选择。首先,每一行输出只升到一个键的最高整数,尾随的零不会被打印,因为在处理完所有输入之前,无法知道要写入多少,对于大输入来说,这意味着将大量中间数据存储在内存中,或者通过将其写入磁盘并读回以完成任务来降低处理速度。第二,也是出于同样的原因,只有在reduce作业结束之前才能写入头行,因此这是头行被写入的时间。可以在输出文件中预先添加它,如果输出已被拆分,则可以在适当的时候对其进行调查。然而,如果并行处理的性能大大提高,那么对于大量输入来说,这些都是小问题
此方法在Spark群集上只需进行相对较小但至关重要的修改,如有必要,可以转换为Java或Scala以提高性能。到目前为止您做了哪些尝试?请添加一些代码,显示您当前所处的位置。如何读取文件?你怎么读一行?如何将逗号分隔的行解析为标记?你如何将字母A=1、B=2等联系起来。?把复杂的问题分解成简单的问题。您的输入文件格式没有多大意义。我希望每行有三个值:行#,列#,和值。可能是这篇文章的副本:在重读问题之后,我认为OP想要计算数字的出现次数,就像将它们与字母组合一样,因为whished输出似乎是输入文件中给出的出现次数的一种摘要。在重读问题之后,我认为OP想要计算数字的出现次数数字的出现次数将它们与字母组合在一起,因为whished输出似乎是输入文件中给出的出现次数的一种总结。非常感谢!我现在正在学习pandas,知道要使用的3行代码对我来说并不容易,所以您的示例很有帮助。我对我的方法与你的方法进行了基准测试,发现我的方法至少在一个小数据集上运行得更快。也许这就是我