大多数Pythonic方法在Pandas中创建许多新列

时间:2016-02-03 15:17:13

标签: python performance pandas

我有一个大型数据帧df(约100列和~700万行),我需要创建~50个新变量/列,它们是当前变量的简单转换。一种方法是使用许多.apply语句(我只是使用transform*作为简单转换的占位符,例如max或平方):

df['new_var1'] = df['old_var1'].apply(lambda x : transform1(x))
...
df['new_var50'] = df['old_var50'].apply(lambda x : transform50(x))

另一种方法是首先创建一个字典

transform_dict = {
'new_var1' : lambda row : transform1(row),
...,
'new_var50' : lambda row : transform50(row)
}

然后写一个.apply.concat结合使用:

df = pd.concat([df, 
   df.apply(lambda r: pd.Series({var : transform_dict[var](r) for var in transform_dict.keys()}), axis=1)], axis=1)

一种方法比另一种方法更受欢迎,无论是在' Pythonic'它是,还是效率,可扩展性,灵活性?

2 个答案:

答案 0 :(得分:2)

从:

开始
df = pd.DataFrame(np.random.random((1000, 100)))

添加单个列:

def cols_via_apply(df):
    for i in range(100, 150):
        df[i] = df[i-100].apply(lambda x: x * i)
    return df  

%timeit cols_via_apply(df)

10 loops, best of 3: 29.6 ms per loop

<class 'pandas.core.frame.DataFrame'>
Int64Index: 1000 entries, 0 to 999
Columns: 150 entries, 0 to 149
dtypes: float64(150)
memory usage: 1.2 MB
None

似乎比使用pd.concat更有效率 - 可能是因为所涉及的rows的{​​{1}}上有一个循环。因此,随着DataFrame变长,这种差异会变得更糟:

DataFrame

答案 1 :(得分:2)

继续@Stefan的实验但是大小为100k x 100并且使用新方法首先分配一块NaN并将其连接到数据帧。然后,它使用iloc对每列执行计算。

def cols_via_iloc(df):
    df = pd.concat([df, pd.DataFrame(np.tile(np.nan, [len(df), 50]))], axis=1)
    for i in range(100, 150):
        df.iloc[:, i] = i * df.iloc[:, i - 100]

def cols_via_apply(df):
    for i in range(100, 150):
        df[i] = df[i-100].apply(lambda x: x * i)
    return df  

def cols_via_concat(df):
    df = pd.concat([df, df.apply(lambda row: pd.Series({i : i * row[i - 100] 
                                                        for i in range(100, 150)}), axis=1)])
    return df

>>> %%timeit df = pd.DataFrame(np.random.randn(100000, 100))
    cols_via_iloc(df)
1 loops, best of 3: 540 ms per loop

>>> %%timeit df = pd.DataFrame(np.random.randn(100000, 100))
    cols_via_apply(df)
1 loops, best of 3: 2.91 s per loop

>>> %%timeit df = pd.DataFrame(np.random.randn(100000, 100))
    cols_via_concat(df)
1 loops, best of 3: 55.8 s per loop