呆鸟的Python数据分析Python

Pandas进阶之提速遍历操作

2019-07-06  本文已影响0人  惑也

一、概念

  1. pandas是基于numpy库的数组结构构建的,它的很多操作都是(通过numpy或者pandas自身由Cpython实现并编译成C的扩展模块)在C语言中实现的。因此,正确使用pandas,它的运行速度是非常快的。
  2. 本篇介绍几种pandas中常用的提升运行速度的方法
    1)将datetime数据与时间序列一起使用的优点
    2)进行批量计算的最有效途径

二、使用Datetime数据节省时间

  1. 通常创建DataFrame时,或从txt、excel中读取数据时,如果没有特殊声明,那么date_time将会成为默认的object类型,实际上,pandas和numpy都有一个dtypes的概念,可以设置数据类型;
df = pd.read_csv("speed_promotion.csv")

df.head()
   type                 id                      amount      dt
0   QY  ac89c667-8d21-454f-b205-49e3d5ba4920    38000.0 2018/9/21 0:00
1   XYY 0cb72f4d-0059-43ac-a326-6fcf33e55632    85196.1 2019/1/29 0:00
2   QY  6937fdb5-bef7-419a-a633-7f58f664c9cc    33000.0 2018/8/29 0:00
3   QY  05b75e08-f2fe-4610-87ec-15ada55a1685    54000.0 2018/12/21 0:00
4   QY  1e9f8e40-67f9-4882-8935-4e10c5b6258f    32000.0 2018/12/21 0:00

df.dtypes
type       object
id         object
amount    float64
dt         object        # date_time,默认成了object类型
dtype: object
  1. object 类型像一个大的容器,不仅仅可以承载 str,也可以包含那些不能很好地融进一个数据类型的任何数据列,如果我们将日期作为 object 类型就会极大的影响效率;
  2. 对于时间序列的数据而言,要将date_time列格式化为datetime对象数组,pandas称之为时间戳,使用pd.to_datetime()函数即可简单实现;
df["dt"] = pd.to_datetime(df["dt"])

df.dtypes
type              object
id                object
amount           float64
dt        datetime64[ns]
dtype: object
  1. 特别地,如果数据源中的date_time不是ISO 8601 格式的,需要设置pd.to_datetime()中的format参数,进行格式化,否则pandas将使用dateutil 包把每个字符串str转化成date日期,速度并不是最快的,只有当date_time是ISO 8601 格式,pandas才可以立即使用最快速的方法来解析日期。

三、pandas数据的循环操作

  1. 基于上面的数据,如果需要根据amount列的值,构造一个新的列,要求:
    0 < 金额 <= 10000,返回:金额 * 0.3
    10000 < 金额 <= 100000,返回:金额 * 0.5
    100000 < 金额 <= 1000000,返回:金额 * 0.8
  2. 常规的代码做法(不赞同该做法)
def judge_amount(amount, rate):
    """计算不同投资区间的收益"""
    
    if amount >0 and amount <= 10000:
        rate = 0.3
    elif amount > 10000 and amount <= 100000:
        rate = 0.5
    elif amount > 100000 and amount <= 1000000:
        rate = 0.8
    else:
        raise ValueError(f"Invalid amount: {amount}")
    return amount * rate 
def add_judge_amount(df):
    """根据金额判断区间,为df增加新列"""
    
    add_list = []
    for i in range(len(df)):
        amt = df.iloc[i]["amount"]
        income = judge_amount(amt)
        add_list.append(income)
    df["income"] = add_list

# 打印运行时间
%timeit add_judge_amount(df)
5.59 s ± 190 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
  1. 使用itertuples() 和iterrows() 循环
def add_judge_amount_iter(df):
    """根据判断区间,为df增加新列"""
    
    add_list = []
    for index, row in df.iterrows():
        amt = row["amount"]
        income = judge_amount(amt)
        add_list.append(income)
    df["income"] = add_list

# 打印运行时间
%timeit add_judge_amount_iter(df)
2.68 s ± 8.87 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
  1. 使用apply()
# 打印运行时间
%timeit df["income"] = df["amount"].apply(lambda x: judge_amount(x))
13.5 ms ± 113 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
  1. 矢量化操作
%timeit df["income"] = df.amount * pd.cut(df.amount, bins=[0, 10000, 100000, 1000000], labels=[0.3, 0.5, 0.8]).astype("float")
2.93 ms ± 46.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
  1. 数据循环方法排名
上一篇 下一篇

猜你喜欢

热点阅读