【51CTO.com快译】数据科学家是“比任何软件工程师更擅长统计方法,又比任何统计学家更擅长软件工程的人”。许多数据科学家学过统计学,但在软件工程方面经验很少。我是一名高级数据科学家,接触过许多(初级)数据科学家。下面是我经常看到的10个常见错误。
1. 不共享代码中引用的数据
数据科学需要代码和数据。因此,为了让别人能够重现你的结果,他们需要能访问数据。这点似乎很基础,但好多人忘记与他们的代码共享数据。
- import pandas as pd
- df1 = pd.read_csv('file-i-dont-have.csv') # fails
- do_stuff(df)
解决办法:使用d6tpipe与你的代码共享数据文件、上传到S3/web/google drive等,或者保存到数据库,以便接收方可以检索文件(但别将它们添加到git,详见下文)。
2. 硬编码无法访问的路径
与第1个错误相似,如果你对别人无权访问的路径进行硬编码,他们无法运行你的代码,必须查看好多地方以便手动更改路径。太糟了!
- 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,使你的数据易于访问。
3. 将数据与代码混合
由于数据科学代码需要数据,何不将数据放到同一目录中?那样你在处理时,还可以将图像、报告和其他内容保存在那里。真是一团糟!
- ├── data.csv
- ├── ingest.py
- ├── other-data.csv
- ├── output.png
- ├── report.html
- └── run.py
解决办法:对你的目录分门别类,比如数据、报告和代码等。请参阅Cookiecutter Data Science项目,使用第1点中提到的工具来存储和共享数据。
4. Git提交数据和源代码
大多数人现在对其代码进行版本控制。如果你不这么做,这是另一个错误!请参阅git。尝试共享数据时,可能忍不住将数据文件添加到版本控制中。这对很小的文件来说没问题,但是git并未针对数据(尤其是大文件)进行优化。
- git add data.csv
解决办法:使用第1点中提到的工具来存储和共享数据。如果你真想要对数据进行版本控制,请参阅d6tpipe、DVC和Git大文件存储。
5. 编写函数而不是DAG
数据方面说得够多了,不妨聊聊实际的代码!学习编程时***了解的内容之一是函数,数据科学代码主要被组织成一系列线性运行的函数。这会导致几个问题,请参阅《你的机器学习代码可能很糟糕的4个原因》。
- 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。
6. 编写for loops
与函数一样,for loops是你在学习编程时***学到的内容。易于理解,但它们很慢而且过于冗长,通常表明你不知道可替代的向量化函数。
- 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 loops的大多数任务。
7. 不编写单元测试
随着数据、参数或用户输入的变化,代码可能出问题,而有时你浑然不知。这可能导致糟糕的输出;如果有人根据你的输出做决定,糟糕的数据会导致糟糕的决策!
解决办法:使用assert语句检查数据质量。Pandas有相等测试,d6tstack可检查数据摄取,d6tjoin则可检查数据连接。示例数据检查代码如下:
- 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?
8.未将代码记入文档
你急着做一些分析,想把结果交给客户或老板。一星期后,他们回复“可以更改xyz吗?”或“请更新这个”。你看了看自己编写的代码,不记得当初为什么这么编写。而现在别人要运行它。
- 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
解决办法:就算你已提交了分析,也要抽点时间将编写的代码记入文档。你会感谢自己,别人更会感谢你!那样你显得很专业!
9.将数据保存为csv或pickle
回到数据,毕竟是数据科学。就像函数和for loops一样,CSV和pickle文件经常使用,但它们实际上不是很好。CSV不包含模式,因此每个人都要再次解析数字和日期。pickles解决了这个问题,但只适用于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,那样你不必处理它。
10. 使用jupyter notebook
***一个是颇有争议的错误:jupyter notebook和CSV一样普遍。很多人都使用它们,这并不意味着它们很好。jupyter notebook助长上面提到的许多糟糕的软件工程习惯,尤其是:
- 你忍不住想把所有文件放到一个目录中
- 你编写自上而下运行的代码,而不是DAG
- 你没有使代码实现模块化
- 很难调试
- 代码和输出混合在一个文件中
- 没有很好的版本控制
- 感觉易于上手,但扩展性很差。
原文标题:Top 10 Coding Mistakes Made by Data Scientists,作者:Norman Niemer
【51CTO译稿,合作站点转载请注明原文译者和出处为51CTO.com】