如何使用 for 循环对一组数据帧进行 运行 操作?
How can I run operations on a set of dataframes with a for loop?
这是我遇到的一个普遍问题,但我将以泰坦尼克号数据集为例。为了同时对训练集和测试集进行操作,我将它们合并:
combined = [train_df, test_df]
我还简化了每位乘客的标题,所以现在每个都是 8 种可能性之一。对于 train_df 和 test_df,我现在想为 'Title' 列制作虚拟对象,将它们添加到数据框中,然后删除原始的 'Title' 列。我提出的代码是:
for df in combined:
df = pd.concat([df,pd.get_dummies(df.Title)],axis=1)
df = df.drop('Title',axis=1)
当我在单个数据帧上手动执行这些操作时,这些操作确实有效,但是当 运行 for 循环时,什么也没有发生。我错过了什么?
这是行不通的,因为您正在修改列表中变量的副本,并且永远不会将其重新分配到列表中。
例如:
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,4
和 l = [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
就是这样做的。它直接修改数据框,而不是创建它的副本。
这是我遇到的一个普遍问题,但我将以泰坦尼克号数据集为例。为了同时对训练集和测试集进行操作,我将它们合并:
combined = [train_df, test_df]
我还简化了每位乘客的标题,所以现在每个都是 8 种可能性之一。对于 train_df 和 test_df,我现在想为 'Title' 列制作虚拟对象,将它们添加到数据框中,然后删除原始的 'Title' 列。我提出的代码是:
for df in combined:
df = pd.concat([df,pd.get_dummies(df.Title)],axis=1)
df = df.drop('Title',axis=1)
当我在单个数据帧上手动执行这些操作时,这些操作确实有效,但是当 运行 for 循环时,什么也没有发生。我错过了什么?
这是行不通的,因为您正在修改列表中变量的副本,并且永远不会将其重新分配到列表中。
例如:
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,4
和 l = [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
就是这样做的。它直接修改数据框,而不是创建它的副本。