繁体   English   中英

有效地用令牌替换字符串列表中的数字

[英]Efficiently replace numbers in list of strings with a token

我有一些字符串是整数的字符串列表。 我想找到一种方法,可以根据数字的长度用令牌快速替换超过100的数字。

['foo', 'bar', '3333'] -> ['foo', 'bar', '99994']

我将在长度约100的列表上执行此操作数百万次。我想出的纯python方法如下:

def quash_large_numbers(tokens, threshold=100):
    def is_int(s):
        try:
            int(s)
            return True
        except ValueError:
            return False

    BIG_NUMBER_TOKEN = '9999%d'
    tokens_no_high_nums = [BIG_NUMBER_TOKEN % len(t) if is_int(t) and int(t) > threshold else t
                           for t in tokens]
    return tokens_no_high_nums

我试图查看是否可以通过pandas更快地完成此操作,但是对于小列表,它要慢得多,我想从从序列到列表的来回转换的所有开销中可以想象得到。

def pd_quash_large_numbers(tokens, threshold=100):
    BIG_NUMBER_TOKEN = 9999
    tokens_ser = pd.Series(tokens)
    int_tokens = pd.to_numeric(tokens_ser, errors='coerce')
    tokens_over_threshold = int_tokens > threshold
    str_lengths = tokens_ser[tokens_over_threshold].str.len().astype(str)

    tokens_ser[tokens_over_threshold] = BIG_NUMBER_TOKEN + str_lengths

    return tokens_ser.tolist()

我在这里缺少更有效的方法吗? 可能是通过cython吗?

新的更快的答案

v = np.array(['foo', 'bar', '3333'])
r = np.arange(v.size)
m = np.core.defchararray.isdigit(v)
g = v[m].astype(int) > 100
i = r[m][g]
t = np.array(['9999{}'.format(len(x)) for x in v[i].tolist()])
v = v.astype(t.dtype)
v[i] = t
v.tolist()

['foo', 'bar', '99994']

旧答案

s = pd.Series(['foo', 'bar', '3333'])
s.loc[pd.to_numeric(s, 'coerce') > 100] = s.str.len().map('9999{}'.format)

s

0      foo
1      bar
2    99994
dtype: object

要么

s.tolist()

['foo', 'bar', '99994']

通过计数文本位数而不进行任何转换,我得到了很好的加速。 该测试程序将其降低了近80%。 它运行原始代码,我的文本检查代码和piRSquared的numpy代码。 让最好的代码获胜!

import time

# a thousand 100 item long lists to test
test_data = [['foo', 'bar', '3333'] * 33 for _ in range(1000)]

def quash_large_numbers(tokens, threshold=100):
    def is_int(s):
        try:
            int(s)
            return True
        except ValueError:
            return False

    BIG_NUMBER_TOKEN = '9999%d'
    tokens_no_high_nums = [BIG_NUMBER_TOKEN % len(t) if is_int(t) and int(t) > threshold else t
                           for t in tokens]
    return tokens_no_high_nums

start = time.time()
result = [quash_large_numbers(tokens, 100) for tokens in test_data]
print('original', time.time() - start)

def quash(somelist, digits):
    return [text if len(text) <= digits or not text.isdigit() else '9999' + str(len(text)) for text in somelist]

start = time.time()
result = [quash(item, 2) for item in test_data]
print('textual ', time.time() - start)

import numpy as np

def np_quash(somelist, threshold=100):
    v = np.array(somelist)
    r = np.arange(v.size)
    m = np.core.defchararray.isdigit(v)
    g = v[m].astype(int) > threshold
    i = r[m][g]
    t = np.array(['9999{}'.format(len(x)) for x in v[i].tolist()])
    v = v.astype(t.dtype)
    v[i] = t
    return v.tolist()

start = time.time()
result = [np_quash(item, 100) for item in test_data]
print('numpy   ', time.time() - start)

结果

original 0.6143333911895752
textual  0.12842845916748047
numpy    0.3644399642944336

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM