乐趣区

关于人工智能:Pandas字符串操作的各种方法速度测试

因为 LLM 的倒退,很多的数据集都是以 DF 的模式公布的,所以通过 Pandas 操作字符串的要求变得越来越高了,所以本文将对字符串操作方法进行基准测试,看看它们是如何影响 pandas 的性能的。因为一旦 Pandas 在解决数据时超过肯定限度,它们的行为就会很奇怪。

咱们用 Faker 创立了一个 100,000 行的测试数据。

测试方法

装置:

 !pip install faker

生成测试数据的办法很简答:

 import pandas as pd
 import numpy as np
 
 def gen_data(x):
   from faker import Faker
   fake = Faker()
   outdata = {}
   for i in range(0,x):
     outdata[i] = fake.profile()
   return pd.DataFrame(outdata).T
 
 n= 100000
 basedata = gen_data(n)

而后把 Google Colab 将输入存储在 Google drive 中

 from google.colab import drive
 drive.mount('/content/drive')

创立了非常简单的函数来测试连贯两个字符串的各种办法。

 def process(a,b):
   return ''.join([a,b])
 
 def process(a,b):
   return a+b
 
 def process(a,b):
   return f"{a}{b}"
 
 def process(a,b):
   return f"{a}{b}"*100

创立一个空 DF,编写一个函数将输入 %%timeit 作为一行增加到数据框中

 # add a row to the dataframe using %%timeit output
 def add_to_df(n, m, x, outputdf):
   outputdf.loc[len(outputdf.index)] = [m, n, x]
 
 # output frame
 outputdf = pd.DataFrame(columns=['method', 'n', 'timing'])
 outputdf

而后就是运行下面的每个函数并将数据导出到 pandas 的代码。

 # get a sample of data
 n = 10000
 suffix = 'fstring_100x'
 data = basedata.copy().sample(n).reset_index()

记录运行工夫

 %%timeit -r 7 -n 1 -o
 data['newcol'] = ''
 for row in range(len(data)):
   data.at[row ,'newcol'] = process(data.at[row, 'job'], data.at[row, 'company'])
 
 # 451 ms ± 34 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
 # <TimeitResult : 451 ms ± 34 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)>

残缺的函数调用

 m = "Iterating over the rows"
 add_to_df(n = n, m = m, x = vars(_), outputdf = outputdf)

试验

下面是代码,上面开始用下面的代码进行试验:

Iterrows (pandas 原生函数) 每行相加

 %%timeit -r 7 -n 1 -o
 data['newcol'] = ''
 for row, item in data.iterrows():
   data.at[row ,'newcol'] = process(item['job'], item['company'])

Itertuples(因为不可变而更平安) 每行相加

 %%timeit -r 7 -n 1 -o
 data['newcol'] = ''for row, job, company in data[['job','company']].itertuples():
   data.at[row ,'newcol'] = process(job, company)

应用 pandas 原生函数作为字符串相加

 %%timeit -r 7 -n 1 -o
 data['newcol'] = data.job + data.company

应用原生函数 pandas. series .add

 %%timeit -r 7 -n 1 -o
 data['newcol'] = data.job.add(data.company)

应用 dataframe.apply

 %%timeit -r 7 -n 1 -o
 data['newcol'] = data.apply(lambda row: process(row['job'],row['company']), axis=1)

应用 List Map

 %%timeit -r 7 -n 1 -o
 data['newcol'] = list(map(process, data.job, data.company))

Pandas 矢量化

 %%timeit -r 7 -n 1 -o
 data['newcol'] = process(data.job, data.company)

numpy 数组矢量化

 %%timeit -r 7 -n 1 -o
 data['newcol'] = process(data.job.to_numpy(), data.company.to_numpy())

显式在 numpy 数组上应用 numpy 向量化

 %%timeit -r 7 -n 1 -o
 data['newcol'] = np.vectorize(process)(data.job.to_numpy(), data.company.to_numpy())

优化后的列表推导式

 %%timeit -r 7 -n 1 -o
 data['newcol'] = ''data['newcol'] =[process(i,j) for i,j in list(zip(data.job, data.company)) ]

最初是后果的输入:

 outputdf.to_csv(f"./drive/MyDrive/{n}_{suffix}.csv")

后果

后果如下所示。我用了下面 3 种不同函数测试了后果。

原生的字符串加法 C = a+b

从 1000 行扩大到 100,000 行所需的工夫;

可视化比照:

所有矢量化办法都十分快,而且 pandas 规范的 str.add 对 numpy 数组也进行了矢量化。可能看到 Pandas 的原生办法个别都是线性的。List-map 仿佛以 N 的平方根的速度增长

应用 fstring: c = f ” {a}{b} “

应用 fstring,后果很乏味,有的后果无法解释。

工夫

可视化

从工夫上看,长度超过 10,000 的 DF 时,向量化是正确执行的

下图是第三个函数,就是 *100,这更能阐明问题,向量化操作的基本上工夫没有变动

总结

通过下面的测试,咱们能够总结一下后果:

1、还是陈词滥调的问题,不要应用 iterrows(),itertuples(),尽量不要应用 DataFrame.apply(),因为几个函数还是循环遍历的。

2、矢量化操作在字符串操作中也是能够应用的,然而为了平安起见,应用 Numpy 数组。

3、列表推导式就像它的名字一样,它还是一个 list

4、还有一些奇怪的无法解释的问题,然而大部分的状况都是能够解释的

如果你有更好的了解,欢送留言

https://avoid.overfit.cn/post/2633908f89b14e0bb14bcaab443c3fec

作者:Dr. Mandar Karhade

退出移动版