import pandas as pd
import os
from datetime import datetime
import re
import time
start_time = time.time()
"""
获取未导入的数据,且去除了没有电话号码,年龄小于60大于18
"""
# 初始化一个空的列表来存储所有的 DataFrame
dataframes = []
for root,dirs,files in os.walk('./data'):
# 合并历史数据
for data_path in files:
data_path=os.path.join('./data',data_path)
print(data_path)
df = pd.read_excel(data_path)
dataframes.append(df)
print('合并历史数据')
# 使用 concat 函数将所有的 DataFrame 合并成一个总表
# ignore_index=True 表示重置索引,这样合并后的总表将有一个连续的索引
combined_df = pd.concat(dataframes, ignore_index=True)
print('合并完成')
# 保存合并后的总表到 Excel 文件
combined_df.to_excel('./dir/已经导入的数据.xlsx', index=False)
# combined_df=pd.read_excel('./dir/已经导入的数据.xlsx')
total_df=pd.read_excel('./客户信息.xlsx')
# total_df=pd.read_excel('./hh.xlsx')
# 筛选出满足条件的data
# 定义正则表达式模式
id_pattern = re.compile(r'^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$')
# 筛选符合格式的身份证号码
valid_ids = total_df['证件号'].str.match(id_pattern)
# 对符合格式的身份证号码计算年龄
def calculate_age_from_id(id_number):
try:
# 假设身份证号码是18位的,且出生日期位于第7到14位
birth_date_str = id_number[6:14]
# 将字符串转换为日期对象,注意这里我们假设输入的身份证号码是有效的
birth_date = datetime.strptime(birth_date_str, '%Y%m%d')
# 获取当前日期
today = datetime.today()
# 计算年龄
age = today.year - birth_date.year - ((today.month, today.day) < (birth_date.month, birth_date.day))
return age
except ValueError as e:
# 捕获日期格式错误或日期无效的情况
print(f"{id_number}身份证号码中的出生日期无效或格式错误:{e}")
return None
# 应用函数并创建新列存储年龄
total_df['age'] = total_df.loc[valid_ids, '证件号'].apply(calculate_age_from_id)
# 筛选年龄大于18岁且小于60岁的数据(只考虑有效身份证号码的行)
filtered_df = total_df.loc[valid_ids & (total_df['age'] > 18) & (total_df['age'] < 60)]
# 定义一个函数来检查字符串是否是有效的手机号码(以1开头,11位数字)
def is_valid_phone_number(phone):
# 使用正则表达式来匹配有效的手机号码
pattern = r'^1\d{10}$'
return re.match(pattern, str(phone)) is not None if pd.notna(phone) else False
# 应用这个函数来创建一个布尔索引
valid_phone_mask = filtered_df['移动电话'].apply(is_valid_phone_number)
# 使用布尔索引来筛选出有有效手机号码的行(同时排除空值)
df_with_valid_phones = filtered_df[valid_phone_mask & filtered_df['移动电话'] != '']
# 使用布尔索引来筛选出有有效手机号码的行
df_with_valid_phones = df_with_valid_phones[valid_phone_mask]
df_with_valid_phones.to_excel('./dir/符合要求的数据.xlsx',index=False)
pd.set_option('display.float_format', lambda x: '%.0f' % x)
# 去掉已经导入的数据 根据姓名 客户号 年纪 身份证后四位
# 获取表 combined_df 表示 已经批量导入的 中的客户号 combined_df是历史数据
# customer_ids_B = combined_df['客户编号'].values
# # 筛选没有批量导入的数据 df_with_valid_phones是有效数据
# df_A_filtered = df_with_valid_phones[~df_with_valid_phones['客户号'].isin(customer_ids_B)]
combined_df['身份证号后四位'] = combined_df['证件号码'].str[-4:]
combined_df.rename(columns={'客户编号': '客户号', '客户名称': '姓名','年龄':'age'}, inplace=True)
df_with_valid_phones['身份证号后四位'] = df_with_valid_phones['证件号'].str[-4:]
df_with_valid_phones['客户号']=df_with_valid_phones['客户号'].astype(object)
combined_df['客户号']=combined_df['客户号'].astype(object)
merged_df = pd.merge(df_with_valid_phones, combined_df, on=['客户号', '姓名', 'age', '身份证号后四位'], how='left', suffixes=('_A', '_B'),
indicator=True)
# 我们使用indicator参数来标记每行数据的来源
# '_merge'列的值为'both'表示该记录在A表和B表中都存在
# 我们要保留的是'_merge'值为'left_only'的记录,即只存在于A表中的记录
df_A_filtered = merged_df[merged_df['_merge'] == 'left_only'][df_with_valid_phones.columns.tolist()]
df_A_filtered.to_excel('./未导入的数据.xlsx',index=False)
end_time = time.time()
elapsed_time = end_time - start_time
# 将秒转换为分钟和秒
minutes, seconds = divmod(elapsed_time, 60)
print(f"执行时间: {minutes:.2f} 分钟和 {seconds:.2f} 秒")
import pandas as pd
import os
from datetime import datetime
import re
import numpy as np
import pandas as pd
from openpyxl import load_workbook
from openpyxl.utils.dataframe import dataframe_to_rows
from openpyxl.styles import NamedStyle
from openpyxl import load_workbook
from openpyxl.utils.dataframe import dataframe_to_rows
from openpyxl.styles import PatternFill, Border, Side, Alignment, Font
import time
start_time = time.time()
def append_dataframe_with_format( df,save_path, sheet_name=None, startrow=None):
book = load_workbook('最新导入模板.xlsx')
if sheet_name is None:
sheet = book.active
else:
sheet = book[sheet_name]
if startrow is None:
startrow = sheet.max_row + 1
# 假设我们复制第一行的格式作为新行的格式模板
template_row = 10
# 将DataFrame转换为行列表,并追加到工作表中
for r_idx, row in enumerate(dataframe_to_rows(df, index=False, header=False), start=startrow):
for c_idx, value in enumerate(row, start=1):
# 获取模板单元格
template_cell = sheet.cell(row=template_row, column=c_idx)
# 创建新单元格并设置值
new_cell = sheet.cell(row=r_idx, column=c_idx, value=value)
# 复制格式属性
if template_cell.has_style:
# 字体
if template_cell.font:
new_cell.font = template_cell.font.copy()
# 填充
if template_cell.fill:
new_cell.fill = template_cell.fill.copy()
# 边框
if template_cell.border:
new_border = Border(
top=Side(style=template_cell.border.top.style, color=template_cell.border.top.color),
bottom=Side(style=template_cell.border.bottom.style, color=template_cell.border.bottom.color),
left=Side(style=template_cell.border.left.style, color=template_cell.border.left.color),
right=Side(style=template_cell.border.right.style, color=template_cell.border.right.color)
)
new_cell.border = new_border
# 对齐方式
if template_cell.alignment:
new_cell.alignment = template_cell.alignment.copy()
# 可以添加更多格式属性的复制逻辑,如数字格式等
book.save(save_path)
# 定义函数来“添加”B表内容到A表
def add_b_to_a(B):
"""
添加B到A中,并且保留A的格式
"""
# 由于A表和B表没有直接匹配字段,我们假设所有B表的客户都是A表户主的新家庭成员
# 我们将B表的每一行作为一个新行添加到A表的末尾,并填充相关信息
# 创建一个新的DataFrame来存储合并后的数据
C = pd.DataFrame() # 保留A表的原始数据
# 对于B表的每一行,创建一个新行添加到C表中
for _, row_b in B.iterrows():
new_row = {
"序号": C['序号'].max() + 1 if not C.empty else 1, # 如果C表为空,则序号为1,否则为当前最大序号+1
"户主名称*": row_b['姓名'],
"户主证件类型*": "居民身份证",
"户主证件号码*": row_b['证件号'], # 这里应该是具体的证件号码,但出于隐私考虑,使用“手工输入”作为示例
"客户细分类型*": "经营户", # 假设选择的是经营户
"与客户关系*": "本人", # 假设是户主本人
"成员名称*": row_b['姓名'],
"证件类型*": "居民身份证",
"证件号码*": row_b['证件号'], # 同上
"身份证地址": row_b['地址'],
"是否三类人员": "否", # 假设不是三类人员
"联系电话": row_b['移动电话'],
"户口簿户号": " ",
"健康状况": "良好", # 假设健康状况良好
"婚姻状况": "已婚", # 假设已婚
"学历信息": "高中", # 假设学历为大学本科
"是否985、211院校以及双一流大学": "否", # 假设不是985、211或双一流大学
"工作单位": "务农",
"主要收入类型": "农业收入", # 假设主要收入类型为经营收入
"职业信息": "农、林、牧、渔业生产及辅助人员", # 假设职业为企事业单位负责人
"经营地址": " ",
"是否公职人员": "否", # 假设不是公职人员
"是否小微企业主": "否", # 假设是小微企业主
"是否个体工商户": "否", # 假设不是个体工商户
"是否农户": "否", # 假设不是农户
"是否家庭劳动力": "是", # 假设是家庭劳动力
"是否外出务工": "否", # 假设没有外出务工
"是否缴纳公积金": "是", # 假设缴纳公积金
"年平均工资(元)": '', # 假设年平均工资为50000元
"公积金缴存基数(元)": '', # 假设公积金缴存基数为3000元
"是否参加养老保险": "是", # 假设参加养老保险
"统一社会机构代码": "", # 通常是企业的代码,个人不需要填写
"是否有合法合规、手续齐全的经营项目,且经营一年以上": " ", # 假设有合法合规的经营项目且经营一年以上
"是否全款车辆为本次授信办理抵押登记": " ", # 假设没有全款车辆用于抵押
"车辆情况": " ", # 假设没有车辆
"车辆使用性质": "", # 如果有车辆,这里会是车辆的使用性质,如家用、商用等
"车辆是否抵押": "", # 假设车辆没有抵押
"是否有经营项目为运输业且行车证、驾驶证、挂靠协议等手续齐全": "否", # 假设没有运输业经营项目
"是否自有全款房产且为本次授信办理抵押登记增信": "否", # 假设没有全款房产用于抵押
"可以办理抵押登记的房产位置": " ", # 如果有房产,这里会是房产的位置
"房产面积(平方米)": 100, # 假设房产面积为100平方米
"房产建成年份": 2010, # 假设房产建成年份为2010年
"装修情况": "普通装修", # 假设房产为普通装修
"房产评估价值(元)": 500000, # 假设房产评估价值为500000元
"是否抵押": "否", # 假设房产没有抵押
"是否有自有房产剩余价值为本次授信办理再次抵押登记": "否", # 假设没有房产剩余价值用于抵押
"剩余价值(元)": '', # 如果有剩余价值,这里会是具体的金额
"不能办理抵押登记的房产类型": "小产权房", # 如果有不能办理抵押登记的房产,这里会是房产的类型
"房产面积(平方米)_不能抵押": 50, # 假设不能抵押的房产面积为50平方米
"房产建成年份_不能抵押": 2000, # 假设不能抵押的房产建成年份为2000年
"房屋结构_不能抵押": "砖混", # 假设不能抵押的房产为砖混结构
"全款结清但不能办理抵押登记的自有房产面积(平方米)": '', # 假设没有全款结清但不能办理抵押登记的房产
"全款结清但不能办理抵押登记的自有房产建成年份": '', # 同上,没有则填0或空值
"装修情况_不能抵押": "未装修/毛坯", # 假设不能抵押的房产为未装修/毛坯
"林权证明": "无", # 假设没有林权证明
"林权面积(亩)": 0, # 如果没有林权,则面积为0
"其他资产(名称)": "无", # 假设没有其他资产
"是否抵押_其他资产": "否", # 假设其他资产没有抵押
"数量_其他资产": 0, # 如果没有其他资产,则数量为0
"预估价值(元)_其他资产": 0, # 如果没有其他资产,则预估价值为0
"个人荣誉": "", # 假设没有个人荣誉
"家庭荣誉": "未知", # 假设没有家庭荣誉
"家庭及邻里关系": "和睦", # 假设家庭及邻里关系和睦
"支付宝芝麻信用评分": " ", # 这里应该是具体的信用评分,但出于隐私考虑,使用“手工输入”作为示例
"生产项目种类": "种植", # 假设生产项目种类为种植
"类型_生产项目": "其他", # 如果有更具体的类型,则填写在这里
"年营收规模": "10-20万", # 假设年营收规模为10-20万
"年收入(元)": 10000, # 假设年收入为80000元
"年支出(元)": '', # 假设年支出为60000元
"备注": " ", # 如果有备注信息,则填写在这里
"负债类型": " ", # 假设负债类型为银行贷款
"负债金额(元)": '', # 假设负债金额为20000元
"是否涉黄": "否", # 假设没有涉黄
"是否涉赌": "否", # 假设没有涉赌
"是否涉毒": "否", # 假设没有涉毒
"其他负面": "未知", # 假设没有其他负面记录
"近两年内在他行有不良征信记录次数": '', # 假设近两年内没有不良征信记录
"在其他金融机构(含互联网类贷款)已有信用类贷款额度(元)": '', # 假设已有信用类贷款额度为10000元
"在其他金融机构(含互联网类贷款)已有保证担保贷款额度(元)": '', # 假设没有保证担保贷款额度
"在其他金融机构(含互联网类贷款)已有抵质押贷款额度(元)": '', # 假设没有抵质押贷款额度
"在其他金融机构(含互联网类贷款)已有个人住房按揭贷款额度(元)": '', # 假设已有个人住房按揭贷款额度为300000元
"在其他金融机构(含互联网类贷款)已对外提供保证担保的贷款额度(元)": '', # 假设没有对外提供保证担保的贷款额度
"是否需要资金支持": "生产经营", # 假设需要资金支持
"需求金额(元)": '' # 假设需求金额为100000元
}
# C = C.append(new_row, ignore_index=True)
new_row=pd.DataFrame([new_row])
C=pd.concat([C, new_row], ignore_index=True)
return C
def split_and_save_dataframe(df, max_rows_per_file, file_prefix, output_dir='.'):
"""
将DataFrame分割成多个较小的DataFrame,并保存为独立的文件。
参数:
df (pd.DataFrame): 要分割的DataFrame。
max_rows_per_file (int): 每个文件最多包含的行数。
file_prefix (str): 输出文件的前缀名。
output_dir (str): 输出文件的目录(默认为当前目录)。
返回:
None
"""
# 确保输出目录存在
output_dir=os.path.join(output_dir,str(key))
os.makedirs(output_dir, exist_ok=True)
# 计算需要多少个文件
num_files = (len(df) // max_rows_per_file) + (1 if len(df) % max_rows_per_file != 0 else 0)
# 循环分割并保存DataFrame
for i in range(num_files):
# 计算当前文件的起始和结束索引
start_index = i * max_rows_per_file
end_index = min((i + 1) * max_rows_per_file, len(df))
# 切片创建小DataFrame
small_df = df.iloc[start_index:end_index]
# 构造文件名
now = datetime.now()
formatted_time_no_colons = now.strftime("%Y-%m-%d_%H_%M_%S")
# 构建文件名(使用下划线替换冒号)
file_name = f"{file_prefix}_{formatted_time_no_colons}_part_{i + 1}.xlsx"
# 使用 os.path.join 将文件名与输出目录结合(但这里我们直接拼接,因为output_dir已经是原始字符串)
# 注意:如果output_dir是用户输入的,应该使用os.path.join并确保它是正确的路径格式
file_path = os.path.normpath(os.path.join(output_dir, file_name))
#
# file_name = f"{file_prefix}_part_{i + 1}.xlsx"
# file_path = os.path.join(output_dir, file_name)
# 保存小DataFrame为CSV文件并且保留格式
small_df=add_b_to_a(small_df)
append_dataframe_with_format(small_df,file_path)
# small_df.to_excel(file_path, index=False)
print(f"Saved {file_path} with {len(small_df)} rows.")
# 读入模板数据
df = pd.read_excel('./最新导入模板.xlsx',header=2)
# 读入未导入的数据
# n_df=pd.read_excel('./新建文件夹/未导入的数据.xlsx',nrows=10)
n_df=pd.read_excel('./未导入的数据.xlsx')
n_df['地址'] = n_df['地址'].astype(str).fillna('')
# 分别按照开户机构和地址进行分类
township_list = [
'hh'
]
n_df['township'] = pd.NA # 使用pd.NA表示缺失值
# 遍历详细地址列,判断属于哪一个乡镇,并更新新列
for index, row in n_df.iterrows():
detailed_address = row['地址']
# 这里我们简单使用字符串包含关系来判断,实际情况中可能需要更复杂的匹配逻辑
for township in township_list:
if township in detailed_address:
# 找到匹配,更新乡镇列
n_df.at[index, 'township'] = township # 假设乡镇名称是地址的最后一个部分
# 注意:上面的split方法可能不适用于所有情况,你需要根据实际情况调整
break # 找到匹配后退出循环
# print(n_df)
grouped=n_df.groupby('township')
# 将分组转换为字典,键是地区的组合,值是对应的DataFrame
dict_of_dfs = {key: group for key, group in grouped}
# 如果你想遍历所有的DataFrame,你可以这样做:
print('按照地区分')
for key, df_in_group in dict_of_dfs.items():
# df_in_group = add_b_to_a(df, df_in_group)
split_and_save_dataframe(df_in_group, max_rows_per_file=2000, file_prefix=key, output_dir='./地区')
# 按照机构分
grouped = n_df.groupby('开户机构')
# print('按照机构分')
# # 将分组转换为字典,键是地区的组合,值是对应的DataFrame
# dict_of_dfs = {key: group for key, group in grouped}
# # 如果你想遍历所有的DataFrame,你可以这样做:
# for key, df_in_group in dict_of_dfs.items():
# # df_in_group = add_b_to_a(df)
# split_and_save_dataframe(df_in_group, max_rows_per_file=20, file_prefix=key, output_dir='./机构')
#
# n_df.to_excel('./hh.xlsx',index=False)
end_time = time.time()
elapsed_time = end_time - start_time
# 将秒转换为分钟和秒
minutes, seconds = divmod(elapsed_time, 60)
print(f"执行时间: {minutes:.2f} 分钟和 {seconds:.2f} 秒")