我有一个包含很多行的数据框。我使用自定义函数生成的数据附加一列,如下所示:
import numpy
df['new_column'] = numpy.vectorize(fx)(df['col_a'], df['col_b'])
# takes 180964.377 ms
工作正常,我想要做的就是加快速度。实际上只有一小组col_a
和col_b
的独特组合。许多迭代都是多余的。我想也许pandas
可能会自己解决这个问题,但我不认为是这种情况。考虑一下:
print len(df.index) #prints 127255
df_unique = df.copy().drop_duplicates(['col_a', 'col_b'])
print len(df_unique.index) #prints 9834
我也确信通过运行这个可能的加速:
df_unique['new_column'] = numpy.vectorize(fx)(df_unique['col_a'], df_unique['col_b'])
# takes 14611.357 ms
由于存在大量冗余数据,我要做的是更新大型数据帧(df
127255行),但只需要运行fx
函数最少次数( 9834次)。这是因为col_a
和col_b
的所有重复行。当然,这意味着df
中有多个行具有col_a
和col_b
的相同值,但是没关系,df
的其他列不同并使每一行都是唯一的。
在我创建一个正常的迭代循环以循环遍历df_unique
数据帧并在df
上进行条件更新之前,我想问一下是否有更多“pythonic”整齐的方法来做这个有点更新。非常感谢。
**更新**
我创建了上面提到的简单for循环,如下所示:
df = ...
df_unique = df.copy().drop_duplicates(['col_a', 'col_b'])
df_unique['new_column'] = np.vectorize(fx)(df_unique['col_a'], df_unique['col_b'])
for index, row in df_unique.iterrows():
df.loc[(df['col_a'] == row['col_a']) & (df['col_b'] == row['col_b']),'new_column'] = row['new_column']
# takes 165971.890
因此,使用此for循环可能会略微提升性能但不会达到我预期的水平。
FYI
这是fx
函数。它查询mysql数据库。
def fx(d):
exp_date = datetime.strptime(d.col_a, '%m/%d/%Y')
if exp_date.weekday() == 5:
exp_date -= timedelta(days=1)
p = pandas.read_sql("select stat from table where a = '%s' and b_date = '%s';" % (d.col_a,exp_date.strftime('%Y-%m-%d')),engine)
if len(p.index) == 0:
return None
else:
return p.iloc[0].close
答案 0 :(得分:1)
<强>更新强>
如果您可以设法将属于['stat','a','b_date']
表的三列table
读入tab
DF,那么您可以将其合并为:
tab = pd.read_sql('select stat,a,b_date from table', engine)
df.merge(tab, left_on=[...], right_on=[...], how='left')
OLD回答:
您可以将预先计算的df_unique
DF与原始df
DF合并/加入:
df['new_column'] = df.merge(df_unique, on=['col_a','col_b'], how='left')['new_column']
答案 1 :(得分:1)
MaxU的回答可能已经是你想要的了。但我会展示另一种方法可能会更快(我没有测量)。
我认为:
df[['col_a', 'col_b']]
已排序,以便所有相同的条目都在连续的行中(这很重要)
df
有一个唯一索引(如果没有,您可以创建一些临时唯一索引)。
我会使用df_unique.index
是df.index
的子集这一事实。
# (keep='first' is actually default)
df_unique = df[['col_a', 'col_b']].drop_duplicates(keep='first').copy()
# You may try .apply instead of np.vectorize (I think it may be faster):
df_unique['result'] = df_unique.apply(fx, axis=1)
# Main part:
df['result'] = df_unique['result'] # uses 2.
df['result'].fillna(method='ffill', inplace=True) # uses 1.