Pandas: 需要一种更快的索引切片方式
Pandas: Need a speedier way of index slicing
有人愿意尝试加速这个数据帧索引切片方案吗?
我正在尝试对一些巨大的数据帧进行切片和切块,所以每一位都很重要。除了以下技术之外,我需要以某种方式找到一种更快的索引切片数据帧的方法:
v = initFrame.xs(x,level=('ifoo2','ifoo3'), drop_level=False)
pd.unique 中的循环也对性能产生了相当大的影响。
uniqueList = list(pd.unique(initFrame[['bar1','bar4']].values))
复制并粘贴以下代码片段以避免设置。
import pandas as pd
foo1 = (['LABEL1','LABEL1','LABEL2','LABEL2'])
foo2 = ([5,5,6,6])
foo3 = ([1,1,2,3])
index = pd.MultiIndex.from_arrays([foo1,foo2,foo3], names=['ifoo1','ifoo2','ifoo3'])
initFrame = pd.DataFrame({'bar1': [ 5,6,5,6],
'bar2': ['a','b','c','d'],
'bar3': [11,22,33,44],
'bar4': [1,2,1,3]}, index=index)
finDict = {}
#start timer1
uniqueList = list(pd.unique(initFrame[['bar1','bar4']].values))
#end timer1
for x in uniqueList:
#start timer2
v = initFrame.xs(x,level=('ifoo2','ifoo3'), drop_level=False)
#stop timer2
k = int(x[0]), int(x[1])
finDict.update({k:v})
更新 2016-04-04
对于那些感兴趣的人,我最终使用了以下内容:
finDict = {}
grouper = initFrame.groupby(level=('ifoo2', 'ifoo3'))
for name, group in grouper:
finDict.update({name:group})
您可以结合使用字典理解和 loc
来进行数据帧索引:
finDict = {pair: df.loc[pd.IndexSlice[:, pair[0], pair[1]], :]
for pair in pd.unique(initFrame[['bar1', 'bar4']].values).tolist()}
>>> finDict
{(5, 1): bar1 bar2 bar3 bar4
ifoo1 ifoo2 ifoo3
LABEL1 5 1 5 a 11 1
1 6 b 22 2,
(6, 2): bar1 bar2 bar3 bar4
ifoo1 ifoo2 ifoo3
LABEL2 6 2 5 c 33 1,
(6, 3): bar1 bar2 bar3 bar4
ifoo1 ifoo2 ifoo3
LABEL2 6 3 6 d 44 3}
我不知道你真正想做什么,但这里有一些提示可以加速你的代码:
改变
uniqueList = list(pd.unique(initFrame[['bar1','bar4']].values))
至
uniqueList = initFrame[["bar1", "bar4"]].drop_duplicates().values.tolist()
和 for 循环到 :
g = initFrame.groupby(level=(1, 2))
uniqueSet = set(uniqueList)
dict((key, df) for key, df in g if key in uniqueSet)
或:
g = initFrame.groupby(level=(1, 2))
dict((key, g.get_group(key)) for key in uniqueList)
这是 %timeit 比较:
import numpy as np
import pandas as pd
arr = np.random.randint(0, 10, (10000, 2))
df = pd.DataFrame(arr, columns=("A", "B"))
%timeit df.drop_duplicates().values.tolist()
%timeit list(pd.unique(arr))
输出:
100 loops, best of 3: 3.51 ms per loop
10 loops, best of 3: 94.7 ms per loop
不是作为答案,而是只是为了形象化我的评论的想法,因为多索引被分组,我们可以简单地并且可能只是比较并跳过循环如果 ('bar1', 'bar4') 等于之前的值,然后执行dict update.
它可能不会更快,但如果你的数据集很大,它可能会为你节省内存消耗问题,伪代码:
# ...replace timer1...
prev, finDict = None, {}
for n in initFrame[['bar1', 'bar4']].iterrows():
current = (n[0][1], n[0][2])
if current == prev: continue
prev = current
#... whatever faster way to solve your 2nd timer...
我个人认为@Alexander 很好地回答了您的第二个计时器。
有人愿意尝试加速这个数据帧索引切片方案吗? 我正在尝试对一些巨大的数据帧进行切片和切块,所以每一位都很重要。除了以下技术之外,我需要以某种方式找到一种更快的索引切片数据帧的方法:
v = initFrame.xs(x,level=('ifoo2','ifoo3'), drop_level=False)
pd.unique 中的循环也对性能产生了相当大的影响。
uniqueList = list(pd.unique(initFrame[['bar1','bar4']].values))
复制并粘贴以下代码片段以避免设置。
import pandas as pd
foo1 = (['LABEL1','LABEL1','LABEL2','LABEL2'])
foo2 = ([5,5,6,6])
foo3 = ([1,1,2,3])
index = pd.MultiIndex.from_arrays([foo1,foo2,foo3], names=['ifoo1','ifoo2','ifoo3'])
initFrame = pd.DataFrame({'bar1': [ 5,6,5,6],
'bar2': ['a','b','c','d'],
'bar3': [11,22,33,44],
'bar4': [1,2,1,3]}, index=index)
finDict = {}
#start timer1
uniqueList = list(pd.unique(initFrame[['bar1','bar4']].values))
#end timer1
for x in uniqueList:
#start timer2
v = initFrame.xs(x,level=('ifoo2','ifoo3'), drop_level=False)
#stop timer2
k = int(x[0]), int(x[1])
finDict.update({k:v})
更新 2016-04-04
对于那些感兴趣的人,我最终使用了以下内容:
finDict = {}
grouper = initFrame.groupby(level=('ifoo2', 'ifoo3'))
for name, group in grouper:
finDict.update({name:group})
您可以结合使用字典理解和 loc
来进行数据帧索引:
finDict = {pair: df.loc[pd.IndexSlice[:, pair[0], pair[1]], :]
for pair in pd.unique(initFrame[['bar1', 'bar4']].values).tolist()}
>>> finDict
{(5, 1): bar1 bar2 bar3 bar4
ifoo1 ifoo2 ifoo3
LABEL1 5 1 5 a 11 1
1 6 b 22 2,
(6, 2): bar1 bar2 bar3 bar4
ifoo1 ifoo2 ifoo3
LABEL2 6 2 5 c 33 1,
(6, 3): bar1 bar2 bar3 bar4
ifoo1 ifoo2 ifoo3
LABEL2 6 3 6 d 44 3}
我不知道你真正想做什么,但这里有一些提示可以加速你的代码:
改变
uniqueList = list(pd.unique(initFrame[['bar1','bar4']].values))
至
uniqueList = initFrame[["bar1", "bar4"]].drop_duplicates().values.tolist()
和 for 循环到 :
g = initFrame.groupby(level=(1, 2))
uniqueSet = set(uniqueList)
dict((key, df) for key, df in g if key in uniqueSet)
或:
g = initFrame.groupby(level=(1, 2))
dict((key, g.get_group(key)) for key in uniqueList)
这是 %timeit 比较:
import numpy as np
import pandas as pd
arr = np.random.randint(0, 10, (10000, 2))
df = pd.DataFrame(arr, columns=("A", "B"))
%timeit df.drop_duplicates().values.tolist()
%timeit list(pd.unique(arr))
输出:
100 loops, best of 3: 3.51 ms per loop
10 loops, best of 3: 94.7 ms per loop
不是作为答案,而是只是为了形象化我的评论的想法,因为多索引被分组,我们可以简单地并且可能只是比较并跳过循环如果 ('bar1', 'bar4') 等于之前的值,然后执行dict update.
它可能不会更快,但如果你的数据集很大,它可能会为你节省内存消耗问题,伪代码:
# ...replace timer1...
prev, finDict = None, {}
for n in initFrame[['bar1', 'bar4']].iterrows():
current = (n[0][1], n[0][2])
if current == prev: continue
prev = current
#... whatever faster way to solve your 2nd timer...
我个人认为@Alexander 很好地回答了您的第二个计时器。