赞
踩
将特征数据进行简单处理,分割为数值型与字符型两个文件
def simple_nums_feature(): ''' 将原始特征分割为数值型特征和字符型特征 生成两个文件 :return: ''' path = './data/' data_pattern = path + 'feature_nums_df.csv' if os.path.exists(data_pattern): return filename = 'raw_feature.csv' # 之前生成的原始特征 train_df = pd.read_csv(path + filename, encoding='gbk', low_memory=False) print('数据载入成功') feature_num = train_df.shape[1] print('特征数量:', feature_num) # 将值为'未查'或'弃查'的全部改为nan train_df.replace(['未查', '弃查'], np.nan, inplace=True) print('丢弃了弃查未查项') # 丢弃空缺值超过57109项的【特征】 missing_df = train_df.notnull().sum(axis=0).reset_index() # 求每一列(每个检查项/特征)的非空个数 missing_df.columns = ['column_name', 'count'] # 列名,非空个数 missing_df = missing_df.sort_values(by='count', ascending=True) # 按照count字段的值升序排序 # 留下样本数在200以上的特征 missing_df = missing_df[missing_df['count'] > 200] # 按照布尔数组索引,留下true的 # missing_df = missing_df[missing_df['count'] < 57298] # vid和列名组成新的,此时missing_df的原count列已经没用了,因为已经计数筛选完毕了 # missing_df = ['vid'] + list(missing_df['column_name']) # 为什么要加[:-1] 由于之前升序排序的原因,vid被排到了最后,需要将其过滤掉 missing_df = ['vid'] + list(missing_df['column_name'][:-1]) # print(missing_df) #['vid', '2406', '0501',...,'vid'] # 按照missing_df(里面是列名)重新对列进行索引,也就是把特征样本太少(特征对应样本数<200)的特征(列)给过滤掉了 # 且对列进行了排序,排在前面的是样本少的特征 train_df = train_df[missing_df] feature_num = train_df.shape[1] print('过滤后特征数量:', feature_num) ## 数一数每一项的unique值有多少,丢弃只有一项的 # cat_dit = {} # for i in train_df.columns[1:]: # 遍历每个特征(列),除去vid列 # c = train_df[i] # 取出该列所有的值 # c = c[c.notnull()] # 按照布尔数组过滤,留下为true的,丢弃false的 # c = c.unique().shape[0] #报错? # cat_dit.update({i: c}) # cat_dit = pd.Series(cat_dit).sort_values(ascending=False) ## cat_dit[cat_dit > 1].index 将过滤后的dit索引取出来 # lst_str = ['vid'] + list(cat_dit[cat_dit > 1].index) # train_df = train_df[lst_str] # print(len(lst_str)) # 开始转化 count = 0 lst = ['vid'] lst_str = ['vid'] for i in train_df.columns[1:]: if count % 50 == 0: print(count, '/', feature_num) # 打印一下 try: train_df[i] = train_df[i].astype('float') # 将其对应的值(列向量)取出来,直接转化雷星 lst.append(i) # 如果是纯数值的直接append except: lst_str.append(i) # 如果是非数值的,将其apped给lst_str count += 1 print("数值型特征数:", len(lst)) print("字符型特征数", len(lst_str)) # 分别索引 nums_df = train_df[lst] str_df = train_df[lst_str] # 生成文件 nums_df.to_csv(path + 'feature_nums_df.csv', index=False) str_df.to_csv(path + 'feature_str_df.csv', index=False)
def more_nums_feature(): ''' 处理含有少量字符特征的文件 :return: ''' path = './data/' data_pattern = path + 'feature_nums_waiteforprocess_df.csv' if os.path.exists(data_pattern): return filename = 'feature_str_df.csv' # 之前生成的字符特征文件 train_df = pd.read_csv(path + filename, encoding='gbk', low_memory=False) print('数据载入成功', '特征数量', train_df.shape[1]) times = 0 dit = {} for i in train_df.columns[1:]: # 遍历每一列 去掉vid times += 1 if times % 50 == 0: print("正在处理第", times, "个特征") # 打印次数 count = 0 notnull_num = train_df[i].notnull().sum() # 计算非空特征数 for j in range(train_df.shape[0]): # 遍历此列的每一个元素 try: c = float(train_df[i][j]) # 试图转化为float if c is np.nan: pass # do nothing else: count += 1 # 转化完成记个数 except: pass # do nothing # 使用字典统计转化成功的数值型在非空样本中的比例 dit.update({i: count / notnull_num}) # 将字典转化为Series类型并降序排序 dit = pd.Series(dit).sort_values(ascending=False) print(dit.describe()) # 查看描述 # dit[dit <= 0.05].index 将过滤后的dit的索引取出来 num_df = train_df[['vid'] + list(dit[dit >= 0.5].index)] # 数字型样本集 str_df = train_df[['vid'] + list(dit[dit <= 0.05].index)] # 字符型样本集 temp = dit[dit < 0.5] temp = temp[temp > 0.05] # >0.05并<0,.5的中间部分 other_df = train_df[['vid'] + list(temp.index)] # 其他型样本集 print("进一步确定数值型特征数:", num_df.shape[1] - 1) print("进一步确定字符型特征数:", str_df.shape[1] - 1) print("进一步确定其他型特征数:", other_df.shape[1] - 1) num_df.to_csv('./data/feature_nums_waiteforprocess_df.csv', index=False) str_df.to_csv('./data/feature_str2_df.csv', index=False) other_df.to_csv('./data/feature_unknown_df.csv', index=False) print("进一步分割文件完毕")
def more_nums_feature2(): ''' 继续清洗含少量字符特征的数据 :return: ''' path = './data/' data_pattern = path + 'feature_nums2_df.csv' if os.path.exists(data_pattern): return filename = 'feature_nums_waiteforprocess_df.csv' # 之前生成的数值型特征样本 df = pd.read_csv(path + filename, encoding='gbk', low_memory=False) print('数据载入成功', '特征数量', df.shape[1]) ''' re.compile 一个正则表达式要重复使用几千次, 出于效率的考虑,可以预编译该正则表达式, 接下来重复使用时就不需要编译这个步骤了,直接匹配 用*表示任意个字符(包括0个) 用+表示至少一个字符 用?表示0个或1个字符 用{n}表示n个字符 用{n,m}表示n-m个字符 用+?表示非贪婪匹配 .可以匹配任意字符(数字字母标点) ^ 匹配字符串的开头 $ 匹配字符串的末尾 [^...] 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。 ''' pat = [re.compile(r'\d+月\d+日'), re.compile(r'[^\d.]'), re.compile(r'\.$')] cout = 0 t0 = time.time() # 初始化时间 for i in df.columns[1:]: # 遍历每一列 cout += 1 # 计数 lst = [] if cout % 10 == 0: print('每10个用时{}秒'.format(time.time() - t0)) # 计时 print(cout, '/', df.shape[1]) # 处理进度 处理列数/总列数 t0 = time.time() # 更新时间 for j in range(df[i].shape[0]): # 遍历此列的每个元素 c = str(df[i][j]) # 读取df并转化为字符串 if c == 'nan' or (not c) or (c is np.nan): # 如果是nan直接跳过 continue for k in range(len(pat)): if c: # 将时间字符串清除掉 c = re_sub(pat[k], c) else: break df[i][j] = c try: c = float(df[i][j]) except: pass for i in df.columns[1:]: # 遍历所有列 # 转化为数值类型,默认情况下,它不能处理字母型的字符串 df[i] = pd.to_numeric(df[i], errors='coerce') df.to_csv('./data/feature_nums2_df.csv', index=False)
def re_sub(pat, s): ''' re.sub用于替换字符串中的匹配项 re.sub(pattern, repl, string, count=0, flags=0) pattern : 正则中的模式字符串。 repl : 替换的字符串,也可为一个函数。 string : 要被查找替换的原始字符串。 count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。 ''' # 将时间日期替换成空格,其他不变,将组合好的字符串返回 c = re.sub(pat, ' ', s).strip().split() if c: return c[0] else: return c
两篇不错的教程:
https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143193331387014ccd1040c814dee8b2164bb4f064cff000
http://www.runoob.com/python/python-reg-expressions.html
(1)编译 compile
一个正则表达式要重复使用几千次,
出于效率的考虑,可以预编译该正则表达式,
接下来重复使用时就不需要编译这个步骤了,直接匹配
(2)替换 sub
re.sub用于替换字符串中的匹配项
re.sub(pattern, repl, string, count=0, flags=0)count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配
(3)例子
a = re.compile(r'\d+月\d+日')
aa = re.match(a, '12月10日')
if aa:
print('ok')
c = re.sub(r'\d+月\d+日', '0', '12月5日33').strip().split()
if c:
print(c[0])
else:
print(c)
输出:
def wash_str(): ''' 清洗字符特征 :return: ''' path = './data/' data_pattern = path + 'feature_str3_df.csv' if os.path.exists(data_pattern): return filename = 'feature_str2_df.csv' train_df = pd.read_csv(path + filename, encoding='gbk', low_memory=False) # 读取文件 print('数据载入成功', '特征数量', train_df.shape[1]) # 正则化 此字符可以字母,数字与标点符号 # r'' 是因为python字符串本身也需要转义,使用Python的r前缀,就不用考虑转义的问题了,可以使对应的正则表达式字符串不变: p = re.compile(r'[a-zA-Z0-9<>/,.,。()():/*% 、""“”‘’°??=~;;::]') word_lst = set(['未见异常', '未见明显异常', '正常', '未见异常未见异常', '正常正常', '正常正常正常', '未闻及异常', '正常正常正常正常正常', '未发现异常', '未见异常未见异常未见异常', '未见明显异常未见异常', '未发现明显异常', '未发现异常未发现异常', '正常正常正常正常', '无', '未见', '未见未见', '阴性', '阴性-', '阴性阴性', '-阴性', '阴性阴性-', '阴性-阴性-', '抗体阴性', '-', '-~', '--']) count = 0 t0 = time.time() for i in train_df.columns[1:]: # 遍历每一列 count += 1 if count % 10 == 0: print('每10个用时{}秒'.format(time.time() - t0)) t0 = time.time() print(count, '/', train_df.shape[1]) for j in range(train_df[i].shape[0]): # 如果是nan直接跳过 if str(train_df[i][j]) == 'nan' or (not train_df[i][j]) or (train_df[i][j] is np.nan): continue # 将字母、数字和标点删除 train_df[i][j] = re.sub(p, '', train_df[i][j]).strip() # 如果在此词表中,全部替换为正常 if train_df[i][j] in word_lst: # train_df[i][j] = '正常' # 过滤字符串 train_df.to_csv('./data/feature_str3_df.csv', index=False)
def cut_str_feature(): ''' 切分为长字符串和短字符串 ''' path = './data/' data_pattern = path + 'feature_long_str.csv' if os.path.exists(data_pattern): return filename = 'feature_str3_df.csv' # 之前清洗完的(删除了标点,啰嗦正常表意被替换为正常) train_df = pd.read_csv(path + filename, encoding='gbk', low_memory=False) # 读取文件 nums, nums2 = train_df.shape count = 0 max_length = 0 lst = [] ''' collections.Counter() 为hashable对象计数,是字典的子类 Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储, 其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数) ''' dit = collections.Counter() len_dit = {} for i in train_df.columns[1:]: # 遍历每一列 max_i = 0 if count % 10 == 0: print(count, '/', nums2) # 已处理的列数/总列数 for j in range(train_df[i].shape[0]): # 遍历此列的每个元素 ''' jieba:分词模块 ''' c = list(jieba.cut(str(train_df[i][j]).encode('utf-8'))) lst.append(c) max_i = max(len(c), max_i) # 找到分词组数最长的那个 # 更新一条 i: max_i 记录 len_dit.update({i: max_i}) # 增加方法 使用另一个iterable对象更新 dit.update(c) # 计数 count += 1 df = pd.Series(dit).sort_values(ascending=False) # 对词频统计进行降序排序 len_df = pd.Series(len_dit).sort_values(ascending=False) # 按照分词数最大值对每一列索引进行降序排序 print('cut over') # print('max_length', max_length) print(len_df.describe()) print(len_df.head(5)) #6是一个超参数 如果每列的最长分词数<6则认为其为短字符串列 feature_lst = ['vid'] + list(len_df[len_df < 6].index) # 将过滤后的样本索引取出来,与vid组成新的索引,一会要用 # print(feature_lst) # ['vid', '1305', '0201', '0975', '8101', '0210', '1301', '0706', '0435', '1329', '0426', '0979', '3301', '0440', '3601', '0202', '0715', '0537', '0541', '0227', '0949', '0947', '0984', '3869', '0546', '0972', '729005', '0901', '3430', '3486', '100010', '0436', '3485', '0430', '3192', '2231', '21A236', '3190', '3195', '269041', '3197', '0403', '0406', '2233', '2229', '0413', '21A235', '0421', '1328', '0219', '0428', '659023', '659019', '769005', '0221', '0220', '0415', '659017', '0218', '0432', '0216', '0213', '0212', '0206', '0427', '0420', '659022', '0405', '0433', '659018', '0423', '0431', '0407', '0207', '659021', '659020', '0414', '0438', '0437', '0429', '659006', '659016', '0728', '3196', '3194', '3191', '659007', '300086', '30007', '300062', '300019', '300018', '30001', '269047', '269045', '269042', '269040', '659008', '3198', '3203', '3207', '3740', '659004', '659003', '659002', '659001', '3862', '3855', '3738', '3303', '3721', '3433', '3432', '3426', '3400', '3399', '2302', '2278', '2235', '659005', '0986', '0985', '0983', '0982', '0981', '0980', '0977', '100011', '0976', '0974', '0973', '659015', '0733', '0732', '100009', '659014', '2230', '1334', '2228', '21A238', '21A237', '659009', '659010', '1336', '1333', '659013', '1332', '659011', '1315', '1313', '659012', '1304', 'I49012'] short_str_df = train_df[feature_lst] # 按照新的索引取出内容 values_dit = [] unique_nums = [] strange = [] for i in short_str_df.columns[1:]: # 遍历新的每一列 temp = short_str_df[i] # 取值 u_nums = (temp.value_counts() > 1).sum() unique_nums.append(u_nums) if u_nums <= 10: values_dit += list(temp.unique()) else: strange.append(i) unique_nums = pd.Series(unique_nums) unique_nums.describe() # 统计 short_str = list(set(short_str_df.columns[1:]) - set(['0213'])) # 减去了一列 项目描述里面有 long_str = list(set(train_df.columns[1:]) - set(short_str))#减去短索引,剩下的索引就是长索引 np.save(path + 'category_feature_map.npy', short_str) short_str = ['vid'] + short_str long_str = ['vid'] + long_str short_str_df = train_df[short_str] long_str_df = train_df[long_str] short_str_df.to_csv(path + 'feature_short_str.csv', index=False) long_str_df.to_csv(path + 'feature_long_str.csv', index=False)
两篇入门博客:
https://www.cnblogs.com/jiayongji/p/7119065.html
https://blog.csdn.net/reims2046/article/details/72869337
print(df)
输出:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。