Python3分析CSV数据

2.1 基础Python与pandas

2.1.1 使用pandas处理CSV文件

读取CSV文件

#!/usr/bin/env python3
import sys
import pandas as pd

input_file = sys.argv[1]
output_file = sys.argv[2]
data_frame = pd.read_csv(input_file)
print(data_frame)
data_frame.to_csv(output_file, index=False)

使用Python内置的csv模块

#!/usr/bin/env python3
import csv
import sys

input_file = sys.argv[1]
output_file = sys.argv[2]
with open(input_file, 'r', newline=' ') as csv_in_file:
    with open(output_file, 'w', newline = ' ') as csv_out_fileL
        filereader = csv.reader(csv_in_file, delimiter = ',')
        filewriter = csv.writer(csv_out_file, delimiter = ',')
        for row_ist in filereader:
            print(row_list)
            filewriter.writerow(row_list)

with语句在语句结束时自动关闭文件对象。
使用csv模块reader函数创建文件读取对象filereader,读取输入文件中的行。
使用csv模块的writer函数创建文件写入对象filewriter,将数据写入输出文件。
函数的第二个参数(delimiter=',')是默认分隔符,如果输入和输出文件都用逗号分隔,就不需要此参数。
使用filewriter对象的writerow函数来将每行中的列表值写入输出文件。

2.2 筛选特定的行

在输入文件筛选出特定行的三种方法:

  • 行中的值满足某个条件
  • 行中的值属于某个集合
  • 行中的值匹配正则表达式

从输入文件中筛选出特定行的通用代码结构:

for row in filereader:
    ***if value in row meets some business rule or set of rules:***
        do something
    else:
        do something else

行中的值满足某个条件
pandas提供loc函数,可以同时选择特定的行与列。需要在逗号前设定行筛选条件,在逗号后设定列筛选条件。

例如,loc函数的条件设置为:Supplier Name列中姓名包含 Z,或者Cost列中的值大于600.0,并且需要所有的列。
pandas_value_meets_condition.py

#!/usr/bin/env python3
import pandas as pd
import sys

input_file = sys.argv[1]
output_file = sys.argv[2]
data_frame = pd.read_csv(input_file)
data_frame['Cost'] = data_frame['Cost'].str.strip('$').astype(float)
data_frame_value_meets_condition = data_frame.loc[(data_frame\
['Supplier Name'].str.contains('Z')) | (data_frame['Cost'] > 600.0), :]
data_frame_value_meets_condition.to_csv(output_file, index=False)

行中的值属于某个集合
例如,保留购买日期属于集合{'1/20/14', '1/30/14'} 的行,将结果写入输出文件。
pandas_value_in_set.py

#!/usr/bin/env python3
import pandas as pd
import sys

input_file = sys.argv[1]
output_file = sys.argv[2]
data_frame = pd.read_csv(input_file)
important_dates = ['1/20/14', '1/30/14']
data_frame_value_in_set = data_frame.loc[data_frame['Purchase Date'].\
isin(important_dates), :]
data_frame_value_in_set.to_csv(output_file, index=False)

行中的值匹配正则表达式
例如,保留发票编号由“001-”开头的行,并将结果写入输出文件。
pandas_value_matches_pattern.py

#!/usr/bin/env python3
import pandas as pd
import sys

input_file = sys.argv[1]
output_file = sys.argv[2]
data_frame = pd.read_csv(input_file)
data_frame_value_matches_pattern = \
data_frame.loc[data_frame['Invoice Number'].str.startswith("001-"), :]
data_frame_value_matches_pattern.to_csv(output_file, index=False)

使用pandas时,使用startswith函数来搜索数据。

2.3选取特定列

列索引值

#!/usr/bin/env python3
import pandas as pd
import sys

input_file = sys.argv[1]
output_file = sys.argv[2]
data_frame = pd.read_csv(input_file)
data_frame_column_by_index = data_frame.iloc[:, [0, 3]]
# 用iloc函数根据索引位置选取列
data_frame_column_by_index.to_csv(output_file, index=False)

列标题

只保留发票号码和购买日期两列。

#!/usr/bin/env python3
import pandas as pd
import sys

input_file = sys.argv[1]
output_file = sys.argv[2]
data_frame = pd.read_csv(input_file)
data_frame_column_by_name = data_frame.loc[:, ['Invoice Number', \
                                               'Purchase Date']]
# 用loc函数选取列,这次使用的是列标题
data_frame_column_by_name.to_csv(output_file, index=False)

2.4 选取连续的行

pandas提供drop函数根据行索引或列标题来丢弃行或列,提供iloc函数根据行索引选取一个单独行作为列索引,提供reindex函数为数据框重新生成索引。

#!/usr/bin/env python3
import pandas as pd
import sys

input_file = sys.argv[1]
output_file = sys.argv[2]
data_frame = pd.read_csv(input_file, header=None)
data_frame = data_frame.drop([0, 1, 2, 16, 17, 18])
data_frame.columns = data_frame.iloc[0]
data_frame = data_frame.reindex(data_frame.index.drop(3))
data_frame.to_csv(output_file, index=False)

2.5 添加标题行

pandas的read_csv函数可以指定输入文件不包含标题行,并可以提供一个列标题列表。

#!/usr/bin/env python3
import pandas as pd
import sys

input_file = sys.argv[1]
output_file = sys.argv[2]
header_list = ['Supplier Name', 'Invoice Number',\
               'Part Number', 'Cost', 'Purchase Date']
data_frame = pd.read_csv(input_file, header=None, names=header_list)
data_frame.to_csv(output_file, index=False)

2.6 读取多个CSV文件

文件计数与文件中的行列计数

#!/usr/bin/env python3
import csv
import glob
# glob模块可以定位匹配于某个特定模式的所有路径名。
# 模式中可以包含Unixshell风格的通配符,比如*。
import os
# os 模块包含用于解析路径名的函数。
# 例如,os.path.basename(path) 返回path的基本文件名。
# 即,如果path是C:\Users\Clinton\Desktop\my_input_file.csv,
# 那么os.path.basename(path) 返回my_input_file.csv。
import sys

input_path = sys.argv[1]

file_counter = 0
for input_file in glob.glob(os.path.join(input_path, 'sales_*')):
    row_counter = 1
    with open(input_file, 'r', newline='') as csv_in_file:
        filereader = csv.reader(csv_in_file)
        header = next(filereader, None)
        for row in filereader:
            row_counter += 1
    print('{0!s}: \t{1:d} rows \t{2:d} columns'.format(\
os.path.basename(input_file), row_counter, len(header)))
    file_counter += 1
print('Number of files: {0:d}'.format(file_counter))

创建for循环,在一个输入文件集合中迭代,并使用glob模块和os模块中的函数创建输入文件列表以供处理。
os模块的os.path.join()函数将函数圆括号中的两部分连接在一起。input_path是包含输入文件的文件夹的路径,'sales_' 代表任何以模式'sales_' 开头的文件名。
glob 模块中的glob.glob() 函数将'sales_
' 中的星号(*)转换为实际的文件名。在这个示例中,glob.glob() 函数和os.path.join() 函数创建了一个包含3 个输入文件的列表:
['C:\Users\Clinton\Desktop\sales_january_2014.csv',
'C:\Users\Clinton\Desktop\sales_february_2014.csv',
'C:\Users\Clinton\Desktop\sales_march_2014.csv']
然后,这行开头的for 循环语句对于列表中每个输入文件执行下面缩进的各行代码。

这行代码使用{}占位符将3 个值传入print 语句。对于第一个值,使用os.path.basename() 函数从完整路径名中抽取出基本文件名。对于第二个值,使用row_counter 变量来计算每个输入文件中的总行数。最后,对于第三个值,使用内置的len 函数计算出列表变量header 中的值的数量,这个列表变量中包含了每个输入文件的列标题列表。我们使用这个值作为每个输入文件中的列数。最后,在第15 行代码打印了每个文件的信息之后,第17 行代码使用file_counter 变量中的值显示出脚本处理的文件的数量。

要运行这个脚本,在命令行中输入以下命令,然后按回车键:

python 8csv_reader_counts_for_multiple_files.py "C:\Users\Clinton\Desktop"

要处理多个文件,所以必须使用包含所有输入文件的文件夹。

2.7 从多个文件中连接数据

pandas可以直接从多个文件中连接数据。基本过程就是将每个输入文件读取到pandas数据框中,将所有数据框追加到一个数据框列表,然后使用concat 函数将所有数据框连接成一个数据框。concat函数可以使用axis 参数来设置连接数据框的方式,axis=0 表示从头到尾垂直堆叠,axis=1 表示并排地平行堆叠。

#!/usr/bin/env python3
import pandas as pd
import glob
import os
import sys

input_path = sys.argv[1]
output_file = sys.argv[2]
all_files = glob.glob(os.path.join(input_path,'sales_*'))
all_data_frames = []
for file in all_files:
    data_frame = pd.read_csv(file, index_col=None)
    all_data_frames.append(data_frame)
data_frame_concat = pd.concat(all_data_frames, axis=0, ignore_index=True)
data_frame_concat.to_csv(output_file, index = False)

这段代码垂直堆叠数据框。如果你需要平行连接数据,那么就在concat 函数中设置axis=1。除了数据框,pandas 中还有一个数据容器,称为序列。你可以使用同样的语法去连接序列,只是要将连接的对象由数据框改为序列。有时候,除了简单地垂直或平行连接数据,你还需要基于数据集中的关键字列的值来连接数据集。pandas 提供了类似SQL join 操作的merge 函数。如果你很熟悉SQL join,那么就非常容易理解merge 函数的语法:pd.merge(DataFrame1, DataFrame2, on='key', how='inner')。

Python 的另一个内置模块NumPy 也提供了若干函数来垂直或平行连接数据。通常是将NumPy 导入为np。然后,要垂直连接数据,你可以使用np.concatenate([array1, array2], axis=0)、np.vstack((array1, array2)) 或np.r_[array1, array2]。同样,要平行连接数据,你可以使用np.concatenate([array1, array2], axis=1)、np.hstack((array1, array2)) 或np.c_[array1, array2]。

2.8 计算每个文件中值的总和与均值

pandas 提供了可以用来计算行和列统计量的摘要统计函数,比如sum 和mean。下面的代码演示了如何对于多个文件中的某一列计算这两个统计量(总计和均值),并将每个输入文件的计算结果写入输出文件。

#!/usr/bin/env python3
import pandas as pd
import glob
import os
import sys

input_path = sys.argv[1]
output_file = sys.argv[2]
all_files = glob.glob(os.path.join(input_path,'sales_*'))
all_data_frames = []
for input_file in all_files:
    data_frame = pd.read_csv(input_file, index_col=None)

    total_cost = pd.DataFrame([float(str(value).strip('$').replace(',','')) \
                 for value in data_frame.loc[:, 'Sale Amount']]).sum()

    average_cost = pd.DataFrame([float(str(value).strip('$').replace(',','')) \
                   for value in data_frame.loc[:, 'Sale Amount']]).mean()

    data = {'file_name': os.path.basename(input_file), 
            'total_sales': total_sales, 
            'average_sales': average_sales}

    all_data_frames.append(pd.DataFrame(data, \
    columns=['file_name', 'total_sales', 'average_sales']))

data_frames_concat = pd.concat(all_data_frames, axis=0, ignore_index=True)
data_frames_concat.to_csv(output_file, index = False)

列表生成式将销售额列中带美元符号的字符串转换为浮点数,然后使用数据框函数将此对象转换为DataFrame,以便可以使用这两个函数计算列的总计和均值。

因为输出文件中的每行应该包含输入文件名,以及文件中销售额的总计和均值,所以可以将这3 种数据组合成一个文本框,使用concat 函数将这些数据框连接成为一个数据框,然后将这个数据框写入输出文件。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,561评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,218评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,162评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,470评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,550评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,806评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,951评论 3 407
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,712评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,166评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,510评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,643评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,306评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,930评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,745评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,983评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,351评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,509评论 2 348

推荐阅读更多精彩内容