忘记密码   免费注册 查看新帖 |

ChinaUnix.net

  平台 论坛 博客 文库 频道自动化运维 虚拟化 储存备份 C/C++ PHP MySQL 嵌入式 Linux系统
最近访问板块 发新帖
查看: 1577 | 回复: 0

总结贴,记录下pandas处理一大批数据 [复制链接]

论坛徽章:
0
发表于 2018-03-22 21:02 |显示全部楼层
零零散散写过好多脚本,总没有记录的习惯,花了两天时间,从坑里爬了出来,回头看看,常在河边走,以后常备尿不湿。

简单说下目的,目的不明确,每一行代码都是bug。

有一批文件,每个文件每行按照 | 分隔,文件中的字段与Excel表中的sheet页对应。

Excel.jpg

简单说就是按照Excel中sheet页中对应的字段规则,去验证一批文件字段是否正确。
我用的是python 3.6, python有点坑,向下不兼容,肯定不支持2.7
# -*- coding: utf-8 -*-

import os
import re
import time
import argparse
import numpy as np
import xlrd
import xlwt
import glob
from framework.logger import Logger
import pandas as pd

    #
    # 解析Excel, 得到表头和验证规则
    #
    header_names = {}       # 存储Excel中的sheet和字段
    for e in glob.glob(os.path.join(args.configExcel, "*.xlsx")):  # 多个Excel中一同处理
        logger.info("Getting config file: {}".format(e))               # logger 可以去掉
        workbook = xlrd.open_workbook(e)                              # 用xlrd打开每个excel
        sheets   = workbook.sheet_names()                             #  得到打开Excel的所有sheet页得名字
        for idx in range(1,len(sheets)):                                     # 遍历所有的sheet页面                          
            cols = workbook.sheet_by_name(sheets[idx]).col_values(2)    # 得到第二列的长度,就是图中第一个红框的长度workbook.sheet_by_name(),by谁就是用那个sheet
            for tmp_row in range(1, len(cols)):                                        # 遍历第二列中所有元素
                if(workbook.sheet_by_name(sheets[idx]).cell(tmp_row, 2).value and (not workbook.sheet_by_name(sheets[idx]).cell(tmp_row, 4).value)):
                    #
                    # 字段和值必须一一匹配,不能有值没字段或者有字段没有值
                    #
                    logger.error("%s: line %s not match in %s"%(sheets[idx], workbook.sheet_by_name(sheets[idx]).cell(tmp_row, 2).value,workbook.sheet_by_name(sheets[idx]).cell(tmp_row, 4).value))                # logger,可以去掉
                else:
                    if(workbook.sheet_by_name(sheets[idx]).cell(tmp_row, 2).value.strip() != ""):  # 这里判断第二列是否有空值,合并单元格可能就是空值(这个没尝试)。
                                                                                                                                         # 看着很长,by就是用哪个sheet,cell就是(行,列),value就是取值,python3.6有个好处就是不用判断中英文,方便多了

                        if sheets[idx] not in header_names:                                               # 字典的传统套路,用之前先看看key是否存在,不存在就初始化,存在就是直接用                       
                            header_names[sheets[idx]] = []                                                # 不存在就是赋予这个key新的使命,value是列表。
                        header_names[sheets[idx]].append(workbook.sheet_by_name(sheets[idx]).cell(tmp_row, 2).value)  # sheet是字典的key值,sheet中所有的第二列字段是list值
                        if sheets[idx] not in dict:                                                              # 这个字典存储sheet表中第四列的值
                            dict[sheets[idx]] = {}                                                              # 也可以用一个字典,但是可能需要字典升级为三维,考虑到我的单核脑处理器,在搞一个字典
                        if(('BigtoPre' in workbook.sheet_by_name(sheets[idx]).cell(tmp_row, 4).value) and ("=" in workbook.sheet_by_name(sheets[idx]).cell(tmp_row, 4).value)):
                            #
                            # 10<collastcol<100(D=-1)
                            #  这个是特殊列,这列的意思是 这列减去上列大于10或者小于100,或者是缺省值-1
                            #
                            list_a = re.findall("[\-|\d]+\.?\d*",workbook.sheet_by_name(sheets[idx]).cell(tmp_row, 4).value)  # 抓出第四列中所有的数字,正负都要
                            actualValue = workbook.sheet_by_name(sheets[idx]).cell(tmp_row, 2).value + ',' + workbook.sheet_by_name(sheets[idx]).cell((tmp_row -1), 2).value + "," + ">pythonD" + "," + str(list_a)              # 做了转换,换成以后好处理的格式,就是全是逗号分隔,并且写了关键字 pythonD,以后我匹配pythonD,就知道是这个特殊行
                            dict[sheets[idx]][workbook.sheet_by_name(sheets[idx]).cell(tmp_row, 2).value] = actualValue  # 换了之后的值是 col, lastcol, pythonD, 10, 100, -1
                        elif(('BigtoPre' in workbook.sheet_by_name(sheets[idx]).cell(tmp_row, 4).value) and ("=" not in workbook.sheet_by_name(sheets[idx]).cell(tmp_row, 4).value)):
                            #
                            # 10<BigtoPre<100
                            # 这个和上面一样,就是少了默认值而已
                            #
                            list_a = re.findall("[\-|\d]+\.?\d*",workbook.sheet_by_name(sheets[idx]).cell(tmp_row, 4).value)
                            actualValue = workbook.sheet_by_name(sheets[idx]).cell(tmp_row, 2).value + ',' + workbook.sheet_by_name(sheets[idx]).cell((tmp_row -1), 2).value + "," + ">" + str(list_a)
                        else:
                            #
                            # 这个是其他正常值的匹配, 第二列对应第四列
                            #
                            dict[sheets[idx]][workbook.sheet_by_name(sheets[idx]).cell(tmp_row, 2).value] = workbook.sheet_by_name(sheets[idx]).cell(tmp_row, 4).value


前戏了半天,下面才是pandas的主题。前戏因人而异,一点没有总有人抱怨没情趣,无聊,不知所云。

文件一大堆,首先分堆,找出哪些文件是属于同一个sheet页面规则的。

    stat_dict = {}     # 统计被验证文件的字典
    for key in header_names:   # 遍历所有sheet页面
        print("Processing files:", key)
        pfiles = subfiles(key, args.dat)    # 在所有文件中找出sheet页面规则对应的所有文件
        if(len(pfiles) == 0):
            logger.error("Please check the %s and %s"%(key, header_names[key]))
        else:
            i = 0
            frames = []                           # 临时列表,存入打开的验证文件
            for file in pfiles:
                df = "df" + str(i)               # 临时变量
                #logger.info("Processing files: %s"%file)
                #print("Processing files:", file)
                try:
                    df = pd.read_table(file, header=None, names=header_names[key], sep="|",  index_col=False)   
                    #
                    # 用pandas读入文件,file就是读入的文件名,header=None和 index_col=False这个地方有个坑,如果不需要最好不加,否则输出成csv后可能会少一列
                    # 这里多说点,header和index_col都不要,就默认不需要第一列作为索引列,否则默认第一列为索引列,计算无影响,但是to_csv会被吃掉一列。总之,不需要就别写。
                    # names=header_names[key],sheet中对应的第二列作为pandas中columns的名字header_names[key]就是["one","two","three"]
                    #            one                       two   three
                    # 2016-03-22 00:06:24.4463094 3123
                    # 2016-03-22 00:06:32.4565680 432
                    # 2016-03-22 00:06:32.6835965 543
                    # 2016-03-22 00:06:32.8041945 432
                    # sep 不用说了,按照什么分隔,是什么就写什么
                    #
                    if(df.shape[1] != len(header_names[key])):  # 这句是废话了,开始不会用,这句应该去掉
                        logger.error("file %s columns are not equal to Excel %s"%(file, header_names[key]))
                except:
                    # try...except...就是上面某句错了,这里继续执行,也可以打印出特定的错误类型
                    logger.error("Unsupported type file: %s, len of cols is %d"%(file, len(header_names[key])))
                    print(key, header_names[key])
                    continue   # 很多文件,错误继续读下一个
                finally:
                    # 这个就是不管上面对错,这里都要执行。目的就是把都进来的,都拼接在一起。
                    if not isinstance(df, str):
                        frames.append(df)
            stat_dict[key] = pd.concat(frames)   # 这个就是将同一类型的文件,也就是符合同一sheet规则的文件拼接在一起。frame就是所有打开文件的句柄?
            print(key, stat_dict[key].shape)        # .shape就是pandas的维度,这个值应该和awk中显示的一样。
                                                                  比如:    $ ls *.dat | xargs wc -l        $ 89947 总用量                                                               

            for col_key in dict[key]:
                if("in" in dict[key][col_key]):
                    #print(col_key, dict[key][col_key])
                    #
                    # 不在指定范围内的值
                    #
                    filename = key + '-' + col_key + ".csv"
                    results_csv = os.path.join(args.results, filename)
                    list_a =  re.findall("[\-|\d]+\.?\d*", dict[key][col_key])
                    print("list_a :", list_a)
                    stat_dict[key][~stat_dict[key][col_key].isin(list_a)].to_csv(results_csv, sep=',',header=True, columns=header_names[key], index=False)
                elif("N" == dict[key][col_key]):
                    #
                    # 如果此列有值则输出
                    #
                    filename = key + '-' + col_key + ".csv"
                    print("Empty :", filename)
                    results_csv = os.path.join(args.results, filename)
                    stat_dict[key][~stat_dict[key][col_key].isnull()].to_csv(results_csv, sep=',',header=True, columns=header_names[key], index=False)
                elif("Y" == dict[key][col_key]):
                    #
                    # 如果此列是空值则输出
                    #
                    filename = key + '-' + col_key + ".csv"
                    print("NoEmpty :",filename)
                    results_csv = os.path.join(args.results, filename)
                    stat_dict[key][stat_dict[key][col_key].isnull()].to_csv(results_csv, sep=',',header=True, columns=header_names[key], index=False)
                elif(("Y" in dict[key][col_key]) and "D" in dict[key][col_key] and ("<" not in dict[key][col_key])):
                    #
                    # 如果此列是空值和默认值则输出
                    # Y(D=0)
                    #
                    filename = key + '-' + col_key + ".csv"
                    print("Empty and default :", filename)
                    results_csv = os.path.join(args.results, filename)
                    list_a = re.findall("[\-|\d]+\.?\d*", dict[key][col_key])
                    stat_dict[key][(stat_dict[key][col_key].isnull()) | (stat_dict[key][col_key] == int(list_a[0]))].to_csv(results_csv, sep=',',header=True, columns=header_names[key], index=False)
                elif(("<" in dict[key][col_key]) and ("D" in dict[key][col_key]) and ("Y" in dict[key][col_key])):
                    #
                    # Y<500(D=-1)
                    #
                    filename = key + '-' + col_key + ".csv"
                    print("lt and default :", filename)
                    results_csv = os.path.join(args.results, filename)
                    list_a =  re.findall("[\-|\d]+\.?\d*", dict[key][col_key])
                    print(list_a)
                    #print("files: ", pfiles)
                    #print("type: ", stat_dict[key][col_key])
                    stat_dict[key][(stat_dict[key][col_key] >= int(list_a[0])) | (stat_dict[key][col_key] == int(list_a[1]))].to_csv(results_csv, sep=',',header=True, columns=header_names[key], index=False)
                elif((">" in dict[key][col_key]) and ("ZCTTD" in dict[key][col_key])):
                    #
                    # 10<BigtoPre<100(D=-1)
                    #
                    filename = key + '-' + col_key + ".csv"
                    print("< col - lastCol < and default :", filename)
                    results_csv = os.path.join(args.results, filename)
                    list_col = dict[key][col_key].split(",")
                    print("list_col :", list_col)
                    list_a =  re.findall("[\-|0-9][0-9]{1,}",dict[key][col_key])
                    print("list_a :", list_a)
                    stat_dict[key][(((stat_dict[key][list_col[0]] - stat_dict[key][list_col[1]]) <= int(list_a[0])) & (stat_dict[key][list_col[0]] - stat_dict[key][list_col[1]]) >= int(list_a[1])) | (stat_dict[key][list_col[0]] == int(list_a[-1]))].to_csv(results_csv, sep=',',header=True, columns=header_names[key], index=False)
                elif((">" in dict[key][col_key]) and ("ZCTTD" not in dict[key][col_key])):
                    #
                    # 10<BigtoPre<100
                    #
                    filename = key + '-' + col_key + ".csv"
                    print("num < col - lastCol < num :", filename)
                    results_csv = os.path.join(args.results, filename)
                    list_col = dict[key][col_key].split(",")
                    list_a =  re.findall("[\-|0-9][0-9]{1,}",dict[key][col_key])
                    stat_dict[key][((stat_dict[key][list_col[0]] - stat_dict[key][list_col[1]]) <= int(list_a[0])) & ((stat_dict[key][list_col[0]] - stat_dict[key][list_col[1]]) >= int(list_a[1]))].to_csv(results_csv, sep=',',header=True, columns=header_names[key], index=False)

#
#
#
def subfiles(keyword, path):
    files = []
    allfiles = glob.glob(os.path.join(args.dat, "*.dat"))
    for tmp in allfiles:
        if keyword in tmp:
            files.append(tmp)
   
    if(len(files) == 0):
        logger.error("There are no files called %s files under the %s"%(keyword, path))
        
    return files

您需要登录后才可以回帖 登录 | 注册

本版积分规则

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号 北京市公安局海淀分局网监中心备案编号:11010802020122
广播电视节目制作经营许可证(京) 字第1234号 中国互联网协会会员  联系我们:wangnan@it168.com
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP