博客专栏

EEPW首页 > 博客 > 独家 | 数据科学家对可复用Python代码的实用管理方法(附链接)

独家 | 数据科学家对可复用Python代码的实用管理方法(附链接)

发布人:数据派THU 时间:2021-09-19 来源:工程师 发布文章

作者:Matthew Mayo, KDnuggets

翻译:殷之涵

校对:欧阳锦

有很多不同的方法管理自己的代码,这取决于您的具体要求、个性、技术知识、所扮演角色和诸多其他因素。虽然经验丰富的开发人员可能有一套非常严格的方法可以跨多语言、项目和用例进行代码管理,但很少编写自己的代码的数据分析师由于缺乏必要性,可能会较为疏于代码管理。其实,在管理代码这件事情上并没有对错之分,这只是一个是否对您自己“有用”和“合适”的问题而已。

具体来说,我所指的“代码管理”是指您如何组织、存储和调用您自己编写的不同的代码段——这些代码段作为您对自己的编程工具箱的长期积累,是很有用的。编程的本质是自动化,因此如果一名编程者发现自己正在重复执行一些类似任务,那么就势必要考虑以某种方式对该任务的相关代码进行自动调用。

这就是我们经常要使用第三方库的原因。比如要使用支持向量机(SVM)算法时,我们不需要每次都把代码重新实现一遍;相反,我们可以使用一个库——也许是 Scikit-learn——这样我们就能好好利用众多前人随着时间推移所不断完善而成的智慧结晶了。

除了第三方库的使用,我们还要把这种“自动化思想”扩展到个人编程领域。您可能已经这样做了(我希望是的),但如果没有,以下是我作为一名数据科学家,对自己所写的可复用 Python 代码进行管理的几种固化下来的方法(按照最通用到最不通用来进行排序)。

自建代码库(Full-blown Libraries)

这是一种最通用的方法,也可以说是最“专业”的方法;然而,这并不意味着它适用于所有的情况。

如果您发现您在许多用例中都在频繁使用相同的功能,那么自己搭建一个代码库就是正确的选择。此外,如果您要复用的功能很容易参数化,那这个选择也十分合理;参数化的意思是,您可以通过编写和调用带有变量的通用函数来重复多次地处理任务,每次调用时都可以对变量进行重新定义。

举例说明,我经常发现我想在一个字符串中找到某个子字符串第 n 次出现的位置索引,但是并没有一个现成的Python标准库函数能支持这一需求。因此,我自己写了一段简单的代码,它接受一个字符串、一个子字符串以及我所求的第n次出现的“n”作为输入,返回值是字符串中子字符串第n次出现开始的位置索引(具体代码出处见:

https://stackoverflow.com/questions/1883980/find-the-nth-occurrence-of-substring-in-a-string)。

def find_nth(haystack, needle, n):
    start = haystack.find(needle)
    while start >= 0 and n > 1:
        start = haystack.find(needle, start+len(needle))
        n -= 1
    return start

由于我平日有很多文本处理类型的工作,所以我将上述函数连同一些经常使用的其他文本处理函数集合起来并创建了一个库,这个库就像其他任何Python 库一样被储存在我的计算机上,并且能够像其他任何库一样进行导入。创建库的方法虽然不难,但是步骤比较多,所以我就不做过多介绍了,感兴趣的读者可以参考这篇文章:

https://medium.com/analytics-vidhya/how-to-create-a-python-library-7d5aea80cc3f

所以现在我有了一个名为textproc的自建代码库,我可以随时轻松地导入和使用我的find_nth函数,再也不用复制并粘贴整段代码到我编写的每个要用到它的程序中了。

from textproc import find_nth
segment = line[:find_nth(line, ',', 4)].strip()

此外,如果我想扩展这个库——即把更多函数添加进去,或者想更改现有的 find_nth函数的代码,我只需要在底层这一处进行修改后再重新导入即可(而不需要在所有调用之处都进行一次相应的修改)。

基于特定项目的共享脚本

有时候并不需要自建代码库,因为您想要复用的代码并没有当前项目以外的用途,但您确实需要在本项目中对它进行复用。在这种情况下,您可以将这些函数放在一个脚本中,然后简单地按名称导入该脚本即可。

我在读研究生期间编写了大量和无监督学习相关的代码,特别是k-means 聚类。我编写了用于簇中心初始化、数据点和簇中心之间的距离计算、簇中心重新计算等函数,并使用不同的算法对这些任务进行实现。我很快发现,将其中一些算法函数的副本各自保存在一个单独的脚本中以供调用并不是最佳选择,反而将它们先集中在一个脚本中再进行导入会更好。“共享脚本”这个工作方式与库几乎相同,但这个过程是基于特定路径的,并且仅适用于某一特定项目。

很快我就积累了不同簇中心初始化函数和距离计算函数的脚本,以及加载和处理数据的函数的脚本。随着这些代码变得越来越参数化和具有普适性,它们最终被放到了一个正式的库中。

这似乎是事情的常见进展方式,至少根据我的经验是这样的:您在脚本中编写了一个满足当下使用需要的函数,然后使用它。随着项目扩展,或者又接手了一个类似项目,您意识到现在使用一个相同的函数会很方便,所以该函数就被放入了一个脚本中以便导入和使用。如果这种用途在短期内继续发挥作用,并且您发现该函数具有更广泛和更长期的用途,那么它就会被添加到现有库中,或者成为一个新库的基础组成部分。

导入简单脚本这个方法在使用Jupyter Notebook时同样有用,但在使用方式上有所不同。鉴于Jupyter Notebooks中大部分代码内容的临时性、探索性和实验性,我通常不会把一些notebooks作为模块导入到其他notebooks中。如果我发现多个notebooks都经常使用某些代码片段,那我就会把这些代码片段放入一个单独脚本中,并存储在这些notebooks所属的同一文件夹下,然后将其导入到需要使用它们的notebooks中。这种方法对我来说会更合理一些,同时具有更高的稳定性——相比于特定脚本,notebooks有更高的风险会被重新编辑,难以长期依赖。

基于特定任务的模板

我发现我经常重复执行一些相同的任务,而这些任务并不适合参数化,或者参数化的性价比实在很低(需要付出的时间精力远超所能得到的回报)。在这种情况下,我会把代码进行模板化,或者标准化(boiler-plating)。比起我在本文开头所提到的简单复制粘贴——这些是我在所有情况下都想要避开的工作,模板化的做法显然要复杂一些,但有时候这却是正确的选择。

例如,我经常需要进行列表化(listify)操作——即使我压根不清楚待处理的Pandas DataFrame中的内容,仍然需要确定列数和待输入的列以完成相关函数的编写,通常还需要对输出进行调整——上述这些都表明编写函数的确太耗时了。

为了应对这种情况,我编写了一个可灵活更改的脚本模板,并把它放在了一个用于储存此类模板的专用文件夹中。下面就是listify_df的代码段,它能把 CSV 文件转换成Pandas DataFrame,然后再输出为所需的HTML文件。

import pandas as pd
# Read CSV file into dataframe
csv_file = 'data.csv'
df = pd.read_csv(csv_file)
# Iterate over df, creating numbered list entries
i = 1
for index, row in df.iterrows():
entry = '<b>' + str(i) + \
'. <a href="' + \
row['url'] + \
'">' + \
row['title'] + \
'</a> + \
'\n\n<blockquote>\n' + \
row['description'] + \
'\n</blockquote>\n'
i += 1
print(entry)

在这个案例中,我们能够看到清晰的文件名以及对文件夹的有序管理,是很有助于管理这些常用代码段的。

单行代码和短代码块

重复的单行代码和短代码块总是难免出现在我们的日常工作中,为什么不想想办法做些自动化呢?

您可以在需要的时候使用文本扩展工具来插入简短的“短语”。我会用AutoKey来管理这样的短语,这些短语和一些触发关键字相联系,一旦输入这些关键字,短语就会自动插入。

AutoKey

https://github.com/autokey/autokey

例如,您在处理特定类型的项目时是否总是需要导入一批相同的库?您可以通过输入“#nlpimport”来设置处理特定任务所需的所有导入工作,这一输入会被识别为触发关键字并被替换为以下内容:

import sys, requests
import numpy as np
import pandas as pd
import texthero
import scattertext as st
import spacy
from spacy.lang.en.stop_words import STOP_WORDS
from datasets import load_metric, list_metrics
from transformers import pipeline
from fastapi import FastAPI

需要注意的是,一些 IDE 是具有这种自动插入功能的。我自己通常使用美化的文本编辑器来编写代码,所以对于我来说AutoKey是非常必要且有用的。如果您用的是具备此类功能的IDE,那就太好了。关键是,您再也不用总是写一些重复的代码了。

以上就是我作为数据科学家对可复用 Python 代码管理方法的概述。希望它们能对您有所帮助!

编辑:王菁

校对:汪雨晴

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。



关键词: AI

相关推荐

技术专区

关闭