我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Pandas数据处理加速技巧汇总

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Pandas数据处理加速技巧汇总

Pandas 处理数据的效率还是很优秀的,相对于大规模的数据集只要掌握好正确的方法,就能让在数据处理时间上节省很多很多的时间。

Pandas 是建立在 NumPy 数组结构之上的,许多操作都是在 C 中执行的,要么通过 NumPy,要么通过 Pandas 自己的 Python 扩展模块库,这些模块用 Cython 编写并编译为 C。理论上来说处理速度应该是很快的。

那么为什么同样一份数据由2个人处理,在设备相同的情况下处理时间会出现天差地别呢?

需要明确的是,这不是关于如何过度优化 Pandas 代码的指南。如果使用得当 Pandas 已经构建为可以快速运行。此外优化和编写干净的代码之间存在很大差异。

这是以 Python 方式使用 Pandas 以充分利用其强大且易于使用的内置功能的指南。

数据准备

此示例的目标是应用分时能源关税来计算一年的能源消耗总成本。 也就是说,在一天中的不同时间,电价会有所不同,因此任务是将每小时消耗的电量乘以消耗该小时的正确价格。

从一个包含两列的 CSV 文件中读取数据,一列用于日期加时间,另一列用于以千瓦时 (kWh) 为单位消耗的电能。

日期时间数据优化

import pandas as pd
df = pd.read_csv('数据科学必备Pandas实操数据处理加速技巧汇总/demand_profile.csv')
df.head()
     date_time  energy_kwh
0  1/1/13 0:00       0.586
1  1/1/13 1:00       0.580
2  1/1/13 2:00       0.572
3  1/1/13 3:00       0.596
4  1/1/13 4:00       0.592

乍一看这看起来不错,但有一个小问题。 Pandas 和 NumPy 有一个 dtypes(数据类型)的概念。 如果未指定任何参数,则 date_time 将采用 object dtype。

df.dtypes
date_time      object
energy_kwh    float64
dtype: object

type(df.iat[0, 0])
str

object 不仅是 str 的容器,而且是任何不能完全适合一种数据类型的列的容器。将日期作为字符串处理会既费力又低效(这也会导致内存效率低下)。为了处理时间序列数据,需要将 date_time 列格式化为日期时间对象数组( Timestamp)。

df['date_time'] = pd.to_datetime(df['date_time'])
df['date_time'].dtype
datetime64[ns]

现在有一个名为 df 的 DataFrame,有两列和一个用于引用行的数字索引。

df.head()
               date_time    energy_kwh
0    2013-01-01 00:00:00         0.586
1    2013-01-01 01:00:00         0.580
2    2013-01-01 02:00:00         0.572
3    2013-01-01 03:00:00         0.596
4    2013-01-01 04:00:00         0.592

使用 Jupyter 自带的 %%time 计时装饰器进行测试。

def convert(df, column_name):
	return pd.to_datetime(df[column_name])

%%time
df['date_time'] = convert(df, 'date_time')

Wall time: 663 ms

def convert_with_format(df, column_name):
	return pd.to_datetime(df[column_name],format='%d/%m/%y %H:%M')

%%time
df['date_time'] = convert(df, 'date_time')

Wall time: 1.99 ms

处理效率提高将近350倍。如果在处理大规模数据的情况下,处理数据的时间会无限的放大。

数据的简单循环

既然日期和时间格式处理完毕,就可以着手计算电费了。成本因小时而异,因此需要有条件地将成本因素应用于一天中的每个小时。

在此示例中,使用时间成本将定义成三个部分。

data_type = {
    # 高峰
    "Peak":{"Cents per kWh":28,"Time Range":"17:00 to 24:00"},
    # 正常时段
    "Shoulder":{"Cents per kWh":20,"Time Range":"7:00 to 17:00"},
    # 非高峰
    "Off-Peak":{"Cents per kWh":12,"Time Range":"0:00 to 7:00"}, 
}

如果价格是一天中每小时每千瓦时 28 美分。

df['cost_cents'] = df['energy_kwh'] * 28

               date_time    energy_kwh       cost_cents
0    2013-01-01 00:00:00         0.586           16.408
1    2013-01-01 01:00:00         0.580           16.240
2    2013-01-01 02:00:00         0.572           16.016
3    2013-01-01 03:00:00         0.596           16.688
4    2013-01-01 04:00:00         0.592           16.576
...

但是成本计算取决于一天中的不同时间。这就是你会看到很多人以意想不到的方式使用 Pandas 的地方,通过编写一个循环来进行条件计算。

def apply_tariff(kwh, hour):
    """计算给定小时的电费"""    
    if 0 <= hour < 7:
        rate = 12
    elif 7 <= hour < 17:
        rate = 20
    elif 17 <= hour < 24:
        rate = 28
    else:
        raise ValueError(f'无效时间: {hour}')
    return rate * kwh

def apply_tariff(kwh, hour):
    """计算给定小时的电费"""    
    if 0 <= hour < 7:
        rate = 12
    elif 7 <= hour < 17:
        rate = 20
    elif 17 <= hour < 24:
        rate = 28
    else:
        raise ValueError(f'无效时间: {hour}')
    return rate * kwh

def apply_tariff_loop(df):
    energy_cost_list = []
    for i in range(len(df)):
    	# 循环数据直接修改df
        energy_used = df.iloc[i]['energy_kwh']
        hour = df.iloc[i]['date_time'].hour
        energy_cost = apply_tariff(energy_used, hour)
        energy_cost_list.append(energy_cost)

    df['cost_cents'] = energy_cost_list

Wall time: 2.59 s

循环 .itertuples() 和 .iterrows() 方法

Pandas 实际上 for i in range(len(df)) 通过引入 DataFrame.itertuples() 和 DataFrame.iterrows() 方法使语法就可能显得多余,这些都是yield一次一行的生成器方法。

.itertuples() 为每一行生成一个命名元组,行的索引值作为元组的第一个元素。 名称元组是来自 Python 集合模块的数据结构,其行为类似于 Python 元组,但具有可通过属性查找访问的字段。

.iterrows() 为 DataFrame 中的每一行生成 (index, Series) 对(元组)。

def apply_tariff_iterrows(df):
    energy_cost_list = []
    for index, row in df.iterrows():
        energy_used = row['energy_kwh']
        hour = row['date_time'].hour
        energy_cost = apply_tariff(energy_used, hour)
        energy_cost_list.append(energy_cost)
    df['cost_cents'] = energy_cost_list

%%time
apply_tariff_iterrows(df)

Wall time: 808 ms

速度提高又3倍之多。

.apply() 方法

可以使用 .apply() 方法进一步改进此操作。 Pandas 的 .apply() 方法采用函数(可调用对象)并将它们沿 DataFrame 的轴(所有行或所有列)应用。

lambda 函数将两列数据传递给 apply_tariff()。

def apply_tariff_withapply(df):
    df['cost_cents'] = df.apply(
        lambda row: apply_tariff(
            kwh=row['energy_kwh'],
            hour=row['date_time'].hour),
        axis=1)

%%time
apply_tariff_withapply(df)

Wall time: 181 ms

.apply() 的语法优势很明显,代码简洁、易读、明确。在这种情况下所用时间大约是该 .iterrows() 方法的4分之一。

.isin() 数据选择

但是如何在 Pandas 中将条件计算应用为矢量化操作呢?一个技巧是根据的条件选择和分组 DataFrame 的部分,然后对每个选定的组应用矢量化操作。

使用 Pandas 的.isin()方法选择行,然后在矢量化操作中应用。在执行此操作之前,如果将 date_time 列设置为 DataFrame 的索引会更方便。

df.set_index('date_time', inplace=True)

def apply_tariff_isin(df):
    peak_hours = df.index.hour.isin(range(17, 24))
    shoulder_hours = df.index.hour.isin(range(7, 17))
    off_peak_hours = df.index.hour.isin(range(0, 7))

    df.loc[peak_hours, 'cost_cents'] = df.loc[peak_hours, 'energy_kwh'] * 28
    df.loc[shoulder_hours,'cost_cents'] = df.loc[shoulder_hours, 'energy_kwh'] * 20
    df.loc[off_peak_hours,'cost_cents'] = df.loc[off_peak_hours, 'energy_kwh'] * 12

%%time
apply_tariff_isin(df)

Wall time: 53.5 ms

其中整个过程方法返回一个布尔列表。

[False, False, False, ..., True, True, True]

.cut() 数据分箱

设置时间切分的列表和对那个计算的函数公式,让操作起来更简单,但是这个对于新手来说代码阅读起来有些困难。

def apply_tariff_cut(df):
    cents_per_kwh = pd.cut(x=df.index.hour,
                           bins=[0, 7, 17, 24],
                           include_lowest=True,
                           labels=[12, 20, 28]).astype(int)
    df['cost_cents'] = cents_per_kwh * df['energy_kwh']
    
%%time
apply_tariff_cut(df)

Wall time: 2.99 ms

Numpy 方法处理

Pandas Series 和 DataFrames 是在 NumPy 库之上设计的。这为提供了更大的计算灵活性,因为 Pandas 可以与 NumPy 数组和操作无缝协作。

使用 NumPy 的digitize()函数。它与 Pandas 的相似之处cut()在于数据将被分箱,但这次它将由一个索引数组表示,该数组表示每个小时属于哪个箱。然后将这些索引应用于价格数组。

import numpy as np

def apply_tariff_digitize(df):
    prices = np.array([12, 20, 28])
    bins = np.digitize(df.index.hour.values, bins=[7, 17, 24])
    df['cost_cents'] = prices[bins] * df['energy_kwh'].values

%%time
apply_tariff_digitize(df)

Wall time: 1.99 ms

处理效率比较

对比一下上面几种不同的处理方式的效率吧。

功能运行时间(秒)
apply_tariff_loop()2.59 s
apply_tariff_iterrows()808 ms
apply_tariff_withapply()181 ms
apply_tariff_isin()53.5 ms
apply_tariff_cut()2.99 ms
apply_tariff_digitize()1.99 ms

HDFStore 防止重新处理

通常构建复杂的数据模型时,对数据进行一些预处理会很方便。如果有 10 年的分钟频率用电量数据,即指定了格式参数简单地将日期和时间转换为日期时间也可能需要 20 分钟。只需要这样做一次而不是每次运行模型时都需要进行测试或分析。

可以在这里做的一件非常有用的事情是预处理,然后以处理后的形式存储数据,以便在需要时使用。但是如何才能以正确的格式存储数据而无需再次重新处理呢?如果要保存为 CSV 只会丢失您的日期时间对象,并且在再次访问时必须重新处理它。

Pandas 有一个内置的解决方案使用 HDF5,一种专为存储表格数据数组而设计的高性能存储格式。Pandas 的 HDFStore 类允许将 DataFrame 存储在 HDF5 文件中,以便可以有效地访问它,同时仍保留列类型和其他元数据。dict 是一个类似字典的类,因此可以像对 Python对象一样进行读写。

将预处理的耗电量 DataFrame 存储df在 HDF5 文件中。

data_store = pd.HDFStore('processed_data.h5')

# 将 DataFrame 放入对象中,将键设置为 preprocessed_df 
data_store['preprocessed_df'] = df
data_store.close()

从 HDF5 文件访问数据的方法,并保留数据类型。

data_store = pd.HDFStore('processed_data.h5')

preprocessed_df = data_store['preprocessed_df']
data_store.close()

到此这篇关于Pandas数据处理加速技巧汇总的文章就介绍到这了,更多相关Pandas数据处理内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Pandas数据处理加速技巧汇总

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

数据处理利器:pandas读取Excel文件的高效技巧

随着数据处理的日益普及,越来越多的人开始关注如何高效利用数据,让数据为自己所用。而在日常的数据处理中,Excel表格无疑是最为常见的一种数据格式。然而,当需要处理大量数据时,手动操作Excel显然会变得十分费时费力。因此,本文将介绍一个高效
数据处理利器:pandas读取Excel文件的高效技巧
2024-01-19

通过使用pandas来探讨数据清洗和预处理的技巧

利用pandas进行数据清洗和预处理的方法探讨引言:在数据分析和机器学习中,数据的清洗和预处理是非常重要的步骤。而pandas作为Python中一个强大的数据处理库,具有丰富的功能和灵活的操作,能够帮助我们高效地进行数据清洗和预处理。本文
通过使用pandas来探讨数据清洗和预处理的技巧
2024-01-13

提升数据处理效率:使用pandas读取Excel文件的技巧

优化数据处理流程:Pandas读取Excel文件的技巧引言:在数据分析和处理的过程中,Excel是最常见的数据来源之一。然而,Excel文件的读取和处理往往是效率较低的,特别是当数据量较大时。为此,本文将介绍如何使用Python的Pand
提升数据处理效率:使用pandas读取Excel文件的技巧
2024-01-24

Golang数据处理技巧大揭秘

Golang数据处理技巧大揭秘,需要具体代码示例引言:Golang作为一种高效且强大的编程语言,广泛应用于数据处理领域。本文将分享一些Golang中常用的数据处理技巧,并给出具体的代码示例,旨在帮助读者更好地理解和运用这些技巧。一、使用切片
Golang数据处理技巧大揭秘
2023-12-23

PHP 的大数据结构处理技巧

大数据结构处理技巧:分块:分解数据集并分块处理,减少内存消耗。生成器:逐个产生数据项,无需加载整个数据集,适用于无限数据集。流:逐行读取文件或查询结果,适用于大文件或远程数据。外部存储:对于超大数据集,将数据存储在数据库或 nosql 中。
PHP 的大数据结构处理技巧
2024-05-08

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录