【问题标题】:Python Pandas Column (stores set) Compare to Dictionary Set and Return NumberPython Pandas Column(存储集)与字典集比较并返回数字
【发布时间】:2017-01-06 22:51:08
【问题描述】:

在 Pandas 数据框中有超过 15 条 MM 记录的列表,并且正在尝试确定该字段中包含的唯一有效英文单词的数量。

我怎样才能加快速度?比较。我正在使用 set.intersect(..),但它需要一个多小时。代码和示例数据如下。

df.info()
sys_id      float64
grp_id      float64
set_id      float64
desc        object
unique_set  object

这些记录的唯一键是“*id”字段。 Desc 是用户定义的描述

我使用下面的代码创建了 unique_set:

df['unique_set'] = df.data_desc.apply(lambda x: detSet(x))

detSet 的定义位置:

def detSet(strDesc):
    if len(str(strDesc)) <= 1:
        # Return an empty set
        return set()
    else:
        # Remove all punctation
        strDesc = strDesc.translate(replace_punctuation).lower()
        # Remove all Non Alphabetic Characters (including Numbers)
        strDesc = re.sub(r'[^a-zA-Z ]', ' ', strDesc)
        # Remove all words less than 4 characters long
        strDesc = re.sub(r'\b\w{1,3}\b','', strDesc)
        # Remove all the extra spaces
        strDesc = ' '.join(strDesc.split())
        #
        return set(strDesc.split())

然后我读了一份来自http://invpy.com/dictionary.txt的英文字典

ENGLISH_WORDS = open('Dictionary.txt').read().splitlines()
ENGLISH_WORDS = [e.lower() for e in ENGLISH_WORDS]

df['num_english'] = df.unique_set.apply(lambda x: detNumEnglish(x)).astype(np.int16)

def detNumEnglish(setDesc):
    if len(setDesc) == 0:
        return -1
    else:
        return len(setDesc.intersection(ENGLISH_WORDS))

一些示例数据:

141   9437  13522   {jelly, beans, pudding, cake, fruitc}
787   29575 5915    {ingerbread, sugar, plum, powder, jelly}
842   22909 28065   {pudding, bear, claw, sesame, snaps, m}
484   36065 25069   {isu, cake, candy, canes, ca}
897   54587 48574   {tart, fruitcake, dessert, bisc}
123   48335 36038   {chocolate, icing, marzipan, macaroon, apple}
293   36779 12239   {ars, sugar, plum, cupcake, danish, tiramis}
115   18478 43114   {e, pudding, gummies, chocola}
183   13346 33084   {roll, caramels, candy, fruitcak}
501   94397 47227   {cake, candy, canes, cake}
473   52269 44396   {e, gummi, bears, tiramisu, cake, candy}

【问题讨论】:

  • 我开始怀疑这对代码审查是否会更好......

标签: python pandas dictionary set


【解决方案1】:

首先,您应该将ENGLISH_WORDS 创建为set 以加快交叉速度并在短词从您的其他列表中过滤时删除它们:

ENGLISH_WORDS = {e.lower() for e in ENGLISH_WORDS if len(e)>3}

然后,好像detSet方法被调用了很多,而且它做了很多字符串操作,成本很高。

让我们拿你原来的 sn-p:

def detSet(strDesc):
    ...
    else:
        # Remove all punctation
        strDesc = strDesc.translate(replace_punctuation).lower()
        # Remove all Non Alphabetic Characters (including Numbers)
        strDesc = re.sub(r'[^a-zA-Z ]', ' ', strDesc)

(那是你原来的代码 sn-p)

上面的两行基本上都是做同样的事情。您只需通过以下方式添加数字(可能还有其他字符)的翻译:

replace_punctuation.update({i:' ' for i in range(ord('0'),ord('9'))})

当您创建 replace_punctuation 表时。所以你可以放弃昂贵的正则表达式替换。

完成此操作后,您已经拥有一串以空格分隔的单词。此时你应该拆分,过滤掉小词。以及以下 3 行:

    # Remove all words less than 4 characters long
    strDesc = re.sub(r'\b\w{1,3}\b','', strDesc)
    # Remove all the extra spaces
    strDesc = ' '.join(strDesc.split())
    #
    return set(strDesc.split())

可以直接写成集合推导(1 个或多个空格:如果不带任何参数调用 split 则无关紧要),因此您无需创建临时列表(您在代码中创建了很多)

return {s for s in strDesc.split() if len(s) > 4}

这应该会快得多,因为字符串和正则表达式操作要少得多。

总而言之,这是加速例程的样子:

def detSet(strDesc):
    if len(str(strDesc)) <= 1:
        # Return an empty set
        return set()
    else:
        # Remove all punctation & replace digits by spaces (using the new replace_punctuation table)
        strDesc = strDesc.translate(replace_punctuation).lower()
        # split, filter out small words, and create set comprehension directly
        return {s for s in strDesc.split() if len(s) > 4}

除了lambda 在这里有点矫枉过正:

df.data_desc.apply(lambda x: detSet(x))

可以很简单(也稍微快一点):

df.data_desc.apply(detSet)

df.unique_set.apply(lambda x: detNumEnglish(x)) 也是如此)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-09
    • 2015-12-05
    • 1970-01-01
    • 2021-08-25
    • 1970-01-01
    相关资源
    最近更新 更多