数据科学家是“比任何软件工程师更擅长统计,比任何统计学家更擅长软件工程”的人。许多数据科学家具有统计学背景,但在软件工程方面经验不足。本文列出了10个常见的编码错误,希望您仔细阅读并避免它们。1.共享代码中没有引用数据数据科学需要代码和数据。因此,其他人需要能够获得数据才能重现结果。这听起来像是一个基本要求,但许多人忘记了与代码共享数据。importpandasaspddf1=pd.read_csv('file-i-dont-have.csv')#failsdo_stuff(df)解决办法:使用d6tpipe(https://github.com/d6t/d6tpipe)共享数据文件和代码,或者结合2收件人上传到S3/web/google驱动器等或保存到数据库,以便收件人可以检索文件(但不要将它们添加到git,见下文)。2.硬编码无法访问的路径与第一个错误类似,如果您对其他人无法访问的路径进行硬编码,他们将无法运行代码并且必须在许多地方查找以手动更改路径。importpandasaspddf=pd.read_csv('/path/i-dont/have/data.csv')#failsdo_stuff(df)#orimportosos.chdir('c:\\Users\\yourname\\desktop\\python')#fails解决方案:使用相对路径、全局路径配置变量,或使用d6tpipe使您的数据易于访问。3.混淆数据和代码很多人这样想:既然数据科学代码需要数据,为什么不把它转储到同一个目录中呢?当您这样做时,图像、报告和其他垃圾很有可能也会被保存到一个目录中。这是一团糟。├──data.csv├──ingest.py├──other-data.csv├──output.png├──report.html└──run.py解决方案:对文件夹进行分类,如data、Reports、codes等。请参阅#5并使用#1中提到的工具来存储和共享数据。4.使用Gitcommit命令处理数据和源代码。大多数人对他们的代码进行版本控制(如果你不这样做,那是你的错误之一!)。尝试共享数据时,您可能会想将数据文件添加到版本控制中。这适用于非常小的文件;但是git没有针对数据进行优化,尤其是对于大文件。gitadddata.csv解决方案:使用#1中提到的工具来存储和共享数据。如果您真的想对数据进行版本控制,请参阅d6tpipe、DVC(https://dvc.org/)和GitLargeFileStorage(https://git-lfs.github.com/)。5.编写函数而不是使用DAG说完了关于数据的所有内容,让我们来谈谈实际的代码。学习编码时首先要学习的是函数,因此数据科学代码主要被视为一系列以线性方式运行的函数。这可能会导致一些问题。defprocess_data(数据,参数):data=do_stuff(data)data.to_pickle('data.pkl')data=pd.read_csv('data.csv')process_data(数据)df_train=pd.read_pickle(df_train)model=sklearn.svm.SVC()model.fit(df_train.iloc[:,:-1],df_train['y'])解决方案:数据科学代码***被编写为一组相互依赖的任务,而不是写成线性链函数。使用d6tflow(https://github.com/d6t/d6tflow)或气流(https://airflow.apache.org/)。6.编写for循环和函数一样,for循环是您在学习编码时首先要学习的东西。for循环很容易理解,但是它们很慢而且过于冗长。这通常表明您没有意识到矢量化还有其他选择。x=range(10)avg=sum(x)/len(x);std=math.sqrt(sum((i-avg)**2foriinx)/len(x));zscore=[(i-avg)/stdforx]#shouldbe:scipy.stats.zscore(x)#orgroupavg=[]foriindf['g'].unique():dfdfg=df[df[g']==i]groupavg.append(dfg['g'].mean())#shouldbe:df.groupby('g').mean()解决方案:Numpy(http://www.numpy.org/),scipy(https://www.scipy.org/)和pandas(https://pandas.pydata.org/)为您认为可能需要循环的大多数情况提供矢量化函数。7.不写单元测试随着数据、参数或用户输入的变化,代码可能会崩溃,有时你甚至都没有注意到。这可能导致错误的输出,如果有人根据输出做出决定,错误的数据将导致错误的决定!解决方案:使用断言语句检查数据质量。pandas有一个平等测试,d6tstack(https://github.com/d6t/d6tstack)检查数据摄取,d6tjoin(https://github.com/d6t/d6tjoin/blob/master/examples-prejoin.ipynb)检查数据连接。这是数据检查示例的代码:assertdf['id'].unique().shape[0]==len(ids)#havedataforallids?assertdf.isna().sum()<0.9#catchmissingvaluesassertdf.groupby(['g','date'].size().max()==1#noduplicatevalues/date?assertd6tjoin.utils.PreJoin([df1,df2],['id','date']).is_all_matched()#allidsmatched?8.不记录代码为了赶时间做分析,你可能会吞下结果,然后把结果给客户或老板;一周后,他们来找你说“你能不能改变一下?”this”或者“canyouupdateDoyouwantthis?”这时候,当你看代码的时候,你已经不记得当初为什么要这样写了。现在想象一下,其他人也必须运行你的代码。..defsome_complicated_function(data):datadata=data[data['column']!='wrong']datadata=data.groupby('date').apply(lambdax:complicated_stuff(x))数据数据=数据[数据['value']<0.9]returndata解决方案:提供分析后,还要花额外的时间记录编码时做了什么。你会感谢你做到了,其他人会感谢你!这样你会看起来更专业。9.将数据保存为csv或pickle格式回到数据,毕竟我们在谈论数据科学。与函数和for循环一样,CSV和pickle文件也很常用,但它们并不是很好。CSV不包含架构,因此每个人都必须重新解析数字和日期。Pickles解决了这个问题,但只能在python中使用并且不会被压缩。这两种格式都不是存储大型数据集的好格式。defprocess_data(data,parameter):data=do_stuff(data)data.to_pickle('data.pkl')data=pd.read_csv('data.csv')process_data(data)df_train=pd.read_pickle(df_train)解决方法:使用parquet(https://github.com/dask/fastparquet)或您的数据模式的另一种二进制数据格式,两者都是压缩数据的理想格式。d6tflow会自动将任务的数据输出保存为parquet,这样你就不用再担心格式问题了。10.使用jupyternotebooksNotebooks这可能是有争议的:jupyternotebooks和CSV一样普遍。许多人使用它们。但这并不意味着它们是很棒的工具。jupyternotebooks助长了上面提到的软件工程中的坏习惯,特别是:你试图将所有文件转储到一个目录中编写自上而下运行的代码,而不是DAGs无法模块化代码难以调试代码很容易上手,但难以扩展。解决方案:使用pycharm(https://www.jetbrains.com/pycharm/)和/或spyder(https://www.spyder-ide.org/)。
