dyl*_*fan 9 python directory-structure setuptools python-3.x
最近几天我花了很多时间学习如何构建数据科学项目,以保持简单,可重用和pythonic.坚持我已经创建的这个指南my_project.你可以在下面看到它的结构.
??? README.md
??? data
? ??? processed <-- data files
? ??? raw
??? notebooks
| ??? notebook_1
??? setup.py
|
??? settings.py <-- settings file
??? src
??? __init__.py
?
??? data
??? get_data.py <-- script
Run Code Online (Sandbox Code Playgroud)
我定义了一个从中加载数据的函数.data/processed.我想在其他脚本中以及位于.notebooks中的jupyter笔记本中使用此函数.
def data_sample(code=None):
df = pd.read_parquet('../../data/processed/my_data')
if not code:
code = random.choice(df.code.unique())
df = df[df.code == code].sort_values('Date')
return df
Run Code Online (Sandbox Code Playgroud)
显然,除非我直接在定义它的脚本中运行它,否则此函数无法在任何地方运行.我的想法是创建settings.py我声明的地方:
from os.path import join, dirname
DATA_DIR = join(dirname(__file__), 'data', 'processed')
Run Code Online (Sandbox Code Playgroud)
所以现在我可以写:
from my_project import settings
import os
def data_sample(code=None):
file_path = os.path.join(settings.DATA_DIR, 'my_data')
df = pd.read_parquet(file_path)
if not code:
code = random.choice(df.code.unique())
df = df[df.code == code].sort_values('Date')
return df
Run Code Online (Sandbox Code Playgroud)
问题:
这种常见做法是以这种方式引用文件吗?settings.DATA_DIR看起来有点难看.
这根本settings.py应该怎么用?它应该放在这个目录中吗?我曾在不同的点在此看到它的回购下.samr/settings.py
我知道可能没有"一个正确的答案",我只是试图找到处理这些事情的逻辑,优雅的方式.
我正在维护一个基于 DataDriven Cookiecutter 的经济数据项目,我认为这是一个很棒的模板。
对我来说,将数据文件夹和代码分开似乎是一个优势,允许将您的工作视为定向转换流(“ DAG”),从不可变的初始数据开始,一直到中期和最终结果。
最初,我回顾了pkg_resources,但拒绝使用它(语法很长并且缺乏对创建包的理解),而是使用自己的在目录中导航的辅助函数/类。
本质上,助手做了两件事
1. 将项目根文件夹和其他一些路径保留在常量中:
# shorter version
ROOT = Path(__file__).parents[3]
# longer version
def find_repo_root():
"""Returns root folder for repository.
Current file is assumed to be:
<repo_root>/src/kep/helper/<this file>.py
"""
levels_up = 3
return Path(__file__).parents[levels_up]
ROOT = find_repo_root()
DATA_FOLDER = ROOT / 'data'
UNPACK_RAR_EXE = str(ROOT / 'bin' / 'UnRAR.exe')
XL_PATH = str(ROOT / 'output' / 'kep.xlsx')
Run Code Online (Sandbox Code Playgroud)
这与您对 所做的类似DATA_DIR。一个可能的弱点是,这里我手动硬编码帮助程序文件相对于项目根目录的相对位置。如果辅助文件位置发生移动,则需要进行调整。但是,嘿,这与Django中的做法相同。
2. 允许访问raw、interim和processed文件夹中的特定数据。
这可以是一个简单的函数,按文件夹中的文件名返回完整路径,例如:
def interim(filename):
"""Return path for *filename* in 'data/interim folder'."""
return str(ROOT / 'data' / 'interim' / filename)
Run Code Online (Sandbox Code Playgroud)
在我的项目中,我有年月子文件夹interim和processed目录,并且我按年、月和有时频率来处理数据。对于这个数据结构,我有
InterimCSV提供ProcessedCSV参考特定路径的类,例如:
from . helper import ProcessedCSV, InterimCSV
# somewhere in code
csv_text = InterimCSV(self.year, self.month).text()
# later in code
path = ProcessedCSV(2018,4).path(freq='q')
Run Code Online (Sandbox Code Playgroud)
助手的代码在这里。此外,如果子文件夹不存在,这些类会创建子文件夹(我希望在临时目录中进行单元测试),并且有一些方法可以检查文件是否存在并读取其内容。
在您的示例中,您可以轻松地将根目录固定在 中setting.py,但我认为您可以在抽象数据方面向前迈进一步。
目前data_sample()混合了文件访问和数据转换,这不是一个好兆头,并且还使用全局名称,这是函数的另一个坏兆头。我建议您可以考虑以下几点:
# keep this in setting.py
def processed(filename):
return os.path.join(DATA_DIR, filename)
# this works on a dataframe - your argument is a dataframe,
# and you return a dataframe
def transform_sample(df: pd.DataFrame, code=None) -> pd.DataFrame:
# FIXME: what is `code`?
if not code:
code = random.choice(df.code.unique())
return df[df.code == code].sort_values('Date')
# make a small but elegant pipeline of data transfomation
file_path = processed('my_data')
df0 = pd.read_parquet(file_path)
df = transform_sample(df0)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
553 次 |
| 最近记录: |