在利用pandas进行数据分析时,DataFrame是其基本的数据结构,当数据量较小时还好,一旦数据量较大,比如几十万上百万时,这时DataFrame就会变得笨重,笨重主要体现在对其索引的操作上,而对DataFrame的索引操作又是基本的操作,所以这时,在性能上就会有很大的损失;对pandas的使用可以让我们可以直观简单的进行数据分析,但是往往会在性能上有较大的损失。当然,对于性能的损失不能一概而论,pandas具有很多的内置函数,这些函数的底层很多是c语言的python封装,如果我们可以灵活的使用这些内置函数,那么性能上的损失其实是很小的,甚至会提升性能,只是有时候在一些比较复杂的操作中,并没有对应的内置函数供我们直接调用,这时,就需要从其他的角度去考虑提升性能。

性能对比和分析

在数据分析中,往往最消耗时间的是在loop上,一旦数据量较大,比如一个50万行的DataFrame,如果我们需要进行逐行的loop,那么时间的消耗就相当于是一个loop的50万倍,这种量级的放大是很恐怖的,所以,当我们要不可避免的使用loop的时候,就需要非常的谨慎,尽量的减少一个loop需要消耗的时间。

在pandas中,一个loop中比较消耗时间的地方往往有两方面:一是对很少的数据量用pandas的内置函数,起步时间消耗过多,对此可以转而用python原生的方式实现,具体可以看笔者的 这篇文章 ;二是对DataFrame的索引操作上。本文就是解决第二个问题带来的时间消耗。

pandas中对于DataFrame的索引操作是相对低效的,所以我们不应该在一个几十万的循环中使用DataFrame的索引操作,否则会造成程序效率极其低下。为了保持DataFrame的这种数据的相对结构,我们可以有两种方式去替换DataFrame的频繁的索引操作:一,替换成numpy的ndarray;二,替换成python的字典数据结构。下面我们通过一个简单的例子来对比下这三种方式的效率,如下所示。

import time
import pandas as pd
import numpy as np
df=pd.DataFrame(np.arange(800000).reshape(200000,4),columns=list('abcd'))
t1=time.time()
s1=df.apply(lambda x:x['a']+x['d'],axis=1)
t2=time.time()
print(t2-t1)
arr=df.values
t3=time.time()
s=np.apply_along_axis(lambda x:x[0]+x[3],axis=1,arr=arr)
t4=time.time()
print(t4-t3)
dic=df.to_dict()
t5=time.time()
for i in range(len(df)):
    l.append(dic['a'][i]+dic['d'][i])
t6=time.time()
print(t6-t5)
# output: 10.034282922744751
#         1.6413774490356445
#         0.11075925827026367

上述例子仅仅只是一个例子,只是为了传达本文的思想而已,因为实际上可以完全可以通过df[['a','d']].sum(axis=1)函数来快速实现。从例子中我们可以看到,三种方式的运行效率相差很大。首先第一种方式,我们是直接利用DataFrame的apply方法实现逐行的loop,对于每一个loop,通过直接对Series的索引来实现两列的相加;第二种方式,我们是先将DatFrame转为ndarray,然后在numpy中采取类似的做法;第三种方式,我们先将DataFrame转为python的字典对象,然后通过for loop实现,内一个loop中直接通过字典索引实现两列的相加。

通过对比,第一种和第二种方式之间,后者相当于把DataFrame转为numpy的ndarray再进行处理,可知numpy的ndarray的效率更高,虽然pandas也是基于numpy的,但是由于pandas进行了进一步的封装,所以效率自然更低,因此,我们总是可以用numpy来处理比较耗时的pandas任务,特别是在数据量很大的时候,且无法通过内置函数直接办到的任务,那么numpy提升的效率可以很显著。我们再看第一种和第三种方式的对比,后者是先把DataFrame先转为字典,然后通过for loop实现,这里两者的区别还在于前者是apply,后者是for loop,但其实apply和for loop在非内置函数的简单操作上的效率是差不多的,甚至apply会更慢些,但是在pandas内置函数的操作上apply会快很多,具体可看笔者的 这篇文章 ;所以这里两者的差距我们可以认为是由索引造成的,明显的,字典索引相对于DataFrame的索引,前者的效率会高很多,在python中,字典索引几乎是最为高效的索引方式了,因此,我们把DataFrame转为字典并对字典进行操作,这种方式提升的效率效果是最好的,性能几乎提升近百倍!

内存占用分析

上面只是单纯的从性能上进行分析对比,下面还要对比一下这三种方式在内存占用上的区别。首先,对于DataFrame和ndarray,由于前者是基于后者的,因此两者的内存占用其实是产不多的,而且由于前者对后者进行了封装,所以严格来讲,DataFrame的内存占用会大一些,ndarray的内存占用会小一些,但是差别不大。由于ndarray是对内存结构进行了优化的,所以相比于python的字典对象,储存相同的信息,字典对象的内存占用会大很多,当然,这并不是说就是字典对象的缺点,因为字典对象可以存储不同类型的对象,而ndarray只可以存储同一类型的元素,因此,不同的设计方式使得两者在内存占用上不太一样,各有优劣。但是当我们通过把DataFrame转为dict时,相比于DataFrame,dict可储存多类型对象的优势不再,这时dict对象显著变大了,这就是其一个缺点了。具体的可看如下结果。

import sys
size=total_size(dic)
print(sys.getsizeof(df))
print(arr.nbytes)
print(size)
# output: 3200104
#         3200000
#         86715124

可以看到,df占据了3200104字节,arr占据了3200000字节,而dic则占据了86715124字节。这里对于arr和dic不能直接用sys.getsizeof获取其实际内存,因为sys.getsizeof只能获取对象的本身的内存,如果对象是个容器,容器内部的内容内存占用是无法获取到的;字典实际上是个容器,而ndarray又有自己的内存设计,可以通过其nbytes属性获取,而df则兼容了sys.getsizeof这个接口。所以这里对于dic,笔者用的是total_size这个函数,关于该函数的定义,可以查看笔者的 这篇文章

Anyway,最后我们看到的是,字典占据的内存暴涨,相当于是df和ndarray的二十多倍。虽然字典在访问速度上极快,但是内存占用也是极高的,典型的用空间换时间。所以,当我们考虑性能的时候,也要兼考虑内存占用,特别是在大数据量的情况下,如果我们盲目的将df转为字典,那么可能内存就承受不住了。所以如果内存充分的足够,那么可以转为字典,但是如果内存并不是那么充裕,那么我们可以采用转为ndarray的方式去提高性能,因为ndarray的内存占用是三者里最佳的,而且在性能上也是很不错的,因此,在大数据量的情形下,考虑到内存占用,ndarray往往是一个更佳的选择!

在利用pandas进行数据分析时,DataFrame是其基本的数据结构,当数据量较小时还好,一旦数据量较大,比如几十万上百万时,这时DataFrame就会变得笨重,笨重主要体现在对其索引的操作上,而对DataFrame的索引操作又是基本的操作,所以这时,在性能上就会有很大的损失;对pandas的使用可以让我们可以直观简单的进行数据分析,但是往往会在性能上有较大的损失。当然,对于性能的... Pandas 和 NumPy 被认为是科学计算与机器学习中必不可少的库,因为它们具有直观的语法和高 性能 的矩阵计算能力。下面对 Pandas 与 NumPy 进行简单的总结,如下表所示: Pandas NumPy Pandas 主要用来处理类表格数据。 NumPy 主要用来处理数值数据。 Pandas 提供了Series和 DataFrame 数据结构。 NumPy 构建了 ndarray array来容纳数据。 Pandas
今天是 pandas 数据处理专题的第四篇文章,我们一起来聊聊 DataFrame 中的 索引 。 上一篇文章当中我们介绍了 DataFrame 数据结构当中一些常用的 索引 的使用方法,比如iloc、loc以及逻辑 索引 等等。今天的文章我们来看看 DataFrame 的一些基本运算。 我们可以计算两个 DataFrame 的加和, pandas 会自动将这两个 DataFrame 进行数据对齐,如果对不上的数据会被置为Nan(not a number)。 首先我们来创建两个 DataFrame : import numpy
在Excel进行表表运算时,特别是以某表文本字段为关键字,查询另一表文本,即进行vlookup操作时,经常出现两边数据的不匹配。特别是如果数据量足够大,将产生较多的问题。 上述操作实际上是两集合的运算问题。解决办法有很多,就 Pandas 中,就可以以merge功能处理。但本文用 Pandas 的Index集合操作,可以更好理解 Pandas 的高效功能。 1、实验数据 import pandas as pd a = ['王三','王五','刘一','刘八','林二'] b = ['王六','王五','刘三' Python正迅速成为数据科学家偏爱的语言,这合情合理。它拥有作为一种编程语言广阔的生态环境以及众多优秀的科学计算库。如果你刚开始学习Python,可以先了解一下Python的学习路线。 在众多的科学计算库中,我认为 Pandas 对数据科学运算最有用。 Pandas ,加上Scikit-lear
读取文件数据时通常得到的是 dataframe 格式的,如通过pd.read_csv。有时需要将 dataframe 格式的数据转换成 ndarray 的数组形式。 ndarray :NumPy中的 ndarray 是一个多维数组对象,里面的数组多是同质的。 Dataframe : pandas 中处理数据的二维数组表结构。优势在于可以方便地处理不同类型的列。 ndarray Dataframe : 直接用pd. Dataframe ,如dataDf=pd. DataFrame (np.arange(12).re...
numpy. ndarray 类似 字典 操作方法 假如,b和c是一一对应关系,则输入 a这个key值,可以通过b位置,对应的找到c位置 a = np.asarray(["8002"]) b = np.asarray(["8000","8001","8002","8003"]) c = np.asarray([1,2,3,4]) print (a == b) print (c[a == b]) re...
ndim: 数组的秩(纬度),一维为1,二维为2 shape: 数组的类型,为元组格式,示例:二行三列的数组为(2,3) size: 数组中元素的个数 itemsize 1. 导入所需的库:import pandas as pd 2. 创建一个 DataFrame :df = pd. DataFrame ({'A': [1, 2, 3], 'B': [4, 5, 6]}) 3. 创建一个 ndarray 数组:new_col = np.array([7, 8, 9]) 4. 用新的 ndarray 数组 替换 DataFrame 中的一列:df['A'] = new_col 以上步骤中,我们首先导入了 pandas 库,然后使用 DataFrame 函数创建了一个包含两列的 DataFrame 对象df。接下来,我们创建了一个 ndarray 数组new_col,并将其赋值给 DataFrame df的列'A',从而实现 替换 操作。 ### 回答3: 要用 ndarray 替换 dataframe 数组的一列,可以通过以下步骤: 1. 先将 ndarray 转换为 pandas 的Series对象。可以使用 pandas 的Series函数来创建Series对象,将 ndarray 作为参数传入。例如,如果要 替换 的列是df的"column_name"列, ndarray 是arr,可以使用以下代码创建Series对象:s = pd.Series(arr)。 2. 接下来,可以使用 dataframe 的赋值操作来 替换 特定的列。将新创建的Series对象赋值给 dataframe 的相应列即可。例如,如果要将s 替换 dataframe df中的"column_name"列,可以使用以下代码:df["column_name"] = s。 3. 最后,检查结果是否如预期 替换 成功。可以打印 dataframe 的特定列来查看。 综上所述,通过将 ndarray 转换为 pandas 的Series对象,并使用 dataframe 的赋值操作,可以简单地实现 ndarray 替换 dataframe 数组的一列。 pandas.errors.ParserError: Error tokenizing data. C error: EOF inside string starting at row 56789 weixin_50025932: 但是这个读出来的数据都是str类型? pandas中对nan空值的判断和陷阱 宝气不加班: 感谢分享 非常有用 在DataFrame中新建列赋值后全部为NaN的问题释疑 baidu_41917922: 遇到同样问题,谢谢 ! 运行pip命令时发生ssl module in Python is not available错误 自学中,感谢作者 运行pip命令时发生ssl module in Python is not available错误 感谢感谢!本来都快要放弃了。您的方法奏效👍