python - python中有没有更快的方法将字符串拆分为具有100万个元素的列表中的子列表?
问题描述
我正在尝试帮助我的朋友清理包含一百万个元素的订单列表数据框。
您可以看到 product_name 列应该是一个列表,但它们是字符串类型。所以我想把它们分成子列表。
这是我的代码:</p>
order_ls = raw_df['product_name'].tolist()
cln_order_ls = list()
for i in order_ls:
i = i.replace('[', '')
i = i.replace(']', '')
i = i.replace('\'', '')
cln_order_ls.append(i)
new_cln_order_ls = list()
for i in cln_order_ls:
new_cln_order_ls.append(i.split(', '))
但在“拆分”部分,处理需要大量时间。我想知道有没有更快的方法来处理它?</p>
谢谢~
解决方案
编辑
(我不喜欢最后一个答案,它太混乱了,所以我重新排序并更系统地测试了我)。
长话短说:
为了速度,只需使用:
def str_to_list(s):
return s[1:-1].replace('\'', '').split(', ')
df['product_name'].apply(str_to_list).to_list()
长话短说:
让我们剖析您的代码:
order_ls = raw_df['product_name'].tolist()
cln_order_ls = list()
for i in order_ls:
i = i.replace('[', '')
i = i.replace(']', '')
i = i.replace('\'', '')
cln_order_ls.append(i)
new_cln_order_ls = list()
for i in cln_order_ls:
new_cln_order_ls.append(i.split(', '))
您真正想做的是拥有一个功能,例如str_to_list()
将您的输入转换str
为list
.
由于某些原因,您需要分多个步骤执行此操作,但这实际上没有必要。到目前为止,您可以将其重写为:
def str_to_list_OP(s):
return s.replace('[', '').replace(']', '').replace('\'', '').split(', ')
如果您可以假设[
并且]
始终是字符串的第一个和最后一个字符,则可以将其简化为:
def str_to_list(s):
return s[1:-1].replace('\'', '').split(', ')
这也应该更快。
替代方法将使用正则表达式,例如:
def str_to_list_regex(s):
regex = re.compile(r'[\[\]\']')
return re.sub(regex, '', s).split(', ')
请注意,到目前为止,所有方法都使用split()
. 这是一个相当快的实现,它接近C 的速度,几乎没有任何 Python 构造可以击败它。
所有这些方法都非常不安全,因为它们没有正确考虑转义,例如,对于以下有效的 Python 代码,上述所有方法都将失败:
['ciao', "pippo", 'foo, bar']
在这种情况下,更强大的替代方案是:
ast.literal_eval
适用于任何有效的 Python 代码json.loads
这实际上需要有效的 JSON 字符串,所以这里并不是一个真正的选择。
此处比较了这些解决方案的速度:
如您所见,安全是以速度为代价的。
(这些图表是使用这些脚本生成的,具有以下内容
def gen_input(n):
return str([str(x) for x in range(n)])
def equal_output(a, b):
return a == b
input_sizes = (5, 10, 50, 100, 500, 1000, 5000, 10000, 50000, 100000, 500000)
funcs = str_to_list_OP, str_to_list, str_to_list_regex, ast.literal_eval
runtimes, input_sizes, labels, results = benchmark(
funcs, gen_input=gen_input, equal_output=equal_output,
input_sizes=input_sizes)
现在让我们专注于循环。您所做的是显式循环,我们知道 Python 通常不会非常快。但是,在推导中循环可以更快,因为它可以生成更优化的代码。另一种方法是使用使用 Pandas 原语的矢量化表达式,使用apply()
或使用.str.
链接。
获得了以下时间,表明对于较小的输入,理解是最快的,尽管矢量化解决方案(使用apply
)赶上并最终超过了理解:
使用了以下测试函数:
import pandas as pd
def str_to_list(s):
return s[1:-1].replace('\'', '').split(', ')
def func_OP(df):
order_ls = df['product_name'].tolist()
cln_order_ls = list()
for i in order_ls:
i = i.replace('[', '')
i = i.replace(']', '')
i = i.replace('\'', '')
cln_order_ls.append(i)
new_cln_order_ls = list()
for i in cln_order_ls:
new_cln_order_ls.append(i.split(', '))
return new_cln_order_ls
def func_QuangHoang(df):
return df['product_name'].str[1:-1].str.replace('\'','').str.split(', ').to_list()
def func_apply_df(df):
return df['product_name'].apply(str_to_list).to_list()
def func_compr(df):
return [str_to_list(s) for s in df['product_name']]
使用以下测试代码:
def gen_input(n):
return pd.DataFrame(
columns=('order_id', 'product_name'),
data=[[i, "['ciao', 'pippo', 'foo', 'bar', 'baz']"] for i in range(n)])
def equal_output(a, b):
return a == b
input_sizes = (5, 10, 50, 100, 500, 1000, 5000, 10000, 50000, 100000, 500000)
funcs = func_OP, func_QuangHoang, func_apply_df, func_compr
runtimes, input_sizes, labels, results = benchmark(
funcs, gen_input=gen_input, equal_output=equal_output,
input_sizes=input_sizes)
再次使用与以前相同的基本脚本。
推荐阅读
- javascript - 带有大精灵的 CSS 精灵动画在开始时冻结
- android - 遍历 RxJava2 中的 Observable 列表
- regex - 用ansible从变量中解析子字符串
- javafx - 是否可以在 Gluon Mobile 上安装 Spring Boot?
- .net - StateMachineAttribute 在 .NET 中的用途是什么?
- c - 如何相互转换异或和非运算符
- angular - '+' 字符在 HttpParams angular 中转换为空格
- python - 如何使用基于python列中先前值的函数创建列
- reactjs - 在任何请求和响应之后,调用一个 api
- kubernetes - 自定义 cloudwatch 指标 EKS CloudWatch 代理