首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >我用100行代码来支援青岛抗击疫情

我用100行代码来支援青岛抗击疫情

作者头像
马拉松程序员
发布2022-04-26 19:21:14
发布2022-04-26 19:21:14
66100
代码可运行
举报
运行总次数:0
代码可运行

故事背景:

上海此轮疫情到现在已经2周多了,周边的许多同事所在的小区都出现了确诊或者密接,然后小区就封闭了,被迫享受带薪休假14(或者2+12)天。只有我,小区一天没封过,上班一天没落下。

重点是今天周末去公司加班,处理上周五发版后遗留下来的问题。这个时候,之前的一个高中舍友,突然给我打电话,让我帮他处理点事情。

故事背景也是因为青岛受到此轮疫情的波及,需要排查镇上的一些流动人口,进行核酸排查。所以呢,基层的人员就开始挨个打电话,但是有的信息比较过时,有的有改动,而且分了好多人去打电话,最终把结果汇总起来。

大概的内容就是这样,不过因为涉及一些个人公民的隐私信息,我让他给我发几个样例,然后把想要的结果说一下。

产品需求:

最终大概的需求是现在有4个excel表。其中3个是子表,1个汇总表。3个表中都是人员信息,主要是身份证号码、联系电话、工作单位和地址等基本信息。各个表中的关系都通过身份证号码来关联。

现在需要以汇总表为准,将汇总表的信息更新到子表中。如果子表中身份证号码没有出现在汇总表中,则单独标注。如果汇总表中的身份证号码也没有在子表中出现过,也单独汇总。

这骚货(高中同学,之前的宿舍称号叫骚X)说本来呢,之前数据很少,自己搜索一下,复制粘贴就行了。现在太多了,好几万条,不可能一条一条去核对。

我跟他说,你学会一个包,这些基本问题都全部解决了。

解决思路:

问题很简单,Pandas解决一切excel的问题。其实,这个问题可以用excel的vlookup的公式来处理。Excel功能本身很强大,好好学会,基本的表格处理都能解决。不过呢,我没过excel,只是会简单的做个排序,筛选。

那么用pandas怎么处理?

首先读取汇总表作为全局变量dataframe,然后依次读取子表,遍历每一行,找到身份证那一栏的信息,去汇总表找到相应的series,可能有多个,默认就取第一个,把汇总表的series信息覆盖到子表中,如果没有找到,则在最后一栏中标注成“总表未找到”。然后把每次遍历的身份证号码存到全局变量的list中,方便最后统计汇总表中出现,但是3个子表都未出现过的信息。

代码演示:

代码语言:javascript
代码运行次数:0
运行
复制
import os

import pandas as pd

# 指定读取文件夹
path = "E:\\run"
path_list = os.listdir(path)
all_name = None
for i in path_list:
    # 汇总表以全域开头
    if i.startswith("全域"):
        all_name = i

# 找到汇总表,并且读取
all_info = pd.read_excel(path + '\\' + all_name, dtype={'身份证号': str, '*联系电话': str}, header=None)

# 下面是处理汇总表的表头,汇总表的第二栏才是真正的表头
all_info = all_info.iloc[1:]
arr = all_info.values
new_df = pd.DataFrame(arr[1:, 1:], index=arr[1:, 0], columns=arr[0, 1:])
new_df.index.name = arr[0, 0]
all_info = new_df
all_info.index = range(len(all_info))

# 定义一个全局变量,存放子表出现过的身份证号码
all_id_cards = []


def get_one_info(id_card):
    """
    通过身份证号码查找汇总表中的信息
    :param id_card: 身份证号码
    :return: series对象
    """
    df1 = all_info[all_info['身份证号'].isin([id_card])]
    # 如果没找到,返回None
    if df1.empty:

        return None
    else:
        # 如果找到了,就返回第一个,可能有多个,并且把出现过的身份证存全局变量
        all_id_cards.append(id_card)
        return df1.iloc[0]


def get_child_excel(file_name):
    """
    遍历每个子表的信息,一一核对
    :param file_name:子表文件名字
    :return:
    """
    print(path + '\\' + file_name)
    # 读取字表
    cdf1 = pd.read_excel(path + '\\' + file_name, dtype={'ID_CARD': str, 'MOBILE': str})
    cdf2 = cdf1.copy()
    # 只有f1 和ID_CARD取子表的,其余的信息取汇总表。f1是序号
    cdf2 = cdf2[['f1', 'ID_CARD']]
    cdf2['姓名'] = ''
    cdf2['户籍地'] = ''
    cdf2['现居住地'] = ''
    cdf2['联系电话'] = ''
    cdf2['工作单位名称'] = ''
    cdf2['工作单位地址'] = ''
    cdf2['备注'] = ''
    cdf2['汇总表匹配'] = ''
    columns = list(cdf2.columns)
    # 遍历子表每一行
    # index 索引 row是数据内容 dataframe 迭代出来的对象
    for index, row in cdf1.iterrows():
        # 调用前面的查找方法
        res = get_one_info(row['ID_CARD'].strip())
        if res is None or res.empty:
            # 如果没有在汇总表中找到对应的信息,则标注,把部分信息引用原表,其余的为空
            cdf2.iloc[index, columns.index('大表匹配')] = "总表未找到信息"
            cdf2.iloc[index, list(cdf2.columns).index('姓名')] = row['full_name']
            cdf2.iloc[index, list(cdf2.columns).index('联系电话')] = row['MOBILE']
            cdf2.iloc[index, list(cdf2.columns).index('工作单位地址')] = row['ADDRESS']

        else:
            # 如果在汇总表中出现,则把总表的信息copy到子表中
            cdf2.iloc[index, list(cdf2.columns).index('姓名')] = res['姓名']
            cdf2.iloc[index, list(cdf2.columns).index('户籍地')] = res['户籍地']
            cdf2.iloc[index, list(cdf2.columns).index('现居住地')] = res['现居住地']
            cdf2.iloc[index, list(cdf2.columns).index('联系电话')] = res['联系电话']
            cdf2.iloc[index, list(cdf2.columns).index('工作单位名称')] = res['工作单位名称']
            cdf2.iloc[index, list(cdf2.columns).index('工作单位地址')] = res['工作单位地址']
            cdf2.iloc[index, list(cdf2.columns).index('备注')] = res['备注']
            cdf2.iloc[index, list(cdf2.columns).index('汇总表匹配')] = ""
    # 匹配完成后的表格,加上更新的后缀
    file_name = file_name.replace(".xlsx", "_更新.xlsx")
    # 保存文件
    cdf2.to_excel(path + '\\' + file_name, index=False)


def get_file():
    """
    读取文件夹内的全部Excel文件
    :return:
    """
    n_path_list = []
    for i in path_list:
        if i.startswith("poli") or i.startswith("全域") or i.endswith("更新.xlsx") or i.endswith("未找到.xlsx"):
            pass
        else:
            n_path_list.append(i)
    return n_path_list


def get_other_info():
    """
    把汇总表中从未在子表中出现过的信息统计到一个表中
    :return:
    """
    # 获取全部子表中出现过的号码并且去重
    id_cards = list(set(all_id_cards))
    # 创建建一个新的DataFrame
    other = pd.DataFrame(columns=["姓名", "身份证号", "户籍地", "居住地", "联系电话", "工作单位名称", "工作单位地址", "备注"])
    # 遍历汇总表
    for index, row in all_info.iterrows():
        id_card = row['* 身份证号']
        # 如果在list中就跳过,没有则添加到新创建的DataFrame中
        if id_card in id_cards:
            pass
        else:

            new = pd.DataFrame({'姓名': row['姓名'],
                                '身份证号': row['身份证号'],
                                '户籍地': row['户籍地'],
                                '居住地': row['现居住地'],
                                '联系电话': row['联系电话'],
                                '工作单位名称': row['工作单位名称'],
                                '工作单位地址': row['工作单位地址'],
                                '备注': row['备注']
                                },
                               index=[1])

            other = other.append(new, ignore_index=True)
    # 保存文件
    other.to_excel(path + '\\' + "子表中未找到.xlsx", index=False)

if __name__ == '__main__':
    n_path_list = get_file()
    for i in n_path_list:
        print(i)
        get_child_excel(i)
    get_other_info()

故事后续:

因为他电脑里没有Python环境,我直接给他代码并不能用,所以最后把这个脚本打成exe可执行的文件,直接发给他运行,最终效果是这样。

其实,全部的功能处理完全都用Pandas就可以来完成,当然除了Pandas也有一些excel的处理工具,但是想这种规范化的数据,使用Pandas还是相当便利的。

不仅仅是这骚货,也有一些其他朋友也会找我处理点数据。其实对于代码来说,如果只有三五行数据,完全没必要。

代码的发挥场景是,数据量比较大,再就是需要经常做的工作,这样把流程性的东西做成一个脚本,以后每次跑一下就要可以得到结果

后面呢,我会在空闲时间,写个如何用Pandas简单的处理点数据的教程,让这些整天想白嫖我的朋友们学习学习。

好了,今天就分享到这里,我是马拉松程序员,可不至于代码!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-03-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 马拉松程序员 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档