【问题标题】:Python - How to improve speed of transformation of string to floatPython - 如何提高字符串到浮点数的转换速度
【发布时间】:2021-04-10 15:47:18
【问题描述】:

我正在处理一个包含多种数据类型的非常大的数据框。 有两种类型的数据具有我感兴趣的一些特征,我想有效地将​​其转换为浮动

  1. 字符串变量的某些字符集可以映射为 1,其他字符映射为 0,其余字符映射为 nan
  2. 具有'12,34'格式的浮点数的字符串变量,函数float无法正确转换它们,因为它们有逗号而不是点,因此需要先替换它们

目前我正在这样做:

import pandas as pd
import numpy as np
dataset = pd.DataFrame({'var1':['Error', 'No Data', 'START', 'OFF'],
                        'var2':['2,65', '3,45', '4', '6,7089'],
                        'var3':['START', 'OFF', 'NON', 'Error']})

statusZero= ['STOP', 'OFF']
statusOne= ['START', 'ON']
statusNaN= ['Error', 'No Data'] # it can be everything else really

patternZero = '|'.join(statusZero)
patternOne = '|'.join(statusOne)
patternNaN = '|'.join(statusNaN)

def to_float(x):
    import re
    try:
        x = x.replace(',', '.')
        x = re.sub(patternZero, '0', x)
        x = re.sub(patternNaN, 'nan', x)
        x = re.sub(patternOne, '1', x)
        return float(x)
    except:
        try:
            return float(x)
        except:
            return np.nan

dataset = dataset.applymap(to_float)
dataset

有什么我可以替代的东西来更高效、更优雅地做到这一点吗?

【问题讨论】:

  • 我认为你可以完全删除第二个 try-except 并且只有except: return np.nan

标签: python pandas performance dataframe numpy


【解决方案1】:

.applymap 是对每个单独值的循环,因此它会非常慢。在这种情况下,更好的选择是使用.map 将您的单词映射到1/0,并使用pd.to_numeric 处理任何类似数字的数字(首先用小数替换逗号之后)。默认情况下,未映射或隐藏的任何内容都是NaN,因此无需指定。

虽然这些仍然使用apply,但它是列上的循环,因此这些通常非常快。

# Create a dict of your exact replacement to 1/0
d = {'STOP': 0, 'OFF': 0, 'START': 1, 'ON': 1}

df1 = dataset.replace(',', '.', regex=True).apply(pd.to_numeric, errors='coerce')

for col in dataset.columns:
    dataset[col] = dataset[col].map(d)
    
dataset = dataset.combine_first(df1)
#   var1    var2  var3
#0   NaN  2.6500   1.0
#1   NaN  3.4500   0.0
#2   1.0  4.0000   NaN
#3   0.0  6.7089   NaN

如果您需要部分字符串匹配或不区分大小写的匹配来映射到 1/0,则可以使用字符串方法来执行此操作,但由于字符串方法往往较慢,因此会有些慢。

【讨论】:

    【解决方案2】:
    import re
    
    datadict = {
    'var1':['Error', 'No Data', 'START', 'OFF'],
    'var2':['2,65', '3,45', '4', '6,7089'],
    'var3':['START', 'OFF', 'NON', 'Error']}
    
    statusdict = {
    '0':['STOP', 'OFF'],
    '1':['START', 'ON'],
    'nan':['Error', 'No Data']
    }
    
    
    for datakey in datadict.keys():
        temp = " @ ".join(datadict[datakey]).replace(",",".")
        datadict[datakey] = temp
        for statkey in statusdict.keys():
            for statval in statusdict[statkey]:
                if statval in temp:
                    datadict[datakey] = re.sub(statval,statkey,datadict[datakey])
    
        datadict[datakey] = datadict[datakey].split(" @ ")
    
    print (datadict)
    
    #Load the datadict in your panda df
    

    这将非常快,因为它在必要时使用正则表达式。另外,它只是迭代最小值。

    因此,对于每个 var1、var2、var3,您获取单词列表。

    你用它创建一个字符串,选择一个你在别处找不到的分隔符,你替换你的逗号。

    然后您浏览 yoru statusdict 以检查是否在字符串中找到状态键中的列表中的一个值,如果是这样,您重新分,您拆分回来,就是这样。

    【讨论】:

      【解决方案3】:

      您可以执行以下操作,避免应用:

      import numpy as np
      
      replacements = {v: e for e, vs in zip(['0', 'nan', '1'], [statusZero, statusOne, statusNaN]) for v in vs}
      res = dataset.replace(replacements).replace(',', '.', regex=True)
      dataset[:] = np.genfromtxt(res.values.flatten()).reshape(res.shape)
      print(dataset)
      

      输出

         var1    var2  var3
      0   1.0  2.6500   NaN
      1   1.0  3.4500   0.0
      2   NaN  4.0000   NaN
      3   0.0  6.7089   1.0
      

      【讨论】:

        【解决方案4】:

        您可以使用字典而不是正则表达式。这将使它更快更简单:

        mapping = { 'STOP':0.0,  'OFF':0.0, 'START':1.0, 'ON':1.0 }
        
        def to_float(x):
            try:    return mapping.get(x,float(x.replace(",",".")))
            except: return np.nan
        

        如果您的非数字值在有限的集合内,您可以动态扩充映射字典以避免经历浮点转换过程并反复遇到异常:

        def to_float(x):
            try: 
                return mapping.get(x,float(x.replace(",",".")))
            except:
                mapping[x] = np.nan
                return np.nan
        

        【讨论】:

          猜你喜欢
          • 2016-06-14
          • 1970-01-01
          • 2013-10-03
          • 2019-06-22
          • 2019-07-10
          • 2011-11-25
          • 2012-10-19
          • 1970-01-01
          相关资源
          最近更新 更多