Python 熊猫透视表的更快替代方案

Python 熊猫透视表的更快替代方案,python,pandas,performance,numpy,dask,Python,Pandas,Performance,Numpy,Dask,我在一个大数据集(1000万行,6列)上使用Pandaspivot\u table函数。由于执行时间是最重要的,我尝试加快这个过程。目前,处理整个数据集大约需要8秒,这是一种缓慢的方式,我希望找到其他方法来提高速度/性能 我当前的表: df_pivot = df_original.pivot_table(index="industry", columns = "months", values = ["orders", "client_name"],

我在一个大数据集(1000万行,6列)上使用Pandas
pivot\u table
函数。由于执行时间是最重要的,我尝试加快这个过程。目前,处理整个数据集大约需要8秒,这是一种缓慢的方式,我希望找到其他方法来提高速度/性能

我当前的表:

df_pivot = df_original.pivot_table(index="industry", columns = "months",
                    values = ["orders", "client_name"],
                    aggfunc ={"orders": np.sum, "client_name": pd.Series.nunique})
df_original
包含所有数据(10万行,从csv导入)。行业是客户的行业,月份是订单月份(1月至12月),订单是订单数量。除订单数量(
int
datatype)外,所有数据均转换为
category
数据。最初,行业、月份和客户名称是字符串

我试着使用
pandas.DataFrame.unstack
——速度更慢。我还尝试了
Dask
dask pivot_表
产生了一些改进(执行时间为6秒,因此减少了2秒)。然而,它仍然相当缓慢。 是否有更快的替代方案(针对大型数据集)?可能使用
groupy
crosstab
。。。不幸的是,我根本没有工作的替代品,我对Python和Pandas还是相当陌生的。。。 期待您的建议。提前谢谢

更新:

我通过以下方式找到了groupby:

df_new = df_original.groupby(["months", "industry"]).agg({"orders": np.sum, "client_name": pd.Series.nunique}).unstack(level="months").fillna(0)

现在速度要快得多,大约2-3秒。还有一些选项可以进一步提高速度吗?

将列月份和行业转换为分类列:
这样可以避免大量的字符串比较。

当您将csv文件读入df时,您可以通过convert函数(通过
read\u csv
参数)将
客户端名称
转换为哈希,并将
顺序
向下转换为适当的
int
类型,尤其是无符号类型

此函数列出了类型及其范围:

将numpy导入为np
定义列表\u np\u类型()
对于np.sctypes.items()中的k,v:
对于枚举(v)中的i,d:
如果np.dtype(d).kind在'iu'中:
#只有int和uint有一个确定的范围
fmt='{:>7},{:>2}:{:>26}来自:{:>20}\tTo:{}'
打印格式(k,i,str(d),
str(np.iinfo(d.min)),
str(np.iinfo(d.max)))
其他:
打印({:>7},{:>2}:{:>26})。格式(k,i,str(d)))
列表\u np\u类型()
输出:

    int,  0:       <class 'numpy.int8'>  From:                 -128 To: 127
    int,  1:      <class 'numpy.int16'>  From:               -32768 To: 32767
    int,  2:      <class 'numpy.int32'>  From:          -2147483648 To: 2147483647
    int,  3:      <class 'numpy.int64'>  From: -9223372036854775808 To: 9223372036854775807
   uint,  0:      <class 'numpy.uint8'>  From:                    0 To: 255
   uint,  1:     <class 'numpy.uint16'>  From:                    0 To: 65535
   uint,  2:     <class 'numpy.uint32'>  From:                    0 To: 4294967295
   uint,  3:     <class 'numpy.uint64'>  From:                    0 To: 18446744073709551615
  float,  0:    <class 'numpy.float16'>
  float,  1:    <class 'numpy.float32'>
  float,  2:    <class 'numpy.float64'>
complex,  0:  <class 'numpy.complex64'>
complex,  1: <class 'numpy.complex128'>
 others,  0:             <class 'bool'>
 others,  1:           <class 'object'>
 others,  2:            <class 'bytes'>
 others,  3:              <class 'str'>
 others,  4:       <class 'numpy.void'>
int,0:From:-128到:127
int,1:From:-32768到:32767
整数,2:From:-2147483648到:2147483647
内部,3:从:-9223372036854775808到:9223372036854775807
uint,0:从:0到:255
uint,1:从:0到:65535
uint,2:从:0到:4294967295
uint,3:从:0到:18446744073709551615
浮动,0:
浮动,1:
浮动,2:
复杂,0:
综合体,1:
其他,0:
其他,1:
其他,2:
其他,3:
其他,4:

您可以使用稀疏矩阵。它们实现起来很快,但有点受限。例如:您不能在数据库上建立索引

我最近需要训练一个重新编译系统(lightFM),它接受稀疏矩阵作为输入,这使我的工作变得容易多了。在行动中看到它:

row  = np.array([0, 3, 1, 0])
col = np.array([0, 3, 1, 2])
data = np.array([4, 5, 7, 9])
mat = sparse.coo_matrix((data, (row, col)), shape=(4, 4))

如您所见,它使用您拥有的数据的列和行自动为您创建一个透视表,并用零填充其余数据。您还可以将稀疏矩阵转换为数组和数据帧(
df=pd.dataframe.sparse.from_-spmatrix(mat,index=…,columns=…)

您的执行环境是什么?多核、群集还是一台机器?大内存,还是大量快速磁盘访问?调整性能意味着知道您可以使用哪些资源。您是对的,对不起!!单机,16GB RAM,8核(i7-8650U CPU@1.90GHz)。我在IDE中运行代码(VisualStudio代码)。理想情况下,我的模块也应该在RAM更少(例如8GB)和CPU功耗更少的机器上“快速”运行……好的,下一个问题,数据是否有序?i、 e.您能否依赖于要在数据透视中创建的拆分,以反映在基础数据中?通过对一些稍微简单的函数计时来找到期望值的下限也很有趣,只是为了看看最好的结果会是什么样子。e、 g.在不进行任何额外处理的情况下,将文件的每一行读入内存需要多长时间?数据(即,
订单数
)不排序。应该是吗?它对性能有什么帮助?我首先转换csv文件,然后将其转换为HDF5格式,以便下次使用数据集时更快地加载。我不太担心将文件的每一行读入内存。也许我误解了你的问题…我用:
df_new=df_original.groupby([“月”,“行业]).agg({“订单”:np.sum,“客户名称”:pd.Series.nunique})解堆栈(level=“months”).fillna(0)
现在大约2秒的时间就快多了。还有一些选项可以进一步提高速度吗?谢谢,我已经这样做了,执行时间大约是8秒。之前所有数据都转换为分类列,例如
df_original[“industry”]=df_original[“industry”]。astype(“category”)
做了这件事后我为什么会有TypeError,然后。reset_index()?感谢您的建议。下调到
uint
会提高速度吗?将
客户机名称
转换为哈希是什么意思?这背后的想法/改进是什么?我对
客户名称的不好
:它已经是分类的了。要下调订单,您需要知道最大值或上限是多少;我的猜测是你不应该需要
>>> print(mat)
  (0, 0)    4
  (3, 3)    5
  (1, 1)    7
  (0, 2)    9
>>> print(mat.toarray())
[[4 0 9 0]
 [0 7 0 0]
 [0 0 0 0]
 [0 0 0 5]]