|
|
51CTO旗下网站
|
|
移动端

十个编码过程中的“坑”,一篇文章帮你填平了!

数据科学家是“比任何软件工程师都更擅长统计学、又比任何统计学家都更擅长软件工程”的人。许多数据科学家都有统计学背景,但在软件工程方面经验很少。本文列出了常见的10个编码错误,希望你能认真阅读并避免它们。

作者:读芯术来源:读芯术|2019-06-10 06:22

数据科学家是“比任何软件工程师都更擅长统计学、又比任何统计学家都更擅长软件工程”的人。许多数据科学家都有统计学背景,但在软件工程方面经验很少。本文列出了常见的10个编码错误,希望你能认真阅读并避免它们。

1. 没有共享代码中引用的数据

数据科学既需要代码也需要数据。因此,其他人要能够获取数据才能重现结果。这听起来是很基本的要求,但很多人都忘记和代码一起共享数据。

  1. import pandas as pd 
  2. df1 =pd.read_csv('file-i-dont-have.csv') # fails 
  3. do_stuff(df) 

解决方案:

使用d6tpipe(https://github.com/d6t/d6tpipe)共享数据文件和代码,或将二者上传到S3 / web /google drive等或保存到数据库,以便收件人可以检索文件(但不要将它们添加到git,见下文)。

2. 硬编码无法访问的路径

与第一个错误类似,如果你对其他人无权访问的路径进行硬编码,他们就无法运行代码并且必须查看许多地方以手动更改路径。

  1. import pandas as pd 
  2. df = pd.read_csv('/path/i-dont/have/data.csv')# fails 
  3. do_stuff(df) 
  4. # or 
  5. import os 
  6. os.chdir('c:\\Users\\yourname\\desktop\\python')# fails 

解决方案:使用相对路径,全局路径配置变量,或使用d6tpipe 让你的数据易于访问。

3. 混淆数据与代码

很多人会这么想:由于数据科学代码需要数据,为什么不将它转储到同一目录中?当你这么做的时候,很有可能也会把图像,报告和其他垃圾保存到一个目录下。这样就一团乱麻了。

  1. ├── data.csv 
  2. ├── ingest.py 
  3. ├── other-data.csv 
  4. ├── output.png 
  5. ├── report.html 
  6.   
  7. └── run.py 

解决方案:将文件夹归类,如数据、报告、代码等。请参阅#5,并使用#1中提到的工具来存储和共享数据。

4. 和源代码一起用Gitcommit命令处理数据

大多数人会在版本控制他们的代码(如果你不这样做,那这也是你犯的错误之一!)。在尝试共享数据时,你可能很想把数据文件添加到版本控制中。这对于非常小的文件是可以的;但是git无法针对数据进行优化,尤其是对大文件来说。

  1. git add data.csv 

解决方案:使用#1中提到的工具来存储和共享数据。如果你真的想版本控制数据,请参阅d6tpipe, DVC(https://dvc.org/) 和Git Large File Storage(https://git-lfs.github.com/)。

5. 编写函数而不是使用DAGs

说了这么多数据,让我们谈谈实际的代码。

学习编码时学到的第一件事就是函数,因此数据科学代码主要被处理为一系列线性运行的函数。这会导致一些问题。

  1. defprocess_data(data, parameter): 
  2.     data = do_stuff(data) 
  3.     data.to_pickle('data.pkl') 
  4.   
  5. data =pd.read_csv('data.csv') 
  6. process_data(data) 
  7. df_train =pd.read_pickle(df_train) 
  8. model = sklearn.svm.SVC() 
  9. model.fit(df_train.iloc[:,:-1],df_train['y']) 

解决方案:数据科学代码最好写为一组相互之间具有依赖性的任务,而不是写为线性链式函数。

使用 d6tflow(https://github.com/d6t/d6tflow) 或airflow(https://airflow.apache.org/)。

6. 写for循环

与函数一样,for循环是学习编码时首先学到的。For循环容易理解,但它们很慢而且过于冗长。这通常表明了你没意识到还有矢量化替代方案。

  1. x = range(10) 
  2. avg =sum(x)/len(x); std = math.sqrt(sum((i-avg)**2 for i in x)/len(x)); 
  3. zscore =[(i-avg)/std for x] 
  4. # should be:scipy.stats.zscore(x) 
  5.   
  6. # or 
  7. groupavg = [] 
  8. for i indf['g'].unique(): 
  9.         dfdfg = df[df[g']==i] 
  10.         groupavg.append(dfg['g'].mean()) 
  11. # should be:df.groupby('g').mean() 

解决方案:

Numpy(http://www.numpy.org/), scipy(https://www.scipy.org/)和pandas(https://pandas.pydata.org/)为大多数你认为可能需要循环的情况提供了矢量化函数。

7. 不写单元测试

随着数据,参数或用户输入的变化,代码可能会中断,有时你甚至注意不到。这可能导致输出错误,如果有人根据输出做决策,那么糟糕的数据将导致错误的决策!

解决方案:使用assert语句检查数据质量。pandas有同等性测试,d6tstack

(https://github.com/d6t/d6tstack) 检查数据摄取,d6tjoin

(https://github.com/d6t/d6tjoin/blob/master/examples-prejoin.ipynb)检查数据连接。以下是数据检查示例的代码:

  1. assertdf['id'].unique().shape[0] == len(ids) # have data for all ids? 
  2. assertdf.isna().sum()<0.9 # catch missing values 
  3. assertdf.groupby(['g','date']).size().max() ==1 # no duplicate values/date? 
  4. assertd6tjoin.utils.PreJoin([df1,df2],['id','date']).is_all_matched() # all idsmatched? 

8. 不记录代码

为了急着做分析,你可能囫囵吞枣地弄出结果,然后把结果交给客户或老板;一个星期后,他们找到你说“能改一下这里吗”或“能更新一下这个吗”。这时你看看代码,完全不记得当初为什么这么写了。现在想象一下,其他人还必须运行你的代码……

  1. defsome_complicated_function(data): 
  2.         datadata = data[data['column']!='wrong'] 
  3.         datadata = data.groupby('date').apply(lambdax: complicated_stuff(x)) 
  4.         datadata = data[data['value']<0.9
  5.         return data 

解决方案:在提供分析之后,也要花费额外的时间来记录编码时做了什么。你会庆幸自己这么做了的,其他人更会感谢你!这样你会看起来更专业。

9. 将数据保存为csv或pickle格式

回到数据,毕竟我们在谈数据科学。就像函数和for循环一样,CSV和pickle文件很常用,但它们实际上并不是很好。CSV不包含架构,因此每个人都必须再次解析数字和日期。Pickles解决了这个问题但只能在python中使用并且不会被压缩。两者都不是存储大型数据集的好格式。

  1. defprocess_data(data, parameter): 
  2.     data = do_stuff(data) 
  3.     data.to_pickle('data.pkl') 
  4.   
  5. data =pd.read_csv('data.csv') 
  6. process_data(data) 
  7. df_train = pd.read_pickle(df_train) 

解决方案:

对数据模式使用 parquet(https://github.com/dask/fastparquet)或其他二进制数据格式,这两者是压缩数据的理想格式。d6tflow自动将任务的数据输出保存为parquet,这样就不用再操心格式问题了。

10. 使用jupyternotebooks笔记本

这一点也许颇具争议:jupyternotebooks和CSV一样普遍。很多人都使用它们。但这并不意味它们就是很好的工具。jupyternotebooks助长了上面提到的软件工程中的坏习惯,特别是:

  • 你很想将所有文件转储到一个目录中
  • 编写自上而下运行的代码,而不是DAGs
  • 没有将代码模块化
  • 难以纠错
  • 代码和输出混在一个文件中
  • 没有很好地进行版本控制
  • 上手很容易,但扩展很难。

解决方案:

使用pycharm (https://www.jetbrains.com/pycharm/)和/或spyder(https://www.spyder-ide.org/)。

【编辑推荐】

  1. JavaScript:十大排序的算法思路和代码实现
  2. 500行Python代码打造刷脸考勤系统,其实也就那么简单
  3. 只用120行Java代码写一个自己的区块链
  4. 这三个技巧,让你的代码可读性提高300%
  5. 码妞:领导让我重构代码,怎么办?
【责任编辑:赵宁宁 TEL:(010)68476606】

点赞 0
分享:
大家都在看
猜你喜欢

订阅专栏+更多

WOT2019全球人工智能技术峰会

WOT2019全球人工智能技术峰会

通用技术、应用领域、企业赋能三大章节,13大技术专场,60+国内外一线人工智能精英大咖站台,分享人工智能的平台工具、算法模型、语音视觉等技术主题,助力人工智能落地。
共50章 | WOT峰会

0人订阅学习

Spring Boot 爬虫搜索轻松游

Spring Boot 爬虫搜索轻松游

全栈式开发之旅
共4章 | 美码师

77人订阅学习

Linux性能调优攻略

Linux性能调优攻略

性能调优规范
共15章 | 南非蚂蚁

219人订阅学习

读 书 +更多

UNIX到Linux的移植

本书讲述怎样把UNIX环境下的应用程序移植到Linux环境上运行,是一本综合的开发和解决问题的参考手册 。本书详细描述了当前IT行业中被广泛应...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊

51CTO服务号

51CTO播客