范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

Pandas大数据量内存优化

  #头条创作挑战赛# 一、背景介绍
  Pandas 在处理大数据(尤其是列比较多的场景)时,如果不做优化,内存占用还是很大的,下面通过一个实例来说明可以怎样优化
  首先,生成一批 18 万的数据,每条数据 151 列import pandas as pd import numpy as np   def gen_big_data(csv_file: str, big_data_count=90000):     chars = "abcdefghijklmnopqrstuvwxyz"     dates = pd.date_range(start="2020-01-01", periods=big_data_count, freq="30s")     big_data_cols = ["Name"]     for group in range(1, 31):         big_data_cols.extend([f"date str {group}",                               f"bool {group}",                               f"int {group}",                               f"float {group}",                               f"str {group}"])     big_data = []     for i in range(0, big_data_count):         row = [f"Name Item {(i + 1)}"]         for _ in range(0, 30):             row.extend([str(dates[i]),                         i % 2 == 0,                         np.random.randint(10000, 100000),                         10000 * np.random.random(),                         chars[np.random.randint(0, 26)] * 15])         big_data.append(row)     df = pd.DataFrame(data=big_data, columns=big_data_cols)     df.to_csv(csv_file, index=None)   if __name__ == "__main__":     # 修改存放路径以及模拟数据量(默认 9 万)     gen_big_data("./files/custom_big_data.csv", 180000) 复制代码
  查看生成的数据格式,可以看到每一行有 151 列
  保存数据后,先查看一下内存占用情况import pandas as pd   def info_memory(csv_file: str):     df = pd.read_csv(csv_file)     print(df.info(memory_usage="deep"))   if __name__ == "__main__":     info_memory("./files/custom_big_data.csv") 复制代码
  打印结果如下,可以看到当前内存占用为 862.1MB RangeIndex: 180000 entries, 0 to 179999 Columns: 151 entries, Name to str 30 dtypes: bool(30), float64(30), int64(30), object(61) memory usage: 862.1 MB 复制代码
  查看不同类型的内存占用情况def info_memory_by_d_type(csv_file: str):     df = pd.read_csv(csv_file)     for d_type in ["bool", "float64", "int64", "object"]:         d_type_selected = df.select_dtypes(include=[d_type])         mem_mean_bit = d_type_selected.memory_usage(deep=True).mean()         mem_mean_mb = mem_mean_bit / 1024 ** 2         print(f"mean memory usage: {d_type:<7} - {mem_mean_mb:.3f} M") 复制代码
  输出结果如下,其中 object 类型占用内存最多mean memory usage: bool    - 0.166  M mean memory usage: float64 - 1.329  M mean memory usage: int64   - 1.329  M mean memory usage: object  - 12.494 M 复制代码二、优化方案
  查看某个类型的内存占用量def info_mem_usage_mb(pd_obj):     if isinstance(pd_obj, pd.DataFrame):         mem_usage = pd_obj.memory_usage(deep=True).sum()     else:         mem_usage = pd_obj.memory_usage(deep=True)     # 转换为MB返回     return f"{mem_usage / 1024 ** 2:02.3f} MB" 复制代码
  int 和 float 类型
  对于 int 和 float 类型的数据,Pandas 加载到内存中的数据,默认是 int64 和 float64。一般场景下的数据,用 int32 和 float32 就足够了,用 numpy.iinfo 和 numpy.finfo 可以打印对应类型的取值范围Machine parameters for int32 --------------------------------------------------------------- min = -2147483648 max = 2147483647 ---------------------------------------------------------------  Machine parameters for int64 --------------------------------------------------------------- min = -9223372036854775808 max = 9223372036854775807 --------------------------------------------------------------- 复制代码Machine parameters for float32 --------------------------------------------------------------- ... maxexp =    128   max =        3.4028235e+38 nexp =        8   min =        -max ---------------------------------------------------------------  Machine parameters for float64 --------------------------------------------------------------- ... maxexp =   1024   max =        1.7976931348623157e+308 nexp =       11   min =        -max --------------------------------------------------------------- 复制代码
  分别优化 int 和 float 的类型def optimize_int_and_float():     df_int = df.select_dtypes(include=["int64"])     df_int_converted = df_int.apply(pd.to_numeric, downcast="unsigned")     df_float = df.select_dtypes(include=["float64"])     df_float_converted = df_float.apply(pd.to_numeric, downcast="float")      print("int before     ", info_mem_usage_mb(df_int))     print("int converted  ", info_mem_usage_mb(df_int_converted))      print("float before   ", info_mem_usage_mb(df_float))     print("float converted", info_mem_usage_mb(df_float_converted)) 复制代码
  优化后的结果如下,内存减少 50% 左右int before      41.199 MB int converted   20.599 MB float before    41.199 MB float converted 20.599 MB 复制代码
  object 类型中的普通 str 数据
  获取 object 类型数据,并调用 describe() 展示统计信息
  对于区分度较低的 str 1 到 str 30,一共只有 26 个可能的值,可以考虑转换为 Pandas 中的 categroy 类型,这里将区分度小于 40% 的列转换为 category 类型def optimize_obj():     df_obj = df.select_dtypes(include=["object"])     df_obj_converted = pd.DataFrame()     for col in df_obj.columns:         unique_count = len(df_obj[col].unique())         total_count = len(df_obj[col])         # 将区分度小于40%的列转换为category类型         if unique_count / total_count <= 0.4:             df_obj_converted.loc[:, col] = df_obj[col].astype("category")         else:             df_obj_converted.loc[:, col] = df_obj[col]      print("object before   ", info_mem_usage_mb(df_obj))     print("object converted", info_mem_usage_mb(self.df_obj_converted)) 复制代码
  执行结果如下,降低了 300+M 的内存object before    774.602 MB object converted 409.047 MB 复制代码
  object 类型中的 date 数据def optimize_date_str():     df_date = pd.DataFrame()     df_date_converted = pd.DataFrame()     for col_name in df.columns:         if col_name.startswith("date str"):             df_date.loc[:, col_name] = df[col_name]             df_date_converted.loc[:, col_name] = pd.to_datetime(df[col_name])      print("date before   ", info_mem_usage_mb(df_date))     print("date converted", info_mem_usage_mb(df_date_converted)) 复制代码
  执行结果如下,也降低了 300+M 的内存date before    391.388 MB date converted 41.199 MB 复制代码三、总体优化
  综合以上的优化方法,并封装为类 PandasMemoryOptimizeDemoimport pandas as pd import numpy as np   class PandasMemoryOptimizeDemo:     df: pd.DataFrame     df_int_converted: pd.DataFrame     df_float_converted: pd.DataFrame     df_obj_converted: pd.DataFrame     df_date_converted: pd.DataFrame      def __init__(self, csv_file: str):         self.csv_file = csv_file         self.df = pd.read_csv(self.csv_file)           @staticmethod     def info_mem_usage_mb(pd_obj):         if isinstance(pd_obj, pd.DataFrame):             mem_usage = pd_obj.memory_usage(deep=True).sum()         else:             mem_usage = pd_obj.memory_usage(deep=True)         # 转换为 MB 返回         return f"{mem_usage / 1024 ** 2:02.3f} MB"           def optimize_int_and_float(self):         df_int = self.df.select_dtypes(include=["int64"])         self.df_int_converted = df_int.apply(pd.to_numeric, downcast="unsigned")         df_float = self.df.select_dtypes(include=["float64"])         self.df_float_converted = df_float.apply(pd.to_numeric, downcast="float")          print("int before     ", self.info_mem_usage_mb(df_int))         print("int converted  ", self.info_mem_usage_mb(self.df_int_converted))          print("float before   ", self.info_mem_usage_mb(df_float))         print("float converted", self.info_mem_usage_mb(self.df_float_converted))      def optimize_obj(self):         df_obj = self.df.select_dtypes(include=["object"])         self.df_obj_converted = pd.DataFrame()         for col in df_obj.columns:             unique_count = len(df_obj[col].unique())             total_count = len(df_obj[col])             # 将区分度小于 40% 的列转换为 category 类型             if unique_count / total_count <= 0.4:                 self.df_obj_converted.loc[:, col] = df_obj[col].astype("category")             else:                 self.df_obj_converted.loc[:, col] = df_obj[col]          print("object before   ", self.info_mem_usage_mb(df_obj))         print("object converted", self.info_mem_usage_mb(self.df_obj_converted))      def optimize_date_str(self):         df_date = pd.DataFrame()         self.df_date_converted = pd.DataFrame()         for col_name in self.df.columns:             if col_name.startswith("date str"):                 df_date.loc[:, col_name] = self.df[col_name]                 self.df_date_converted.loc[:, col_name] = pd.to_datetime(self.df[col_name])          print("date before   ", self.info_mem_usage_mb(df_date))         print("date converted", self.info_mem_usage_mb(self.df_date_converted))      def optimize_all(self):         self.optimize_int_and_float()         self.optimize_obj()         self.optimize_date_str()          df_converted = self.df.copy()         df_converted[self.df_int_converted.columns] = self.df_int_converted         df_converted[self.df_float_converted.columns] = self.df_float_converted         df_converted[self.df_obj_converted.columns] = self.df_obj_converted         df_converted[self.df_date_converted.columns] = self.df_date_converted          print("before   ", self.info_mem_usage_mb(self.df))         print("converted", self.info_mem_usage_mb(df_converted))   if __name__ == "__main__":     optimize_demo = PandasMemoryOptimizeDemo("./files/custom_big_data.csv")     optimize_demo.optimize_all() 复制代码
  执行结果如下,优化效果还是很明显的before    862.149 MB converted 105.207 MB 复制代码四、直接优化 read_csv 方法
  写代码的过程中,如果每次都按照这样的步骤,其实还是很繁琐,那能不能在调用 read_csv 方法时就进行优化呢?
  接下来就一起来探索一下
  在 PyCharm 中,点击 read_csv 进入源码,发现该方法提供了非常丰富的参数(50+),这里只列举需要的参数def read_csv(     filepath_or_buffer: FilePath | ReadCsvBuffer[bytes] | ReadCsvBuffer[str],     # General Parsing Configuration     dtype: DtypeArg | None = None,     converters=None,     # Datetime Handling     parse_dates=None,     infer_datetime_format=False,     keep_date_col=False,     date_parser=None,     low_memory=_c_parser_defaults["low_memory"],     memory_map=False,     storage_options: StorageOptions = None, ):     # locals() should never be modified     kwds = locals().copy() 复制代码
  可以直接指定 dtype 和 parse_dates,最终代码如下def big_data_optimized_read_csv(self):     d_type_dict = {}     date_indexes = []     for i in range(1, 31):         d_type_dict[f"int {i}"] = "int32"         d_type_dict[f"float {i}"] = "float32"         d_type_dict[f"str {i}"] = "category"          date_indexes.append(5 * (i - 1) + 1)     self.df = pd.read_csv(self.csv_file, dtype=d_type_dict, parse_dates=date_indexes)     print("optimized read_csv: ", self.info_mem_usage_mb(self.df)) 复制代码
  执行结果如下,内存占用也大大降低了optimized read_csv:  105.207 MB

五大名医集体总结60岁之后要想少生病的10大建议!当我们难以坚持好的习惯时,想要不生病的话,一定不能再去做伤害身体健康的事情!今天,和大家分享一些退休后不生病的经验总结,其中不乏院士名医的养生秘方,想要不生病,一定要记住这不生病的痛风还想吃火锅?也不是不行,牢记这4个要点,吃得健康天气越来越冷了,火锅成了最受人们喜爱的食物。但是对于痛风患者来说,火锅就不那么友好了。很多痛风急性发作的患者,都有吃火锅和饮酒的经历。痛风患者到底能不能火锅,成了大家都想知道的一个壹健康小知识冬至早上吃饺子还是中午吃?吃饺子有什么好处冬至是生活中常见的一种节气,在我国是比较受重视的,冬至的时候人们会吃饺子,那冬至早上吃饺子还是中午吃?冬至吃饺子有什么好处?冬至早上吃饺子还是中午吃都可以。冬至是我国二十四节气之一湖南版梅干菜做法,蒸扣肉吃太香了梅干菜又叫乌干菜,是浙江绍兴一种价廉物美的传统名菜,也是绍兴的著名特产。虽然梅干菜是浙江特产,但我们湖南人从小也很爱吃。我们村里办宴席,桌上必备的一道大菜就有梅菜扣肉。今天用奶奶祖法国时尚圈力捧的设计新秀,还是位脸蛋天才今年巴黎时装周真的是神仙打架,不少秀场融入了好玩的概念,亮点超多!但是这一届,让我尤其关注到的,是法国老牌时装屋Rochas年仅24岁的新任设计总监CharlesdeVilmori护肤小妙招,用过都说好我的日常护肤心得护肤小妙招,用过都说好!你可曾经皮肤上长满痘痘?可有黑色暗纹的痘印?可有皮肤干燥问题?介绍简单实用护肤小方法准备产品(实惠简单)1。温清水2。干净的毛巾3。洗面奶依化妆学徒,学费3万,月入3000提起化妆学校,业内最有名气的莫过于毛戈平东田彩妆与MakeupForever品牌旗下的彩妆学院。近两年,毛戈平李东田频频现身于网红美妆博主频道,重新出现在年轻人的视野里。他们合作过49岁陈妙瑛出席港姐聚会,休闲打扮难掩霸气,已转型经商至今未婚1993年的港姐佳丽时隔28年重聚,虽然并没有全员到齐,郭可盈麦家琪就没有现身,但是还有那么多人能够聚在一起已经很不简单。出席者中莫可欣已经不算是焦点,毕竟她这些年频频随着方中信露DeHorizon加密世界中的迪士尼,真正的元宇宙一DeHorizon项目简介DeHorizon是美国的一家区块链游戏服务商,旨在推出元宇宙游戏生态系统,为玩家提供游戏体验,推动其向开放互连连接和构建用户生成网络发展。作为一个Ga世界更新排名!王艺迪跻身5强指日可待,张本智和原地踏步国际乒联12月7日公布最新的世界排名。由于世锦赛之后马上举办的WTT世界杯总决赛还未结束,所以各个顶尖高手的排名会在下周迎来不同程度的变化,本周的排名与上期没有太大变化。不过已经打疑问乒乓球三大赛体系是否仍存在?WTT世界杯决赛算不算?2021年乒乓球WTT世界杯决赛即将结束,但许多球迷心中的一个疑问却仍然未得到解答,那就是这个赛事究竟能否取代旧的世界杯?算不算是乒坛的三大赛之一?最后的冠军能否被国乒认证为世界冠
新手炒股快速入门,让你股票投资赢在起跑线上我将从从实用性与可操作性入手,全面系统地介绍新手炒股必知的基础知识,包括股民的入市准备股票交易的基本流程,全程教会新股民如何操盘,如何选股,如何把握最佳股票买卖点,如何看透庄家,巧三十而立却未立的我们常说三十而立,到了而立之年却依然一事无成,人生过得一塌糊涂。我们要怎么办呢?三十岁,曾经觉得很远,没想到已然到了这个年纪。以前觉得年纪只是一个符号,不会影响什么。真的到了三十岁才知抖音外卖突袭战提点5低于同行3个百分点,联盟饿了么抢夺美团千亿市场抖音将在外卖领域与美团展开正面竞争。2月9日,尽管已有抖音内部人士否认抖音将于3月上线全国外卖服务的传闻,搜狐财经从饿了么内部人士外卖行业专家等多方面获悉,抖音app目前确实正在筹全球鱼子酱市场占有率第二!这家彭州造企业凭啥?用贝壳勺子挖一勺放在虎口处,再放进口中用舌尖和上颚碾碎,颗粒饱满圆润的鱼子酱逐一爆破,那口感,好像海浪在嘴里跳舞。享有黑金美誉的鱼子酱,向来是食家饕餮们的座上宾,长久以来,鱼子酱的墙倒众人推!曼城在危机中越陷越深,媒体调查竟有超6成球迷赞成被罚降级俗话说墙倒众人推,破鼓万人捶,现在的曼城就正在经历这样的事情。英超官方最近几天公布的报告中认定该队自20092010赛季以来,多次都出现了违反联赛财政规则的情况(ffp),虽然此前取消U23政策,二队打中乙2023职业联赛新规初显,细节或仍有优化记者陈永报道2月7日,中足联筹备组在香河召开三级职业联赛俱乐部总经理会议,在此次会议上,中足联筹备组也发布了中国足协和中足联筹备组制定的多项意向性政策,包括中超取消U23政策中超俱阿特苏经纪人他所在的11层大楼被地震完全摧毁,而他住在9楼直播吧2月8日讯土耳其本周发生大地震,而曾在切尔西纽卡斯尔踢过球的阿特苏在地震中受伤。阿特苏的经纪人纳纳塞科雷向媒体透露了当时的经历。阿特苏目前效力于土耳其球队哈塔斯堡,在本次地震勒布朗登顶雷霆搅局,你带走数据,我拿下胜利勒布朗詹姆斯,终于超越了天勾贾巴尔,成为了NBA历史得分王。其实第三节他就拿下36分,完成了反超,然后第四节他只有2投1中,拿下2分,但湖人130133,输给了直接竞争对手鹈鹕3分智能建造战略地位再提升智能防腐机器人助推桥梁行业减碳增效前言制造业进入到全新的数字化时代,需要构建新型智能工厂数字化工厂与智能车间以助力传统产业智能制造升级,将新一代信息技术贯穿到设计工艺生产物流等各个环节。目的是完善创新体系提升产品质氢能源汽车未来将取代电车?这4家企业将成为下一个比亚迪?据统计全球加氢站已经突破1千座大关,而我国占总数的3分之一约300座左右,目前全球氢燃料站的部署势头强劲,而中国已经走在了处于领先的位置。自从长安发布的氢能源汽车之后,国内车迷对氢欢太数科智造OPPO钱包(1)聚类算法实现切卡自由在还没有电子支付的时代,我们都有这样的经历钱包里各种ICIPIQ卡一大堆,掏半天急得满头汗,都找不到自己想要的卡。而现在所有的卡都装进手机里了,本来以为可以高枕无忧,可是随着电子钱