数据科学家是“比软件工程师更擅长统计学,比统计学家更擅长软件工程的人”。许多数据科学家都具备统计学背景,可是在软件工程方面的经验甚少。我是一名资深数据科学家,在Stackoverflow的python编程方面排名前1%,并与许多(初级)数据科学家共事。如下是我常常看到的10大常见错误,本文将为你相关解决方案:html
数据科学须要代码和数据。所以,为了让别人能够复现你的结果,他们须要可以访问到数据。道理很简单,可是不少人忘记分享他们代码中的数据。python
import pandas as pd df1 = pd.read_csv('file-i-dont-have.csv') # fails do_stuff(df)
解决方案:使用d6tpipe(https://github.com/d6t/ d6tpipe)来共享你的代码中的数据文件、将其上传到S3/web/google驱动等,或者保存到数据库,以便于别人能够检索到文件(可是不要将其添加到git,缘由见下文)。git
与错误1类似,若是你对别人没法访问的路径进行硬编码,他们将没法运行你的代码,而且必须仔细查看代码来手动更改路径。使人崩溃!github
import pandas as pd df = pd.read_csv('/path/i-dont/have/data.csv') # fails do_stuff(df) # or import os os.chdir('c:\\Users\\yourname\\desktop\\python') # fails
解决方案:使用相对路径、全局路径配置变量或d6tpipe,使你的数据易于访问。web
d6tpipe:数据库
https://github.com/d6t/d6tpipapache
既然数据科学的代码中包含数据,为何不把它们放到同一目录中?那样你还能够在其中保存图像、报告和其余垃圾。哎呀,真是一团糟!编程
├── data.csv ├── ingest.py ├── other-data.csv ├── output.png ├── report.html └── run.py
解决方案:将你的目录进行分类,好比数据、报告、代码等。请参阅Cookiecutter Data Science或d6tflow项目模板[见#5],并使用#1中提到的工具来存储和共享数据。数组
Cookiecutter Data Science: https://drivendata.github.io/cookiecutter-data-science/ d6tflow项目模板: https://github.com/d6t/d6tflow-templat
如今,大多数人对他们的代码使用版本控制(若是你不使用,那就是另一个错误,请参阅git:https://git-scm.com/)。在尝试共享数据时,很容易将数据文件添加到版本控制中。当文件很小时是能够的,可是git并无针对数据进行优化,尤为是大文件。cookie
git add data.csv
解决方案:使用第1点中提到的工具来存储和共享数据。若是你真的但愿对数据进行版本控制,请参阅 d6tpipe,DVC和Git大文件存储。
d6tpipe: https://github.com/d6t/d6tpipe DVC: https://dvc.org/ Git大文件存储: https://git-lfs.github.com
关于数据部分已经够多了,如今来谈一谈实际的代码!在学习编程时最早学习的内容之一就是函数,数据科学代码一般由一系列线性运行的函数组成。
这会致使一些问题,请参阅“为何你的机器学习代码可能很差的4个缘由”:
https://github.com/d6t/d6t-python/blob/master/blogs/reasons-why-bad-ml-code.rst
def process_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) model = sklearn.svm.SVC() model.fit(df_train.iloc[:, :-1], df_train['y'])
解决方案:数据科学代码不是一系列线性链接的函数,而是一组具备依赖关系的任务集合。请使用d6tflow或airflow。
d6tflow:
https://github.com/d6t/d6tflow-template
airflow:
与函数相似,for循环也是你学习编程时最初学习的内容。它们易于理解,可是运行缓慢且过于冗长,一般意味着你不了解矢量化的替代方案。
x = range(10) avg = sum(x)/len(x); std = math.sqrt(sum((i-avg)**2 for i in x)/len(x)); zscore = [(i-avg)/std for x] # should be: scipy.stats.zscore(x) # or groupavg = [] for i in df['g'].unique(): dfg = df[df[g']==i] groupavg.append(dfg['g'].mean()) # should be: df.groupby('g').mean()
解决方案:Numpy,scipy和pandas为你须要for循环的状况提供了矢量化函数。
Numpy:
scipy:
pandas:
随着数据、参数或用户输入的改变,你的代码可能会出现问题,有时你并无注意到。这可能会致使糟糕的输出结果,而若是有人基于你的输出作出决策,那么糟糕的数据将会致使糟糕的决策。
解决方案:使用assert语句来检查数据质量。pandas有相等测试,d6tstack有数据提取检查以及用于数据链接的d6tjoin。
pandas相等测试:
https://pandas.pydata.org/pandas-docs/stable/reference/general_utility_functions.html
d6tstack:
https://github.com/d6t/d6tstack
d6tjoin:
https://github.com/d6t/d6tjoin/blob/master/examples-prejoin.ipyn
如下是数据检查的示例代码:
assert df['id'].unique().shape[0] == len(ids) # have data for all ids? assert df.isna().sum()<0.9 # catch missing values assert df.groupby(['g','date']).size().max() ==1 # no duplicate values/date? assert d6tjoin.utils.PreJoin([df1,df2],['id','date']).is_all_matched() # all ids matched?
我明白,你急着作出一些分析结果。你把事情汇总到一块儿分析,将结果交给你的客户或老板。一个星期以后,他们回来讲,“能够把XXX改一下吗”或者“能够更新一下这里吗”。你看着你的代码,可是并不记得你当初为何这么写。如今就像是在运行别人的代码。
def some_complicated_function(data): data = data[data['column']!='wrong'] data = data.groupby('date').apply(lambda x: complicated_stuff(x)) data = data[data['value']<0.9] return data
解决方案:即便在你已经提交分析报告后,也要花费额外的时间,来对你作的事情编写说明文档。之后你会感谢本身,别人更会感谢你。那样显得你很专业!
回到数据,毕竟是在讲数据科学。就像函数和for循环同样,CSV和pickle文件很经常使用,可是并很差用。CSV文件不包含纲要(schema),所以每一个人都必须再次解析数字和日期。Pickle文件解决了这个问题,可是它只能在python中使用,而且不能压缩。二者都不是存储大型数据集的最优格式。
def process_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或其余带有数据纲要的二进制数据格式,在理想状况下能够压缩数据。d6tflow将任务的数据输出保存为parquet,无需额外处理。
parquet:
https://github.com/dask/fastparquet
d6tflow:
https://github.com/d6t/d6tflow-template
最后一个是很有争议的错误:jupyter notebook和csv文件同样广泛。许多人使用它们,可是这并不意味着它们很好。jupyter notebook滋长了上述提到的许多不良编程习惯,尤为是:
把全部文件保存在一个目录中
编写从上至下运行的代码,而不是DAG
没有对代码进行模块化
很难调试
代码和输出混在一个文件中
没有很好的版本控制
它容易上手,可是扩展性不好。
解决方案:使用pycharm和/或spyder。
pycharm:
https://www.jetbrains.com/pycharm/
spyder:
原文连接 本文为云栖社区原创内容,未经容许不得转载。