我一直在寻找应用函数的最佳方法,该函数采用多个单独的Pandas DataFrame列并在相同的所说DataFrame中输出多个新列。假设我有以下内容:
def apply_func_to_df(df):
df[['new_A', 'new_B']] = df.apply(lambda x: transform_func(x['A'], x['B'], x['C']), axis=1)
def transform_func(value_A, value_B, value_C):
# do some processing and transformation and stuff
return new_value_A, new_value_B
我正在尝试将上述功能应用于整个DataFrame df
,以便输出2个NEW列。但是,这可以推广到一个用例/函数,该用例/函数接受n
个DataFrame列,并将m
个新列输出到同一DataFrame。
以下是我一直在关注的事情(取得不同程度的成功):
transform_func
,以明确期望行(即字段)A
,B
,C
,如下所示,然后将其应用于df: def transform_func_mod(df_row):
# do something with df_row['A'], df_row['B'], df_row['C]
return new_value_A, new_value_B
我希望以一种非常通用的Python方式来完成此任务,同时兼顾性能(包括内存和时间)。我对此表示感谢,因为由于对熊猫不熟悉,我一直在为此苦苦挣扎。
答案 0 :(得分:3)
通过以下方式编写 transform_func :
示例:假设所有3列均为 string 类型,并置 A 和 B 列,请在 C :
def transform_func(row):
a = row.A; b = row.B; c = row.C;
return pd.Series([ a + b, c + '_xx'], index=['new_A', 'new_B'])
要仅仅获取新值,请将此功能应用于每一行:
df.apply(transform_func, axis=1)
请注意,生成的DataFrame保留原始行的键 (我们稍后会使用此功能)。
或者,如果您想添加这些新列到您的DataFrame中,请加入您的 df 使用上述应用程序的结果,将连接结果保存在 原始的 df :
df = df.join(df.apply(transform_func, axis=1))
使用 zip 可能是最慢的选择。 基于行的功能应该更快,并且结构更直观。 最快的方法可能是为每个列分别编写2个向量化表达式。在这种情况下,类似:
df['new_A'] = df.A + df.B
df['new_B'] = df.C + '_xx'
但是通常问题是是否基于行的函数 可以表示为矢量化表达式(如上所述)。 在“负”情况下,您可以应用基于行的函数。
要比较每个解决方案的速度,请使用%timeit 。
答案 1 :(得分:1)
该问题似乎与this question有关。我参考了@ spen.smith在this answer上提出的评论。
df = pd.DataFrame([[1,2,3], [2,3,4], [3,5,7]], columns = ['A', 'B', 'C'])
print(df)
A B C
0 1 2 3
1 2 3 4
2 3 5 7
不像修改函数的返回那样,只需照常创建
def add_subtract(args):
arg1, arg2 = args
ret1 = arg1 + arg2
ret2 = arg1 - arg2
return ret1, ret2
检查使用apply
的输出。选项result_type='expand'
以数据框而不是一系列元组的形式返回结果。
print(df[['B', 'C']].apply(add_subtract, axis=1, result_type='expand'))
0 1
0 5 -1
1 7 -1
2 12 -2
然后我们可以通过转置然后访问值来将apply
输出的列分配给两个新系列。必须进行转置,因为调用values
的默认行为会将每一行都视为一个列表,而我们希望将每一列都视为一个列表。所以最终的表达式是:
df['D'], df['E'] = df[['B', 'C']].apply(add_subtract, axis=1, result_type='expand').transpose().values
print(df)
A B C D E
0 1 2 3 5 -1
1 2 3 4 7 -1
2 3 5 7 12 -2