python数据处理中内存优化的一些tricks

1、读入数据时,pandas默认int类型为int64,未采用最省类型方式读取,可通过以下方式优化内存

1)数值型能用更低内存类型保存就转换为更低内存类型

   

 2) 将object类型转换为category类型

     category 类型在底层使用整型数值来表示该列的值,而不使用原值.Pandas用一个字典来构建这些整型数据到原数据的映射关系.当一列只包含有有限种值时,这种设计不错。当我们把一列转换为category类型时,pandas会用一种最省空间的int子类型来表示这一列,对于缺失值,category子类型会将缺失数据设为-1.如果某一列全都是唯一值,category类型将会占用更多内存,这是因为这样做不仅要存储全部的原始字符串数据,还要存储整型类别标识.

代码如下:

def reduce_mem_usage(df, verbose=True):

    numerics = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']

         cateics = ['object']

    start_mem = df.memory_usage().sum() / 1024**2

    for col in df.columns:

        col_type = df[col].dtypes

                   num_unique_values = len(df[col].unique())

                   num_total_values = len(df[col])

        if col_type in numerics:

            c_min = df[col].min()

            c_max = df[col].max()

            if str(col_type)[:3] == 'int':

                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:

                    df[col] = df[col].astype(np.int8)

                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:

                    df[col] = df[col].astype(np.int16)

                elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:

                    df[col] = df[col].astype(np.int32)

                elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:

                    df[col] = df[col].astype(np.int64)

            else:

                if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:

                    df[col] = df[col].astype(np.float16)

                elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:

                    df[col] = df[col].astype(np.float32)

                else:

                    df[col] = df[col].astype(np.float64)

                   if (col_type in cateics) and (num_unique_values*1.0/num_total_values < 0.5):

                       df[col] = df[col].astype('category')

         end_mem = df.memory_usage().sum() / 1024**2

    if verbose:

        print('Mem. usage decreased to {:5.2f} Mb ({:.1f}% reduction)'.format(

            end_mem, 100 * (start_mem - end_mem) / start_mem))

    return df

2、分批读入处理
      pandas.read_csv('',iterator = True, chunksize = 10000)
分批处理数据:
如取众数,即分批求类别次数后,再在外面整合求所有类别次数,得到次数最大类别
如取平均值,记录分批长度及平均值,再在外面整合最终平均值
如取中位数,即分批求类别次数后,再在外面整合求所有类别次数,排序后得到中间次数类别

3、及时回收不需要的变量
import gc
del a
gc.collect()

4、pandas.read_csv 使用指定列,指定类型读取,指定时间读取,低内存消耗等等
1) dtype:指定每列数据的数据类型,如{'a':np.float64,'b':np.int32}

2) usecols:返回一个数据子集,这个参数可以加快加载速度并降低内存消耗

3) low_memory:分块加载到内存,在低内存消耗解析,可能出现类型混淆。为避免类型混淆,需设置False,或者使用dtype参数指定类型。

4) memory_map:
如果使用文件在内存内,直接map文件使用.使用这种方式可以避免文件再次IO操作

5) parse_dates:
boolean.True -> 解析索引
list of ints or names. e.g. If [1,2,3] -> 解析1,2,3列的值作为独立的日期列;
list of lists. e.g.If [[1,3]] -> 合并1,3列作为一个日期列使用
dict, e.g. {'foo':[1,3]} -> 将1,3列合并,并给合并后的列起名为"foo"

5、谨防驻留字符串
python会记录如字符串等不可改变的值(其每个值的大小依赖于实现方法)

t = "abcdefghijklmnopqrstuvwxyz"
p = "abcdefghijklmnopqrstuvwxyz"
id(t)
id(p)

如果两个字符串拥有相同的ID或引用——他们是全等的

如果你的程序创建了许多小的字符串,你的内存就会出现膨胀

6、生成字符串时使用Format来代替"+"

st = "{0}_{1}_{2}_{3}".format(a,b,c,d) #对内存更好,不创建临时变量
st2 = a + '_' + b + '_' + c + '_' + d #在每个"+"时创建一个临时str, 这些都是驻留在内存中的

当我们将某些字符串构造从"+" 变为使用format时, 内存会明显被节省。

posted @ 2020-05-16 23:03  白鹭倾城  阅读(1250)  评论(0编辑  收藏  举报