Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从csv文件创建矩阵-Python_Python_Parsing_Csv_Matrix - Fatal编程技术网

从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模块

我试图从.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模块:

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行代码对我来说并不容易,所以您的示例很有帮助。我对我的方法与你的方法进行了基准测试,发现我的方法至少在一个小数据集上运行得更快。也许这就是我