【问题标题】:Extract the highest place value digit from numbers in a dataframe从数据框中的数字中提取最高位值数字
【发布时间】:2020-06-11 12:38:11
【问题描述】:

我有一个 python 数据框,其中有一列称为错误代码:

df1=pd.DataFrame({'errorcodes1':[6321,235,314,421,5346,514,4,3415,136,216,34,623])

我需要一个输出:[6,2,3,4,5,5,4,3,1,2,3,6] 的函数。

我曾想过将每个错误代码转换为一个字符串,并提取元素 [0]。但是,这涉及字符串操作、从整数转换为整数,这可能很慢。有更快的方法吗?

【问题讨论】:

  • df['errorcodes1'].apply(lambda x:int(str(x)[0]))
  • 顺便说一句:你检查过你的想法有多慢吗?也许它并不慢。您搜索更快的方法,但您不知道您的想法有多慢。您希望如何比较这两个版本?
  • 这是基于对 Fortran 95、MATLAB 和 C++ 等其他语言的经验。字符串操作和类型转换是较慢的操作之一。
  • 熊猫为此使用 C/C++ 代码,因此它可以比纯 Python 更快。没有字符串的唯一想法是 log() 但我不知道它会快多少 - 你必须测试它。

标签: python dataframe digits


【解决方案1】:

如果您被禁止转换为 str,您可以利用 Briggs 对数执行该任务,方法如下:

import math
numbers = [6321,235,314,421,5346,514,4,3415,136,216,34,623]
def first_digit(n):
    return n//10**int(math.log(n, 10))
for n in numbers:
    print(n, first_digit(n), sep='\t')

输出:

6321    6
235 2
314 3
421 4
5346    5
514 5
4   4
3415    3
136 1
216 2
34  3
623 6

解释:首先我使用前面提到的对数检测数字中的位数,然后使用整数除法 (//) 检查有多少 10**(number_of_digits) 适合给定数字。

【讨论】:

    【解决方案2】:

    我测试了哪种方法更快 - logstr - 两者都给出了相似的结果,但 str 快一点。如果您不将str 转换为int,那么它会更快。您也可以使用ord() 代替int() 以使其更快。

    e1 = time.time()
    results = [int(str(n)[0]) for n in numbers]
    e2 = time.time()
    print('int(str): {:.10f}'.format(e2-e1))
    
    e1 = time.time()
    results = [n//10**int(math.log(n, 10)) for n in numbers]
    e2 = time.time()
    print('     log: {:.10f}'.format(e2-e1))
    
    e1 = time.time()
    results = [str(n)[0] for n in numbers]
    e2 = time.time()
    print('     str: {:.10f}'.format(e2-e1))
    
    e1 = time.time()
    results = [ord(str(n)[0])-ord('0') for n in numbers]
    e2 = time.time()
    print('ord(str): {:.10f}'.format(e2-e1))
    

    结果

    int(str): 0.0000424385
         log: 0.0000514984
         str: 0.0000197887
    ord(str): 0.0000286102
    

    为了进行更好的测试,我使用了模块timeit,它多次运行代码并计算平均时间。

    我还使用df.apply() 检查代码并将df 转换为list,然后将list 转换为df。一切都表明,用于获得第一位数字的时间是如此之短,以至于它在所有计算中并不重要

    import pandas as pd
    import math
    import time
    import timeit
    
    def test1():
        results = [int(str(n)[0]) for n in numbers]
    
    def test1b():
        results = [ord(str(n)[0]) - ord('0') for n in numbers]
    
    def test1c():
        results = [str(n)[0] for n in numbers]
    
    def test2():
        results = [n//10**int(math.log(n, 10)) for n in numbers]
    
    def test3():
        df['number'] = df['errorcodes1'].apply(lambda n:int(str(n)[0]))
    
    def test3b():
        df['number'] = df['errorcodes1'].apply(lambda n:ord(str(n)[0])-ord('0'))
    
    def test3c():
        df['number'] = df['errorcodes1'].apply(lambda n:str(n)[0])
    
    def test4():    
        df['number'] = df['errorcodes1'].apply(lambda n:n//10**int(math.log(n, 10)))
    
    def test5():
        numbers = df['errorcodes1'].to_list()
        results = [int(str(n)[0]) for n in numbers]
        df['number'] = results
    
    def test6():
        numbers = df['errorcodes1'].to_list()
        results = [n//10**int(math.log(n, 10)) for n in numbers]
        df['number'] = results
    
    df = pd.DataFrame({'errorcodes1':[6321,235,314,421,5346,514,4,3415,136,216,34,623]})
    numbers = df['errorcodes1'].to_list()
    
    print('list log()      : {:.5f}'.format(timeit.timeit(test2, number=1000)))
    print('list int(str()) : {:.5f}'.format(timeit.timeit(test1, number=1000)))
    print('list ord(str()) : {:.5f}'.format(timeit.timeit(test1b, number=1000)))
    print('list str()      : {:.5f}'.format(timeit.timeit(test1c, number=1000)))
    print('---')
    print('df.apply(log())      : {:.5f}'.format(timeit.timeit(test4, number=1000)))
    print('df.apply(int(str())) : {:.5f}'.format(timeit.timeit(test3, number=1000)))
    print('df.apply(ord(str())) : {:.5f}'.format(timeit.timeit(test3b, number=1000)))
    print('df.apply(str())      : {:.5f}'.format(timeit.timeit(test3c, number=1000)))
    print('---')
    print('df -> list int(str()) -> df : {:.5f}'.format(timeit.timeit(test5, number=1000)))
    print('df -> list log()      -> df : {:.5f}'.format(timeit.timeit(test6, number=1000)))
    

    结果:

    list log()      : 0.01505
    list int(str()) : 0.00917
    list ord(str()) : 0.00713
    list str()      : 0.00463
    ---
    df.apply(log())      : 0.62433
    df.apply(int(str())) : 0.61940
    df.apply(ord(str())) : 0.60435
    df.apply(str())      : 0.64205
    ---
    df -> list int(str()) -> df : 0.27188
    df -> list log()      -> df : 0.27696
    

    【讨论】:

    • 感谢您的深入回答。非常有用。
    【解决方案3】:

    我认为字符串操作是最好的,或者您可以尝试按长度划分每个数据单元

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-05
      • 2017-10-22
      • 1970-01-01
      • 2021-10-14
      • 1970-01-01
      • 2018-01-31
      相关资源
      最近更新 更多