资讯专栏INFORMATION COLUMN

csv文件与字典,列表等之间的转换小结【Python】

econi / 2324人阅读

摘要:本文针对前面利用所做的一次数据匹配实验,整理了其中的一些对于文件的读写操作和常用的数据结构如字典和列表之间的转换文件与列表之间的转换将列表转换为文件将嵌套字典的列表转换为文件将列表转换为文件最基本的转换,将列表中的元素逐行写入到文件中将嵌套

本文针对前面利用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

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

# convert csv file to dict
# @params:
# key/value: the column of original csv file to set as the key and value of dict
def csv2dict(in_file,key,value):
    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[key]] = row[value]
    return new_dict

其中的new_dict[row[key]] = row[value]中的"key""value"是csv文件中的对应的第一行的属性字段,需要注意的是这里假设csv文件比较简单,所指定的key是唯一的,否则直接从csv转换为dict文件会造成重复字段的覆盖而丢失数据,如果原始数据指定作为key的列存在重复的情况,则需要构建列表字典,将value部分设置为list,可参照列表字典的构建部分代码

每一行为key,value的记录

针对每一行均为键值对的特殊情形
这里默认认为第一列为所构建的字典的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中的某些列对应的值作为某一个列的值的情形
或者说本身并不适合作为单纯的字典结构,同一个键对应的值不唯一

# build a dict of list like {key:[...element of lst_inner_value...]}
# key is certain column name of csv file
# the lst_inner_value is a list of specific column name of csv file
def build_list_dict(source_file, key, lst_inner_value):
    new_dict = {}
    with open(source_file, "rb")as csv_file:
        data = csv.DictReader(csv_file, delimiter=",")
        for row in data:
            for element in lst_inner_value:
                new_dict.setdefault(row[key], []).append(row[element])
    return new_dict
# sample:
# test_club=build_list_dict("test_info.csv","season",["move from","move to"])
# print test_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

[更新]
进一步改进后可以使用更加灵活一点的方法来构建二级字典,不用修改内部代码,二是指定传入的键和值,有两种不同的字典构建,按需查看

构建的二级字典的各层级的键值均人为指定为某一列的值

# build specific nested dict from csv files
# @params:
#   source_file
#   outer_key:the outer level key of nested dict
#   inner_key:the inner level key of nested dict
#   inner_value:set the inner value for the inner key
def build_level2_dict2(source_file,outer_key,inner_key,inner_value):
    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[outer_key], dict())
            item[row[inner_key]] = row[inner_value]
            new_dict[row[outer_key]] = item
    return new_dict

指定第一层和第二层的字典的键,而将csv文件中剩余的键值对存储为最内层的值

# build specific nested dict from csv files
# @params:
#   source_file
#   outer_key:the outer level key of nested dict
#   inner_key:the inner level key of nested dict,and rest key-value will be store as the value of inner key
def build_level2_dict(source_file,outer_key,inner_key):
    new_dict = {}
    with open(source_file, "rb")as csv_file:
        reader = csv.reader(csv_file, delimiter=",")
        fieldnames = next(reader)
        inner_keyset=fieldnames
        inner_keyset.remove(outer_key)
        inner_keyset.remove(inner_key)
        csv_file.seek(0)
        data = csv.DictReader(csv_file, delimiter=",")
        for row in data:
            item = new_dict.get(row[outer_key], dict())
            item[row[inner_key]] = {k: row[k] for k in inner_keyset}
            new_dict[row[outer_key]] = 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文件并不适合直接构造单纯的字典结构,某些键对应多个值,所以需要在内部用列表来保存值,或者对每一个键值对用列表保存

用列表保存键值对
# build specific nested dict from csv files
# @params:
#   source_file
#   outer_key:the outer level key of nested dict
#   lst_inner_value: a list of column name,for circumstance that the inner value of the same outer_key are not distinct
#   {outer_key:[{pairs of lst_inner_value}]}
def build_level2_dict3(source_file,outer_key,lst_inner_value):
    new_dict = {}
    with open(source_file, "rb")as csv_file:
        data = csv.DictReader(csv_file, delimiter=",")
        for row in data:
            new_dict.setdefault(row[outer_key], []).append({k: row[k] for k in lst_inner_value})
    return new_dict
用列表保存值域
# build specific nested dict from csv files
# @params:
#   source_file
#   outer_key:the outer level key of nested dict
#   lst_inner_value: a list of column name,for circumstance that the inner value of the same outer_key are not distinct
#   {outer_key:{key of lst_inner_value:[...value of lst_inner_value...]}}
def build_level2_dict4(source_file,outer_key,lst_inner_value):
    new_dict = {}
    with open(source_file, "rb")as csv_file:
        data = csv.DictReader(csv_file, delimiter=",")
        for row in data:
            # print row
            item = new_dict.get(row[outer_key], dict())
            # item.setdefault("move from",[]).append(row["move from"])
            # item.setdefault("move to", []).append(row["move to"])
            for element in lst_inner_value:
                item.setdefault(element, []).append(row[element])
            new_dict[row[outer_key]] = item
    return new_dict
# build specific nested dict from csv files
# @params:
#   source_file
#   outer_key:the outer level key of nested dict
#   lst_inner_key:a list of column name
#   lst_inner_value: a list of column name,for circumstance that the inner value of the same lst_inner_key are not distinct
#   {outer_key:{lst_inner_key:[...lst_inner_value...]}}
def build_list_dict2(source_file,outer_key,lst_inner_key,lst_inner_value):
    new_dict = {}
    with open(source_file, "rb")as csv_file:
        data = csv.DictReader(csv_file, delimiter=",")
        for row in data:
            # print row
            item = new_dict.get(row[outer_key], dict())
            item.setdefault(row[lst_inner_key], []).append(row[lst_inner_value])
            new_dict[row[outer_key]] = item
    return new_dict

# dct=build_list_dict2("test_info.csv","season","move from","move to")
构造三级字典

类似的,可以从csv重构造三级字典甚至多级字典,方法和上面的类似,就不赘述了,只贴代码

# build specific nested dict from csv files
# a dict like {outer_key:{inner_key1:{inner_key2:{rest_key:rest_value...}}}}
# the params are extract from the csv column name as you like
def build_level3_dict(source_file,outer_key,inner_key1,inner_key2):
    new_dict = {}
    with open(source_file, "rb")as csv_file:
        reader = csv.reader(csv_file, delimiter=",")
        fieldnames = next(reader)
        inner_keyset=fieldnames
        inner_keyset.remove(outer_key)
        inner_keyset.remove(inner_key1)
        inner_keyset.remove(inner_key2)
        csv_file.seek(0)
        data = csv.DictReader(csv_file, delimiter=",")
        for row in data:
            item = new_dict.get(row[outer_key], dict())
            sub_item = item.get(row[inner_key1], dict())
            sub_item[row[inner_key2]] = {k: row[k] for k in inner_keyset}
            item[row[inner_key1]] = sub_item
            new_dict[row[outer_key]] = item
    return new_dict

# build specific nested dict from csv files
# a dict like {outer_key:{inner_key1:{inner_key2:inner_value}}}
# the params are extract from the csv column name as you like
def build_level3_dict2(source_file,outer_key,inner_key1,inner_key2,inner_value):
    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[outer_key], dict())
            sub_item = item.get(row[inner_key1], dict())
            sub_item[row[inner_key2]] = row[inner_value]
            item[row[inner_key1]] = sub_item
            new_dict[row[outer_key]] = item
    return new_dict

这里同样给出两种根据不同需求构建字典的方法,一种是将剩余的键值对原封不动地保存为最内部的值,另一种是只取所需要的键值对保留。

此外还有一种特殊情形,当你的最内部的值不是一个多带带的元素而需要是一个列表来存储多个对应同一个键的元素,则只需要对于最内部的键值对进行修改

# build specific nested dict from csv files
# a dict like {outer_key:{inner_key1:{inner_key2:[inner_value]}}}
# for multiple inner_value with the same inner_key2,thus gather them in a list
# the params are extract from the csv column name as you like
def build_level3_dict3(source_file,outer_key,inner_key1,inner_key2,inner_value):
    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[outer_key], dict())
            sub_item = item.get(row[inner_key1], dict())
            sub_item.setdefault(row[inner_key2], []).append(row[inner_value])
            item[row[inner_key1]] = sub_item
            new_dict[row[outer_key]] = item
    return new_dict

其中的核心部分是这一句
sub_item.setdefault(row[inner_key2], []).append(row[inner_value])

字典转换为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("
")
    for data in rows:
        f.write(",".join(str(data[h]) for h in header))
        f.write("
")

这里用到了三个包,除了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上找到或者自己提问解决,上面的朋友还是很给力的,后续会小结一下实验过程中的一些对数据的其他处理如格式转换,除重,重复判断等等

最后,源码我发布在github上的csv_toolkit里面,欢迎随意玩耍~


更新日志
1、2016-12-22: 改进了构建二级字典的方法,使其变得更加灵活
2、2016-12-24 14:55:30: 加入构造三级字典的方法
3、2017年1月9日11:26:59: 最内部可保存制定列的元素列表
4、2017年1月16日10:29:44:加入了列表字典的构建;针对特殊二级字典的构建(需要保存对应同一个键的多个值);
5、2017年2月9日10:54:41: 加入新的二级列表字典的构建
6、2017年2月10日11:18:01:改进了简单的csv文件到字典的构建代码

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/38187.html

相关文章

  • Python学习之路15-下载数据

    摘要:本节中将绘制幅图像收盘折线图,收盘价对数变换,收盘价月日均值,收盘价周日均值,收盘价星期均值。对数变换是常用的处理方法之一。 《Python编程:从入门到实践》笔记。本篇是Python数据处理的第二篇,本篇将使用网上下载的数据,对这些数据进行可视化。 1. 前言 本篇将访问并可视化以两种常见格式存储的数据:CSV和JSON: 使用Python的csv模块来处理以CSV(逗号分隔的值)...

    张春雷 评论0 收藏0
  • 针对Python初学者,这13个好用到起飞小技巧!

    摘要:如果你也是学习爱好者,今天讲述的个小技巧,真挺香欢迎收藏学习,喜欢点赞支持。因此,键将成为值,而值将成为键。幸运的是,这可以通过一行代码快速完成。因此,我们的代码不会因错误而终止。 ...

    张宪坤 评论0 收藏0
  • 一文带你斩杀Python之Numpy☀️Pandas全部操作【全网最详细】❗❗❗

    目录Numpy简介Numpy操作集合1、不同维度数据的表示1.1 一维数据的表示1.2 二维数据的表示1.3 三维数据的表示2、 为什么要使用Numpy2.1、Numpy的ndarray具有广播功能2.2 Numpy数组的性能比Python原生数据类型高3 ndarray的属性和基本操作3.1 ndarray的基本属性3.2 ndarray元素类型3.3 创建ndarray的方式3.4 ndarr...

    asoren 评论0 收藏0
  • 十三个好用到起飞Python技巧!

    摘要:因其在各个领域的实用性与和等其他编程语言相比的生产力以及与英语类似的命令而广受欢迎。反转字典一个非常常见的字典任务是如果我们有一个字典并且想要反转它的键和值。   ...

    ruicbAndroid 评论0 收藏0
  • Python3网络爬虫实战---31、数据存储:文件存储

    摘要:如果该文件已存在,文件指针将会放在文件的结尾。运行结果以上是读取文件的方法。为了输出中文,我们还需要指定一个参数为,另外规定文件输出的编码。 上一篇文章:Python3网络爬虫实战---30、解析库的使用:PyQuery下一篇文章:Python3网络爬虫实战---32、数据存储:关系型数据库存储:MySQL 我们用解析器解析出数据之后,接下来的一步就是对数据进行存储了,保存的形式可以...

    dreamans 评论0 收藏0

发表评论

0条评论

econi

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<