需求
在实际工作中,我经常要处理其他同事发来的csv文件。这些文件不是一个两个,而是十几二十个。
因此,怎么准确区分这些文件就很关键——弄错了文件、找不到需要的文件,都会导致我的报告出错。
之前的解决办法
之前我是依靠同事对这些文件进行重命名来识别它们。但重命名有两个问题:一是同事们不会严格遵循我的要求,总是会在文件命名上创新,导致我的代码出错。二是文件缺失的话,我也不能及时发现究竟是因为重命名不规范导致的缺失呢还是这个文件本来就没发给我。
所以,我决定研究下根据文件内容来区分文件。
根据文件内容来区分csv文件
先上代码:
#基础数据准备
def gen_data(kw,is_feed=False,groupby_date=False):
paths=[x for x in files if re.search('.csv',x,re.IGNORECASE)!=None]
for path in paths:
df,pos=skip_to(path,delimiter=',',parse_dates =['日期'])
if kw in list(df):
if groupby_date==True:
df=df.groupby('日期').sum()
else:
df=df.groupby(kw).sum()
df=df[['展现','点击']]
try:
df=df[~df.index.str.contains('未识别')]
except:
pass
df=df.reset_index()
print(pos)
df['点击率']=df['点击']/df['展现']
#df['点击率']=df['点击率'].apply(lambda x: format(x,'.2%'))
df['百分比']=df['点击']/df['点击'].sum()
#df['百分比']=df['百分比'].apply(lambda x: format(x,'.2%'))
df[['展现','点击']]=df[['展现','点击']].astype(int)
df.sort_values(by='点击',ascending=False)
if is_feed==True:
num=range(60,130)
else:
num=range(140,300)
if pos in num:
return df
【paths=[x for x in files if re.search('.csv',x,re.IGNORECASE)!=None]】是筛选出csv文件。
这一行【df,pos=skip_to(path,delimiter=',',parse_dates =['日期'])】,是用来读取csv文件。由于每个csv文件开头都有数量不定的垃圾行要剔除,所以我用了一个函数skip_to()来处理(详见:《pandas读取csv时如何跳过不确定的行数》。
【pos】这个变量我后面要用到,所以一并取出。
最关键的是识别出每个文件中的独特列名。
我用【in】来判断:【if kw in list(df):】,也就是判断【kw】是不是在DataFrame的列名中,如果返回结果为True,就进行下面的代码。
但在实际场景中,我遇到了一个单纯凭【kw】是否在列名中也无法识别文件是哪一个的情况:有两个文件的表头一模一样,唯一的区别是开头的垃圾行数量不同。
这时【pos】变量就有用了。这个变量获取的是【日期】字段在列名中的位置。不同文件这个【pos】差别很大。所以就有了下面的代码:
if is_feed==True:
num=range(60,130)
else:
num=range(140,300)
【is_feed】是函数的参数,如果其值为True,那么把【num】的值设置为range(60,130)的范围。之所以是范围而不是具体的数字,是因为我发现百度这个憨包后台导出的数据里,【日期】所在的位置会发生细微的变动,比如feed数据报告中【日期】可能在75,也可能在79。而搜索推广导出的数据中,【日期】在的位置可能是145,也可能是149,居然还有个200。
好在目前还没有发现两类文件的【pos】值有重合。
最后根据【pos】值是否在【num】的范围内而返回对应的结果。这样就实现了根据文件内容来进行相应的处理了。
网友评论