本文针对前面利用Python 所做的一次数据匹配实验,整理了其中的一些对于csv文件的读写操作和常用的Python\’数据结构\’(如字典和列表)之间的转换
(Python Version 2.7)


csv文件与列表之间的转换

  • 将列表转换为csv文件

  • 将嵌套字典的列表转换为csv文件

将列表转换为csv文件

最基本的转换,将列表中的元素逐行写入到csv文件中

def list2csv(list, file):
    wr = csv.writer(open(file, \'wb\'), quoting=csv.QUOTE_ALL)
    for word in list:
        wr.writerow([word])

将嵌套字典的列表转换为csv文件

这种属于典型的csv文件读写,常见的csv文件常常是第一行为属性栏,标明各个字段,接下来每一行都是对应属性的值,读取时常常用字典来存储(key为第一行的属性,value为对应行的值),例如

my_list = [{\'players.vis_name\': \'Khazri\', \'players.role\': \'Midfielder\', \'players.country\': \'Tunisia\',
            \'players.last_name\': \'Khazri\', \'players.player_id\': \'989\', \'players.first_name\': \'Wahbi\',
            \'players.date_of_birth\': \'08/02/1991\', \'players.team\': \'Bordeaux\'},
           {\'players.vis_name\': \'Khazri\', \'players.role\': \'Midfielder\', \'players.country\': \'Tunisia\',
            \'players.last_name\': \'Khazri\', \'players.player_id\': \'989\', \'players.first_name\': \'Wahbi\',
            \'players.date_of_birth\': \'08/02/1991\', \'players.team\': \'Sunderland\'},
           {\'players.vis_name\': \'Lewis Baker\', \'players.role\': \'Midfielder\', \'players.country\': \'England\',
            \'players.last_name\': \'Baker\', \'players.player_id\': \'9574\', \'players.first_name\': \'Lewis\',
            \'players.date_of_birth\': \'25/04/1995\', \'players.team\': \'Vitesse\'}
           ]

而最后所有的字典嵌套到一个列表中存储,而接下来是一个逆过程,即将这种嵌套了字典的列表还原为csv文件存储起来

# write nested list of dict to csv
def nestedlist2csv(list, out_file):
    with open(out_file, \'wb\') as f:
        w = csv.writer(f)
        fieldnames=list[0].keys()  # solve the problem to automatically write the header
        w.writerow(fieldnames)
        for row in list:
            w.writerow(row.values())

注意其中的fieldnames用于传递key即第一行的属性

csv文件与字典之间的转换

  • csv文件转换为字典

    • 第一行为key,其余行为value

    • 每一行为key,value的记录

  • csv文件转换为二级字典

  • 字典转换为csv文件

    • 第一行为key,其余行为value

    • 每一行为key,value的记录

csv文件转换为字典

第一行为key,其余行为value

针对常见的首行为属性,其余行为值的情形

def csv2dict(in_file):
    new_dict = {}
    with open(in_file, \'rb\') as f:
        reader = csv.reader(f, delimiter=\',\')
        fieldnames = next(reader)
        reader = csv.DictReader(f, fieldnames=fieldnames, delimiter=\',\')
        for row in reader:
            new_dict[row[\'id\']] = row[\'players.player_id\']
    return new_dict

其中的new_dict[row[\'id\']] = row[\'players.player_id\']中的\'id\'\'players.player_id\'是csv文件中的对应的第一行的属性字段

每一行为key,value的记录

针对每一行均为键值对的特殊情形

# convert csv file to dict(key-value pairs each row)
def row_csv2dict(csv_file):
    dict_club={}
    with open(csv_file)as f:
        reader=csv.reader(f,delimiter=\',\')
        for row in reader:
            dict_club[row[0]]=row[1]
    return dict_club

csv文件转换为二级字典

这个一般是特殊用途,将csv文件进一步结构化,将其中的某一列(属性)所对应的值作为key,然后将其余键值对构成子字典作为value,一般用于匹配时优先过滤来建立一种层级结构提高准确度
例如我有csv文件的记录如下(以表格形式表示)

id name age country
1 danny 21 China
2 Lancelot 22 America

经过二级字典转换后(假设构建country-name两级)得到如下字典

dct={\'China\':{\'danny\':{\'id\':\'1\',\'age\':\'21\'}}
     \'America\':{\'Lancelot\':{\'id\':\'2\',\'age\':\'22\'}}}

代码如下

# build specific nested dict from csv files(date->name)
def build_level2_dict(source_file):
    new_dict = {}
    with open(source_file, \'rb\')as csv_file:
        data = csv.DictReader(csv_file, delimiter=\",\")
        for row in data:
            item = new_dict.get(row[\'country\'], dict())
            item[row[\'name\']] = {k: row[k] for k in (\'id\',\'age\')}
            new_dict[row[\'country\']] = item
    return new_dict

参照这种方法可以构建三级字典,就不赘述了,感兴趣朋友的可以看我的另一篇文章中的实验记录

还有另一种构建二级字典的方法,利用的是pop()方法,但是个人觉得不如这个直观,贴在下面

def build_dict(source_file):
    projects = defaultdict(dict)
    # if there is no header within the csv file you need to set the header 
    # and utilize fieldnames parameter in csv.DictReader method
    # headers = [\'id\', \'name\', \'age\', \'country\']
    with open(source_file, \'rb\') as fp:
        reader = csv.DictReader(fp, dialect=\'excel\', skipinitialspace=True)
        for rowdict in reader:
            if None in rowdict:
                del rowdict[None]
            nationality = rowdict.pop(\"country\")
            date_of_birth = rowdict.pop(\"name\")
            projects[nationality][date_of_birth] = rowdict
    return dict(projects)

字典转换为csv文件

  • 每一行为key,value的记录

  • 第一行为key,其余行为value

  • 输出列表字典

每一行为key,value的记录

前述csv文件转换为字典的逆过程,比较简单就直接贴代码啦

def dict2csv(dict,file):
    with open(file,\'wb\') as f:
        w=csv.writer(f)
        # write each key/value pair on a separate row
        w.writerows(dict.items())
第一行为key,其余行为value
def dict2csv(dict,file):
    with open(file,\'wb\') as f:
        w=csv.writer(f)
        # write all keys on one row and all values on the next
        w.writerow(dict.keys())
        w.writerow(dict.values())
输出列表字典

其实这个不太常用,倒是逆过程比较常见,就是从常规的csv文件导入到列表的字典(本身是一个字典,csv文件的首行构成键,其余行依次构成对应列下的键的值,其中值形成列表),不过如果碰到这种情形要保存为csv文件的话,做法如下

import csv
import pandas as pd
from collections import OrderedDict

dct=OrderedDict()
dct[\'a\']=[1,2,3,4]
dct[\'b\']=[5,6,7,8]
dct[\'c\']=[9,10,11,12]

header = dct.keys()
rows=pd.DataFrame(dct).to_dict(\'records\')

with open(\'outTest.csv\', \'wb\') as f:
    f.write(\',\'.join(header))
    f.write(\'\\n\')
    for data in rows:
        f.write(\",\".join(str(data[h]) for h in header))
        f.write(\'\\n\')

这里用到了三个包,除了csv包用于常规的csv文件读取外,其中OrderedDict用于让csv文件输出后保持原有的列的顺序,而pandas则适用于中间的一步将列表构成的字典转换为字典构成的列表,举个例子

[(\'a\', [1, 2, 3, 4]), (\'b\', [5, 6, 7, 8]), (\'c\', [9, 10, 11, 12])]
to
[{\'a\': 1, \'c\': 9, \'b\': 5}, {\'a\': 2, \'c\': 10, \'b\': 6}, {\'a\': 3, \'c\': 11, \'b\': 7}, {\'a\': 4, \'c\': 12, \'b\': 8}]

特殊的csv文件的读取

这个主要是针对那种分隔符比较特殊的csv文件,一般情形下csv文件统一用一种分隔符是关系不大的(向上述操作基本都是针对分隔符统一用,的情形),而下面这种第一行属性分隔符是,而后续值的分隔符均为;的读取时略有不同,一般可逐行转换为字典在进行操作,代码如下:

def func(id_list,input_file,output_file):
    with open(input_file, \'rb\') as f:
        # if the delimiter for header is \',\' while \';\' for rows
        reader = csv.reader(f, delimiter=\',\')
        fieldnames = next(reader)

        reader = csv.DictReader(f, fieldnames=fieldnames, delimiter=\';\')        
        rows = [row for row in reader if row[\'players.player_id\'] in set(id_list)]
        # operation on rows...

可根据需要修改分隔符中的内容.

关于csv文件的一些操作我在实验过程中遇到的问题大概就是这些啦,大部分其实都可以在stackoverflow上找到或者自己提问解决,上面的朋友还是很给力的,后续会小结一下实验过程中的一些对数据的其他处理如格式转换,除重,重复判断等等