使用pandas链接数据转换方法的设计模式

2024-05-23 23:51:54 发布

您现在位置:Python中文网/ 问答频道 /正文

我每月收到一个csv文件,其中有一些列。无论我收到什么列,我都应该输出一个csv,其中包含列C1、C2、C3、。。。C29,C30如果可能+一个日志文件,上面有我采取的步骤

我知道,数据转换的顺序应该是t1、t2、t3、t4、t5

t1 generates columns C8, C9, C12, C22 using C1, C2, C3, C4
t2 generates columns C10, C11, C17 using C3, C6, C7, C8
t3 generates columns C13, C14, C15, C16 using C5, C8, C10, C11, C22
t4 generates columns C18, C19, C20, C21, C23, C24, C25 using C13, C15
t5 generates columns C26, C27, C28, C29, C30 using C5, C19, C20, C21

我无法控制输入数据中的列

如果我的输入数据有C1,C2,C3,C4,C5,C6,C7列,我可以生成所有的C1。。。C30柱

如果我的输入数据有C1、C2、C3、C4、C5、C6、C7、C8、C10、C11、C17列,我可以生成所有C1。。。C30列,但我应该跳过t2,因为它不是必需的

如果我的输入数据有C1、C2、C3、C4、C6、C7,我只能做t1、t2、t3、t4。我无法运行t5,因此我应该仅使用NaN值创建C26、C27、C28、C29、C30列,并且我应该在日志中添加“无法执行t5转换,因为缺少C5。C26、C27、C28、C29、C30填充NaN值”

我的t1、t2、t3、t4、t5已经创建好了,但我不知道如何以优雅的方式组织代码,以使代码重复最少

我必须在很短的时间内开发代码。因此,我所有的t1、t2、t3、t4、t5方法看起来都像

def ti(df):
    output_cols = get_output_cols()
    if output_cols_already_exist(df, output_cols):
        return df, "{} skipped, the output cols {} already exist".format(inspect.stack()[0][3], output_cols)
    else:
        input_cols = get_required_input_cols()
        missing_cols = get_missing_cols(df, input_cols):
        if missing_cols == []:
            // do stuff
            log = "Performed {} transformation. Created {} columns".format(inspect.stack()[0][3], input_cols)
        else:
            for col in input_cols:
                df[col] = np.NaN
            log = "Cannot perform {} transformation because {} columns are missing. {} are filled with NaN values".format(inspect.stack()[0][3], missing_cols, output_cols)

此外,我还以以下方式使用这些函数:

text = ""
df = pd.read_csv(input_path)
df, log_text = t1(df)
text = text + log_text + "\n"
df, log_text = t2(df)
text = text + log_text + "\n"
df, log_text = t3(df)
text = text + log_text + "\n"
df, log_text = t4(df)
text = text + log_text + "\n"
df, log_text = t5(df)
text = text + log_text + "\n"
df.to_csv("output_data.csv", index = False)
logging.info(text)

正如您所看到的,我的代码既丑陋又重复。现在我有时间重构它,但我不知道什么是最好的方法。我还希望我的代码是可扩展的,因为我也在考虑添加t6转换。你能帮我给出一些我可以遵循的方向/设计模式吗?(我还可以使用pandas以外的其他python库)


Tags: columnstextlogdfinputoutputt1t3
1条回答
网友
1楼 · 发布于 2024-05-23 23:51:54

因为在Python中,函数是first-class objects,所以您可以重构代码,通过提取t[i]函数的区别(即do stuff部分),将其作为辅助函数并将其视为参数,从而泛化t[i]函数

在调用函数(t1、t2等,或下文中的重构助手版本)时,您还可以通过在列表上迭代来避免重复

最后,使用f-strings有助于提高代码的可读性

大概是这样的:

# t function takes a dataframe and a function as parameters
def t(df, do_stuff_func):
    output_cols = get_output_cols()
    if output_cols_already_exist(df, output_cols):
        return (
            df,
            (
                f"{inspect.stack()[0][3]} skipped, "
                f"the output cols {output_cols} already exist",
            ),
        )
    else:
        input_cols = get_required_input_cols()
        missing_cols = get_missing_cols(df, input_cols)
        if missing_cols == []:
            # Call the helper function
            do_stuff_func()
            log = (
                f"Performed {inspect.stack()[0][3]} transformation."
                f"Created {input_cols} columns"
            )
        else:
            for col in input_cols:
                df[col] = np.NaN
            log = (
                f"Cannot perform {inspect.stack()[0][3]} transformation"
                f"because {missing_cols} columns are missing. "
                f"{output_cols} are filled with NaN values"
            )

# Define the five new 'do_stuff' functions
def do_stuff1():
    pass
...
def do_stuff5():
    pass

# Store the functions
do_stuff_funcs = [do_stuff1, do_stuff2, do_stuff3, do_stuff4, do_stuff5]

# Call t function in combination with df and do_stuff_funcs helpers
for do_stuff_func in do_stuff_funcs:
    df, log_text = t(df, do_stuff_func)
    text = text + log_text + "\n"

# Save the results
df.to_csv("output_data.csv", index = False)
logging.info(text)

相关问题 更多 >