【问题标题】:How can I run operations on a set of dataframes with a for loop?如何使用 for 循环在一组数据帧上运行操作?
【发布时间】:2019-08-24 18:23:01
【问题描述】:

这是我遇到的一个普遍问题,但我将使用 Titanic 数据集作为示例。为了同时在训练集和测试集上进行操作,我将它们结合起来:

combined = [train_df, test_df]

我还简化了每位乘客的头衔,因此现在每一个都是 8 种可能性之一。对于 train_df 和 test_df,我现在想为“标题”列制作假人,将它们添加到数据框中,然后删除原始的“标题”列。我提出的代码是:

for df in combined:
    df = pd.concat([df,pd.get_dummies(df.Title)],axis=1)
    df = df.drop('Title',axis=1)

当我在单个数据帧上手动执行这些操作时,这些操作确实有效,但在运行 for 循环时什么也没有发生。我错过了什么?

【问题讨论】:

    标签: python loops dataframe for-loop concat


    【解决方案1】:

    这不起作用,因为您正在修改列表中变量的副本,并且从未将其分配回列表中。

    例如:

    a = [0,1,2,3]
    for i in a:
        i = i+1
    a
    >>> [0, 1, 2, 3]
    

    您需要的是访问列表中的元素:

     a = [0,1,2,3]
     for i in range(len(a)):
        a[i] = a[i]+1
     a
     >>> [1, 2, 3, 4]
    

    或者用更简单的方式:

    a = [0,1,2,3]
    a = [i+1 for i in a]
    a
    >>> [1, 2, 3, 4]
    

    所以在你的情况下:

    for df in range(len(combined)):
        combined[df] = pd.concat([combined[df],pd.get_dummies(combined[df].Title)],axis=1)
        combined[df] = combined[df].drop('Title',axis=1)
    

    或者以更简单的方式(使用迭代器无索引)

    combined = [pd.concat([df,pd.get_dummies(df.Title)],axis=1).drop('Title',axis=1) for df in combined]
    

    编辑

    您似乎对python中的内存如何工作以及如何更新变量存在误解。

    假设a,b = 3,4l = [a,b] 然后改变a 或b 将不会改变l。一旦创建,它将独立于 a 和 b 生活。你也会串联。因此,更新列表不会更新用于其创建的变量。您必须将新值分配给变量。为此,由于您不希望列表在使用后存在,因此最好的方法是执行一个函数:

    def my_func(df):
        df = pd.concat([df,pd.get_dummies(df.Title)],axis=1)
        df = df.drop('Title',axis=1)
        return df
    

    然后将其应用于两个数据框:

    train_df = my_func(train_df) 
    test_df= my_func(test_df) 
    

    二次编辑

    那么为什么它起作用了?又是一个关于内存如何在 python 中工作的问题,尤其是迭代器。我们不会详细介绍,但让我们以列表为例(类似于此处的数据框):

    a = [[0,1],[2,3,4]]
    for i in a:
        i.pop(0)
    a
    >>> [[1], [3, 4]]
    

    您看到我们已经修改了列表中的变量。这是因为我们在任何时候都没有创建迭代器的命名副本。我们在内存中修改了当前对象。所以使用Inplace=True 就是这样做的。它是直接修改数据框,而不是创建它的副本。

    【讨论】:

    • 好的,我们正在取得进展,但我注意到以下内容:train_df 和 test_df 在执行您的代码后仍然没有改变,尽管 combine[0] 和 combined[1] 包含正确的解决方案。这让我感到困惑,因为实际上 train_df 和 test_df 应该与 combine[0] 和 combined[1] 相同,对吧?这就是在开始时定义组合数据框的方式。是否有可能在使用 range(len(combined)) 时,组合中每个 df 的标签会丢失或其他什么?
    • 不,不是。你对记忆的工作方式是错误的。我会更新答案让你看到这个。
    • 哇,我没想到!这解决了我的问题!虽然我还有一个后续问题,但也要解释我的困惑来自哪里。之前,我显然成功地从“组合”中的每个数据帧中删除列,例如:对于组合中的数据集: dataset.drop(['PassengerId'],axis=1,inplace=True) 然后调用 train_df并且 test_df 确实在没有PassengerId 列的情况下显示了它们。根据我从你那里得到的信息,我不明白为什么它会起作用......
    • 我会更新来回答这个问题(如果它解决了您的问题,请接受答案以关闭问题)
    猜你喜欢
    • 1970-01-01
    • 2019-09-21
    • 2021-11-22
    • 1970-01-01
    • 1970-01-01
    • 2014-01-15
    • 2021-10-15
    • 2016-08-24
    • 2023-02-10
    相关资源
    最近更新 更多