如何在python中优化正则表达式搜索? ################################################################ # #用于/r/wallstreetbets中评论的Reddit情绪脚本 #从数据库加载注释,使用单词列表扫描注释, #创建情绪分数并将结果写入数据库 # ################################################################ 导入sqlite3 进口稀土 从日期时间导入日期时间 #从文本文件数据库加载关键字搜索词 def从文件(ftext文件)读取单词: 加载单词=() f=打开(ftext_文件'r') #对于f中的项目: #加载单词.append(item.lower().strip()) load_words=tuple([x.lower().strip(),表示f中的x]) 返回(加载单词) #根据评论搜索关键词 #给出+/-表示积极或消极情绪词 定义单词搜索(数据库列表、FPO列表、fneg列表): 位置计数=0 负计数=0 fdb_结果_列表=[] 扫描的总行数=0 打印(“开始单词搜索…”) #循环的第一个是注释数据 #第二个循环是关键词 有关db_列表中的注释: 总扫描行数=总扫描行数+1 对于fpos清单中的pos项目: word\u search=re.findall(r“\b”+位置项+r“\b”,注释[0]) pos\u count=pos\u count+len(单词搜索) 对于fneg_表中的neg_项: word\u search=re.findall(r“\b”+neg\u item+r“\b”,注释[0]) 负计数=负计数+长(单词搜索) #根据评论中的频率确定pos/neg情绪得分 如果pos_计数>neg_计数: 正计数=正计数/(正计数+负计数) 负计数=0 elif正计数0或负计数>0: fdb_结果列表。追加([pos_计数、neg_计数、注释[1])) 如果扫描的总行数为%100000==0: 打印(“到目前为止统计的行:,扫描的行总数”) 位置计数=0 负计数=0 打印(“单词搜索完成”) 返回(fdb_结果_列表) #将结果写入新数据库。删除奇数db。 #pos=项目[0],neg=项目[1],时间戳=项目[2] def写入数据库结果(写入数据库列表): 打印(“将结果写入数据库…”) conn=sqlite3.connect('testdb.sqlite',超时=30) cur=连接光标() cur.executescript(“”)如果存在,则删除表redditresultstable ''') 当前执行脚本(“”) 创建表redditresultstable( id整数不为NULL主键唯一, pos_count整数, 负计数整数, 时间戳文本 ); ''') 对于写入数据库列表中的项目: 当前执行(''插入redditresultstable(正计数、负计数、时间戳) 数值(?,,?),(第[0]项、第[1]项、第[2]项) 康涅狄格州提交 康涅狄格州关闭 打印(“将结果写入数据库完成”) #从db加载注释项[2]和时间戳项[4] def load_db_comments(): 打印(“正在加载数据库…”) conn=sqlite3.connect('redditusertrack.sqlite')) cur=连接光标() cur.execute('SELECT*FROM redditcomments') row_db=cur.fetchall() 康涅狄格州关闭 打印(“加载完成”) db_列表=() db_list=tuple([(第[2]行中的项为lower(),第[4]行]) 返回db_列表 #主程序从这里开始 打印(datetime.now()) db_list=加载db_注释() pos\u words\u list=从文件(“simple\u positive\u words.txt”)中读取单词 neg_words_list=从_文件(“simple_negative_words.txt”)读取_words_ db_结果_列表=单词搜索(db_列表、pos_单词列表、neg_单词列表) db_results_list=元组(db_results_list) 写入数据库结果(数据库结果列表) 打印(datetime.now())

如何在python中优化正则表达式搜索? ################################################################ # #用于/r/wallstreetbets中评论的Reddit情绪脚本 #从数据库加载注释,使用单词列表扫描注释, #创建情绪分数并将结果写入数据库 # ################################################################ 导入sqlite3 进口稀土 从日期时间导入日期时间 #从文本文件数据库加载关键字搜索词 def从文件(ftext文件)读取单词: 加载单词=() f=打开(ftext_文件'r') #对于f中的项目: #加载单词.append(item.lower().strip()) load_words=tuple([x.lower().strip(),表示f中的x]) 返回(加载单词) #根据评论搜索关键词 #给出+/-表示积极或消极情绪词 定义单词搜索(数据库列表、FPO列表、fneg列表): 位置计数=0 负计数=0 fdb_结果_列表=[] 扫描的总行数=0 打印(“开始单词搜索…”) #循环的第一个是注释数据 #第二个循环是关键词 有关db_列表中的注释: 总扫描行数=总扫描行数+1 对于fpos清单中的pos项目: word\u search=re.findall(r“\b”+位置项+r“\b”,注释[0]) pos\u count=pos\u count+len(单词搜索) 对于fneg_表中的neg_项: word\u search=re.findall(r“\b”+neg\u item+r“\b”,注释[0]) 负计数=负计数+长(单词搜索) #根据评论中的频率确定pos/neg情绪得分 如果pos_计数>neg_计数: 正计数=正计数/(正计数+负计数) 负计数=0 elif正计数0或负计数>0: fdb_结果列表。追加([pos_计数、neg_计数、注释[1])) 如果扫描的总行数为%100000==0: 打印(“到目前为止统计的行:,扫描的行总数”) 位置计数=0 负计数=0 打印(“单词搜索完成”) 返回(fdb_结果_列表) #将结果写入新数据库。删除奇数db。 #pos=项目[0],neg=项目[1],时间戳=项目[2] def写入数据库结果(写入数据库列表): 打印(“将结果写入数据库…”) conn=sqlite3.connect('testdb.sqlite',超时=30) cur=连接光标() cur.executescript(“”)如果存在,则删除表redditresultstable ''') 当前执行脚本(“”) 创建表redditresultstable( id整数不为NULL主键唯一, pos_count整数, 负计数整数, 时间戳文本 ); ''') 对于写入数据库列表中的项目: 当前执行(''插入redditresultstable(正计数、负计数、时间戳) 数值(?,,?),(第[0]项、第[1]项、第[2]项) 康涅狄格州提交 康涅狄格州关闭 打印(“将结果写入数据库完成”) #从db加载注释项[2]和时间戳项[4] def load_db_comments(): 打印(“正在加载数据库…”) conn=sqlite3.connect('redditusertrack.sqlite')) cur=连接光标() cur.execute('SELECT*FROM redditcomments') row_db=cur.fetchall() 康涅狄格州关闭 打印(“加载完成”) db_列表=() db_list=tuple([(第[2]行中的项为lower(),第[4]行]) 返回db_列表 #主程序从这里开始 打印(datetime.now()) db_list=加载db_注释() pos\u words\u list=从文件(“simple\u positive\u words.txt”)中读取单词 neg_words_list=从_文件(“simple_negative_words.txt”)读取_words_ db_结果_列表=单词搜索(db_列表、pos_单词列表、neg_单词列表) db_results_list=元组(db_results_list) 写入数据库结果(数据库结果列表) 打印(datetime.now()),python,regex,performance,Python,Regex,Performance,这个脚本从SQLite将130万条评论加载到内存中,然后针对每条评论扫描147个关键词,然后计算情感分数1.91亿次迭代 执行时间为5分32秒 我将大多数变量更改为元组(来自列表),并使用列表理解而不是循环(用于附加)。与仅使用列表和For循环进行追加时的脚本相比,此脚本的执行效率提高了约5%。5%可能是误差范围,因为我的测量方法可能不准确 Stackoverflow和其他资源似乎表明,对于这种类型的迭代,使用元组更快,尽管一些海报提供的证据表明,在某些情况下,列表更快 此代码是否针对元组和列表

这个脚本从SQLite将130万条评论加载到内存中,然后针对每条评论扫描147个关键词,然后计算情感分数1.91亿次迭代

执行时间为5分32秒

我将大多数变量更改为元组(来自列表),并使用列表理解而不是循环(用于附加)。与仅使用列表和For循环进行追加时的脚本相比,此脚本的执行效率提高了约5%。5%可能是误差范围,因为我的测量方法可能不准确

Stackoverflow和其他资源似乎表明,对于这种类型的迭代,使用元组更快,尽管一些海报提供的证据表明,在某些情况下,列表更快

此代码是否针对元组和列表理解进行了正确优化

编辑:谢谢大家的建议/评论。有很多工作要做。我实现了YuriyP的建议,运行时间从5分钟增加到了26秒。问题在于regex For循环搜索函数

已更新附加图像中的代码。我删除了红色的划线代码,并用绿色进行了更新


您应该首先使用cProfile来分析代码,以便更好地进行度量。是的,元组比列表快一点点,因为列表需要2块内存,元组需要1块内存。而且,列表理解也稍微快一点,但前提是循环中有非常简单的表达式

################################################################
#
# Reddit sentiment script for comments in /r/wallstreetbets
# Loads comments from db, scans comments using word list,
# creates sentiment score and writes results to database
#
################################################################

import sqlite3
import re
from datetime import datetime


# Load key search words from text file db
def read_words_from_file(ftext_file):
    load_words = ()
    f = open(ftext_file, 'r')
    # for item in f:
    #    load_words.append(item.lower().strip())
    load_words = tuple([x.lower().strip() for x in f])
    return(load_words)


# Search key words against comments
# Gives +/- for positive or negative sentiment words
def word_search(db_list, fpos_flist, fneg_flist):
    pos_count = 0
    neg_count = 0
    fdb_results_list = []
    total_lines_scanned = 0
    print("Starting word search...")

    # 1st for loop is comment data
    # 2nd for loop is key words
    for comment in db_list:
        total_lines_scanned = total_lines_scanned + 1
        for pos_item in fpos_flist:
            word_search = re.findall(r"\b" + pos_item + r"\b", comment[0])
            pos_count = pos_count + len(word_search)

        for neg_item in fneg_flist:
            word_search = re.findall(r"\b" + neg_item + r"\b", comment[0])
            neg_count = neg_count + len(word_search)

        # Determine pos/neg sentiment score based on frequency in comment
        if pos_count > neg_count:
            pos_count = pos_count / (pos_count+neg_count)
            neg_count = 0
        elif pos_count < neg_count:
            neg_count = neg_count / (pos_count+neg_count)
            pos_count = 0
        elif pos_count == neg_count:
            pos_count = 0
            neg_count = 0

        if pos_count > 0 or neg_count > 0:
            fdb_results_list.append([pos_count, neg_count, comment[1]])
        if total_lines_scanned % 100000 == 0:
            print("Lines counted so far:", total_lines_scanned)
        pos_count = 0
        neg_count = 0

    print("Word search complete.")
    return(fdb_results_list)


# Write results to new DB. Deletes odd db.
# pos = item[0], neg = item[1], timestamp = item[2]
def write_db_results(write_db_list):
    print("Writing results to database...")
    conn = sqlite3.connect('testdb.sqlite', timeout=30)
    cur = conn.cursor()

    cur.executescript('''DROP TABLE IF EXISTS redditresultstable
    ''')

    cur.executescript('''
    CREATE TABLE redditresultstable (
        id INTEGER NOT NULL PRIMARY KEY UNIQUE,
        pos_count INTEGER,
        neg_count INTEGER,
        timestamp TEXT
    );
    ''')
    for item in write_db_list:
        cur.execute('''INSERT INTO redditresultstable (pos_count, neg_count, timestamp)
                    VALUES (?, ?, ?)''', (item[0], item[1], item[2]))

    conn.commit()
    conn.close()
    print("Writing results to database complete.")


# Load comments item[2] and timestamp item[4] from db
def load_db_comments():
    print("Loading database...")
    conn = sqlite3.connect('redditusertrack.sqlite')
    cur = conn.cursor()
    cur.execute('SELECT * FROM redditcomments')
    row_db = cur.fetchall()
    conn.close()
    print("Loading complete.")
    db_list = ()

    db_list = tuple([(item[2].lower(), item[4]) for item in row_db])
    return db_list


# Main Program Starts Here
print(datetime.now())

db_list = load_db_comments()

pos_word_list = read_words_from_file("simple_positive_words.txt")
neg_word_list = read_words_from_file("simple_negative_words.txt")

db_results_list = word_search(db_list, pos_word_list, neg_word_list)
db_results_list = tuple(db_results_list)

write_db_results(db_results_list)

print(datetime.now())
在代码中可以做两件事,比如使用枚举器for代替裸for循环,并用简单的生成器替换理解

我认为,为这样简单的逻辑分析代码并试图使其更快,可能不会带来任何好处。另外,不要使用
datetime
而是使用类似于配置文件装饰器的东西,它将锁定到函数中,并为您提供调用报告

tuple((item[2].lower(), item[4]) for item in row_db) -> you don't need list comprehensions here.

祝你好运

使用正则表达式从commaent获取正反两个单词的总数,而不是对每个正反两个单词进行O(N+M)请求,而是使用O(1)

例子:

pos\u word\u list=从\u文件中读取\u words\u(“简单的\u肯定的\u wo
tuple((item[2].lower(), item[4]) for item in row_db) -> you don't need list comprehensions here.


import cProfile, pstats, io



def profile(fnc):
    
    """A decorator that uses cProfile to profile a function"""
    
    def inner(*args, **kwargs):
        
        pr = cProfile.Profile()
        pr.enable()
        retval = fnc(*args, **kwargs)
        pr.disable()
        s = io.StringIO()
        sortby = 'cumulative'
        ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
        ps.print_stats()
        print(s.getvalue())
        return retval

    return inner