数据科学从业者常见的不良小习惯
Norm Niemer 京东云开发者社区 前天
选自Medium
京东云开发者社区编译
数据科学家是“比任何软件工程师都更擅长统计数据,比统计学家更擅长软件工程的一批人”。许多数据科学家都有统计学背景,同时也有着一些软件工程方面经验。我是一名在Stackoverflow上使用Python代码排名前1%的高级数据科学家,并与许多(初级)数据科学家们一起工作。在这个过程中,我发现大家其实都或多或少有着一些不太好的小习惯,以下是我列出的10个数据科学从业者常见的不良习惯列表。
1.没有共享代码中引用的数据
数据科学需要代码和数据,这点毋庸置疑。因此,如果别人要查证到你的结果,他们就需要访问数据。这看起来似乎很基本,但很多人都会忘记共享他们代码中引用数据。
1import pandas as pd2df1 = pd.read_csv('file-i-dont-have.csv') # fails3do_stuff(df)
解决方案:使用d6tpipe( Drive等,或者保存到数据库也可以。这样做的目的在于可以便于大家进行文件检索。(Notice:但不要将它们添加到Git,详情见下文)。
2.硬编码无法访问的路径
与错误1类似,如果您的硬编码路径别人无权访问,那他们则无法运行您的代码并且必须查看许多地方以手动更改路径。???!
1import pandas as pd2df = pd.read_csv('/path/i-dont/have/data.csv') # fails3do_stuff(df)4# or 5impor os6os.chdir('c:\\Users\\yourname\\desktop\\python') # fails
解决方案:使用相对路径、全局路径配置变量或用d6tpipe使您的数据易于访问。
3.将数据与代码混在一起
有人会问,由于数据科学代码需要数据,因此为什么不将它们转存到同一目录中呢?但这也意味着,当你在使用它的时候,你的图像、报告和其他垃圾也都会存在里面。Emm……可以说是一团糟呢!
1├── data.csv2├── ingest.py3├── other-data.csv4├── output.png5├── report.html6└── run.py
解决方案:将您的目录进行分类,如数据、报告、代码等。具体请参阅Cookiecutter Data Science或d6tflow项目模板()。(可用本文第1点中提到的工具来存储和共享数据。)
4. 使用Git提交源代码数据
大多数人现在用版本控制系统来管理他们的代码(如果你不这样的话,那将会是另一个错误!!?)。在尝试共享数据时,可能很容易将数据文件添加到版本控制中。这对于非常小的文件是可以的,但是git没有针对数据进行优化,尤其是大文件。
1git add data.csv
解决方案:建议使用第1点中提到的工具来存储和共享数据。如果您真的想要版本控制系统来数据,请参阅d6tpipe,DVC和Git大文件存储。
5.编写函数而不是DAGs
聊完数据相关的内容后,让我们来谈谈实际的代码部分!由于您在学习编码时学到的第一件事就是函数,因此数据科学代码主要被组织为一系列线性运行的函数。
1def process_data(data,parameter):2 data = do_stuff(data)3 data.to_pickle('data.pkl')4data = pd.read_csv('data.csv')5process_data(data)6df_train = pd.read_pickle(df_train)7model = sklearn.svm.SVC()8model.fit(df_train.iloc [:,:- 1],df_train [ 'Y'])
解决方案:数据科学代码不是线性地链接函数,而是更好地编写为一组具有它们之间依赖关系的任务。
6.写入循环
与函数一样,for循环是学习编码时学到的第一件事。这个东西不难理解,但它们很慢而且过于冗长,如果你使用他们,通常就表明你并没有发现矢量化的替代方案。
1x = range(10) 2avg = sum(x)/len(x); std = math.sqrt(sum((i-avg)**2 for i in x)/len(x)); 3zscore = [(i-avg)/std for x] 4# should be: scipy.stats.zscore(x) 5# or 6groupavg = [] 7for i in df['g'].unique(): 8 dfg = df[df[g']==i] 9 groupavg.append(dfg['g'].mean())10# should be: df.groupby('g').mean()
解决方案:Numpy,Scipy和Pandas为您认为可能需要循环的大多数情况提供了矢量化函数,可随时进去拽去您需要的。
7.忘写单元测试
随着数据、参数或用户输入的变化,您的代码极有可能在根本没注意到时就出现输出错误的情况。如果有人根据您的输出结果做出决定,那么错误的数据将有可能导致错误的决策!
解决方案:使用Assert语句检查数据质量。Pandas也有相同的测试,d6tstack检查数据摄取和数据连接。数据检查代码示例如下:
1assert df['id'].unique().shape[0] == len(ids) # have data for all ids?2assert df.isna().sum()<0.9 # catch missing values3assert df.groupby(['g','date']).size().max() ==1 # no duplicate values/date?4assert d6tjoin.utils.PreJoin([df1,df2],['id','date']).is_all_matched() # all ids matched?
8.没有记录代码
我能明白,你急着要做一些分析。于是,你把所有的数据、代码都放在一起,然后得出了结果交给你的客户或老板。一个星期后,他们回来说“你能改一下xyz”或“你能更新这部分内容吗?”。然后你看着你的代码,完全不记得你为什么这么做以及你怎么去做的了。你还敢想象其他人必须运行它这件事吗?
1 def some_complicated_function(data):2 data = data[data['column']!='wrong']3 data = data.groupby('date').apply(lambda x: complicated_stuff(x))4 data = data[data['value']<0.9]5 return data
解决方案:即使在您提供分析结果之后,也请一定要花费一部分额外的时间来记录您的操作过程。老板、客户以及你自己都一定会感谢自己这么做了!同时,这会让你看起来更专业!
9.将数据保存为CSV或Pickle
毕竟我们聊的是数据科学,因此让我们再回到”数据“层面来看看。就像函数和for循环一样,CSV和Pickle文件是常用的,但它们实际上并不是最佳选择。CSV不包含架构,因此每个人都必须再次解析数字和日期。Pickles虽然解决了这个问题但只能在Python中使用并且没办法被压缩。两者都不是存储大型数据集的好地方。
1 def process_data(data,parameter):2 data = do_stuff(data)3 data.to_pickle('data.pkl')4 data = pd.read_csv('data.csv')5 process_data(data)6df_train = pd.read_pickle(df_train)
解决方案:使用parquet或其他二进制数据格式,理论上是可以进行数据压缩的。d6tflow自动将任务的数据输出保存为parquet格式,因此您无需再对它进行处理。
10.使用Jupyter Notebooks
这里有一个富有争议的论点:Jupyter Notebooks和CSV一样普遍,有很多人都在使用它们。但这其实并不能证明他们是好用的。Jupyter Notebooks让很多人都养成了上面所提到的不一些良编程习惯,特别是:
您很想将所有文件转储到一个目录中
您编写的代码是按照top-bottom模式运行,而不是有向无环图(DAG)模式
您没有模块化您的代码
不易调试
代码和输出结果混在同一个文件中
缺乏很好的版本控制
很容易上手,但缺乏较好的扩展性
解决方案: 使用 pycharm/spyder.