python - 提高类数据框结构的性能
问题描述
我在我的代码代码中面临一个数据结构挑战,我需要计算正负示例中字符串的频率。这是一个很大的瓶颈,我似乎无法找到更好的解决方案。
我必须遍历数据集中的每个长字符串,并提取子字符串,我需要计算其中的频率。在一个完美的世界中,以下形状的 pandas 数据框将是完美的:
最后,预期的结构类似于
string | frequency positive | frequency negative
________________________________________________
str1 | 5 | 7
str2 | 2 | 4
...
但是,对于明显的性能限制,这是不可接受的。我的解决方案是使用字典来跟踪行,并使用Nx2
numpy 矩阵来跟踪频率。这样做也是因为在此之后,无论如何我都需要在一个Nx2
numpy 矩阵中使用频率。
目前,我的解决方案是这样的:
str_freq = np.zeros((N, 2), dtype=np.uint32)
str_dict = {}
str_dict_counter = 0
for i, string in enumerate(dataset):
substrings = extract(string) # substrings is a List[str]
for substring in substrings:
row = str_dict.get(substring, None)
if row is None:
str_dict[substring] = str_dict_counter
row = str_dict_counter
str_dict_counter += 1
str_freq[row, target[i]] += 1 # target[i] is equal to 1 or 0
但是,这确实是我的代码的瓶颈,我想加快它的速度。
该代码的某些内容是不可压缩的,例如 , extract(string)
,因此必须保留该循环。但是,如果可能的话,使用并行处理没有问题。
我特别想知道的是是否有办法改善内循环。众所周知,Python 循环不好,这似乎有点毫无意义,但是由于我们不能(据我所知)像使用 numpy 数组那样对字典进行多次获取和设置,我不知道我该怎么做改进它。
你建议做什么?用一些较低级别的语言重写是唯一的解决方案吗?
我也想使用 SQL-lite,但我不知道它是否值得。记录一下,这需要大约 10MB 的数据,目前大约需要 45 秒,但每次都需要用新数据重复完成。
编辑:添加了测试自己的示例
import random
import string
import re
import numpy as np
import pandas as pd
def get_random_alphaNumeric_string(stringLength=8):
return bytes(bytearray(np.random.randint(0,256,stringLength,dtype=np.uint8)))
def generate_dataset(n=10000):
d = []
for i in range(n):
rnd_text = get_random_alphaNumeric_string(stringLength=1000)
d.append(rnd_text)
return d
def test_dict(dataset):
pattern = re.compile(b"(q.{3})")
target = np.random.randint(0,2,len(dataset))
str_freq = np.zeros((len(dataset)*len(dataset[0]), 2), dtype=np.uint32)
str_dict = {}
str_dict_counter = 0
for i, string in enumerate(dataset):
substrings = pattern.findall(string) # substrings is a List[str]
for substring in substrings:
row = str_dict.get(substring, None)
if row is None:
str_dict[substring] = str_dict_counter
row = str_dict_counter
str_dict_counter += 1
str_freq[row, target[i]] += 1 # target[i] is equal to 1 or 0
return str_dict, str_freq[:str_dict_counter,:]
def test_df(dataset):
pattern = re.compile(b"(q.{3})")
target = np.random.randint(0,2,len(dataset))
df = pd.DataFrame(columns=["str","pos","neg"])
df.astype(dtype={"str":bytes, "pos":int, "neg":int}, copy=False)
df = df.set_index("str")
for i, string in enumerate(dataset):
substrings = pattern.findall(string) # substrings is a List[str]
for substring in substrings:
check = substring in df.index
if not check:
row = [0,0]
row[target[i]] = 1
df.loc[substring] = row
else:
df.loc[substring][target[i]] += 1
return df
dataset = generate_dataset(1000000)
d,f = test_dict(dataset) # takes ~10 seconds on my laptop
# to get the value of some key, say b'q123'
f[d[b'q123'],:]
d = test_df(dataset) # takes several minutes (hasn't finished yet)
# the same but with a dataframe
d.loc[b'q123']
解决方案
推荐阅读
- html - 在角度如何以一种方式修剪值数据绑定
- oracle - Oracle RAC RMAN 备份未写入 NFS 共享
- java - 尝试比较日期时发生异常 - 即使我设置了日期,Nullpointerexception 和 get 方法也返回空值
- reactjs - 如何使用具有 DD/MMM/YYYY 格式或自定义输入字段的材料 UI 选择器 KeyboardDatePicker
- python - 我们如何防止 FASTAPI 中的 html 注入?
- python - 使用任何需要互联网的东西时 Kivy 应用程序崩溃
- apache-flink - 在 Flink SQL 中加入连续查询
- python - 消除 DSBSC 信号中的直流偏移
- c# - 为什么 .NET“de-CH”区域性数字组分隔符在本地和 Azure 上不同?
- azure-devops-server-2019 - 谁更改了部署标签