问题描述
我正在尝试加快要在数据帧上执行的功能。我最初使用iterrows
,但是它肯定慢一些,所以我使用了apply
。它肯定有所改善,但是我想使用np.vectorize
以获得更好的性能。我的问题是如何将数据框的列传递给函数(假设列数或列名可以变化)。如何传递列然后遍历它们。我猜我可以在函数参数上使用* args,但是如何传递和破坏df的列呢?我也不想复制df(假设df非常大)。希望我的问题清楚
例如,假设我只想将数据打印成如下格式:
data = [ {"a": str(x),"b": x,"c": x} for x in range(10)]
df = pd.DataFrame(data)
def func(row):
print(f"{row.to_json()}:",end="")
_ = df.apply(func,axis=1)
这比进行迭代要快得多,但是如何进一步改进呢?在这种情况下,还应假设列数及其名称可以不同。
解决方法
通常,为了提高性能,您需要尽可能使用numpy
/ pandas
内置方法,并且只能使用apply
或numpy.vectorize
当绝对必要时。有关更多信息,请参阅this post from cs95。
例如,可以使用pandas.DataFrame.to_json
方法1:
print(df.to_json(orient="records",lines=True).replace(os.linesep,':'),end=':')
方法2:
print(':'.join(df.to_json(orient="records",lines=True).split()),end=':')
输出:
{"a":"0","b":0,"c":0}:{"a":"1","b":1,"c":1}:{"a":"2","b":2,"c":2}:{"a":"3","b":3,"c":3}:{"a":"4","b":4,"c":4}:{"a":"5","b":5,"c":5}:{"a":"6","b":6,"c":6}:{"a":"7","b":7,"c":7}:{"a":"8","b":8,"c":8}:{"a":"9","b":9,"c":9}:
性能测试代码和结果如下所示。为了进行比较,我还添加了仅打印一次的原始解决方案的变体。
import sys,os
data = [ {"a": str(x),"b": x,"c": x} for x in range(10)]
df = pd.DataFrame(data)
def func(row,file=sys.stdout):
print(f"{row.to_json()}:",end="",file=file)
def func2(row):
return row.to_json()
null_output = open(os.devnull,'w')
%timeit df.apply(func,axis=1,file=null_output)
%timeit print(':'.join(df.apply(func2,axis=1)),end=':',file=null_output)
%timeit print(':'.join(df.apply(pd.Series.to_json,file=null_output)
%timeit print(df.to_json(orient="records",file=null_output)
%timeit print(':'.join(df.to_json(orient="records",file=null_output)
输出:
1.67 ms ± 13 µs per loop (mean ± std. dev. of 7 runs,1000 loops each)
1.67 ms ± 16.5 µs per loop (mean ± std. dev. of 7 runs,1000 loops each)
1.68 ms ± 42.3 µs per loop (mean ± std. dev. of 7 runs,1000 loops each)
51.8 µs ± 1.61 µs per loop (mean ± std. dev. of 7 runs,10000 loops each)
51.4 µs ± 728 ns per loop (mean ± std. dev. of 7 runs,10000 loops each)