这里是针对广东统计年鉴excel数据清洗的一个小总结
反正要复制的代码
- 循环读取文件夹,用pandas读取excel
for root, dirs, files in os.walk(path):
for f in files:
df = pd.read_excel(os.path.join(root, f),header=None)
#########神仙操作#########
df.to_excel(f.lower()+"_output", sheet_name='Sheet1', index=False, header=False)#f.lower是为了排除有的后缀名是.XLS的
df.to_excel('c_'+f.replace("xlsx", "xls").lower(), sheet_name='Sheet1', index=False, header=False)#这个是简单粗暴直接把xlsx改成了xls
- 把空串设为np.nan(非常重要!!)
df.replace(to_replace=r'^\s*$',value=np.nan,regex=True,inplace=True)
dataframe常用代码
df.iloc[row,col] #读取某个单元格
df.shape[0] #行数
df.shape[1] #列数
df.shape() #返回行和列
df = df.dropna(how='all') #删除空行(how=全为空)
df = df.dropna(axis=1,how='all') #删除空列
df = df.head(i) #只保留前i行df
查找与替换代码
- 注意事项:
进行这类操作前要先判断一下 df.iloc[] is None 或 pd.isnull(df.iloc[]) 或pd.isna(df.iloc[])
还要注意str(df.iloc[]) ,不然会报错哦 - python自带的一些函数
#if df.iloc[i,j] is not None:
# df.iloc[i,j]=str(df.iloc[i,j])
df.iloc[i, j].replace("new", "old")
fstr="aa"
df.iloc[i, j].find(fstr) #返回找到的字符串所在位置,即0~len-1,没找到返回-1,好像还有rfind()?
- 正则表达式相关
菜鸟的正则表达式在线测试工具:https://c.runoob.com/front-end/854
这里用的比较多的是match()和search()两个函数,其他见另一篇~
https://blog.csdn.net/qq_43103270/article/details/114382838
import re
rule=re.compile(r'[\u4e00-\u9fa5]{1,}')#包含中文字符
#找有或没有
if rule.match(str(df.iloc[i, j])) is not None: print("有")
#只保留中文
df.iloc[i, j]=rule.search(str(df.iloc[i, j])).group()
一些特例
- 针对pandas似乎把年份也处理为浮点数的情况:
#处理年份变为浮点数的情况
for i in range(0, min(10,df.shape[0])):#这里是感觉前10行够了,以防万一要加一个min!
for j in range(0, df.shape[1]):
if df.iloc[i,j] in range(1800,2020,1):
df.iloc[i,j]=str(int(df.iloc[i,j]))
- 针对一些逻辑删除,即行或者列里面只有0和0.0和""和nan的
#删掉某列为0和''的列
count=0
for j in range(0,df.shape[1]):
for i in range(0,df.shape[0]):
if df.iloc[i,j]=='0' or df.iloc[i,j]=="" or df.iloc[i,j]=="0.0"or pd.isna(df.iloc[i,j]):
count=count+1
if count==df.shape[0]:
for i in range(0,df.shape[0]):
if df.iloc[i,j]=='0' or df.iloc[i,j]=="0.0":
df.iloc[i,j]=np.nan
count=0
#删掉某行为0和''的行
count=0
count2=0
for i in range(0,df.shape[0]):
for j in range(1,df.shape[1]):
if df.iloc[i,j]=='0'or df.iloc[i,j]=="0.0" or df.iloc[i,j]==""or pd.isna(df.iloc[i,j]):
count=count+1
if df.iloc[i,j]==""or pd.isna(df.iloc[i,j]):
count2=1
if count==df.shape[1]-1 and count2==1:
for j in range(0,df.shape[1]):
if df.iloc[i,j]=='0' or df.iloc[i,j]=="0.0":
df.iloc[i,j]=np.nan
count=0
count2=0
#根据情况在后面dropna()
- 针对合并单元格的重复标题(这里的标题在第一行和第二行),要求只保留第一个
#处理重复标题
if df.iloc[0,1] is not np.nan:
for j in range(1,df.shape[1]):
df.iloc[0,j]=np.nan
if df.iloc[1,0] is not np.nan and str(df.iloc[1,0])==str(df.iloc[0,0]):
for j in range(0,df.shape[1]):
df.iloc[1,j]=np.nan
其他
- 用了dropna() head()等函数记得赋值,不然等于白用
- 处理标题行如果不用find_first_data()函数的话记得要加个min(x,df.shape[0]),小心超出索引
- 用字符串或赋值等相关代码的时候记得数据类型得是字符串
- 删除行、列要用索引,如果没有的话就老实直接nan然后dropna吧,如果以后有更好的办法再补充
- 代码写得可真烂呀 以后加油整成函数吧 加油加油