Pandas 0.15的指数非常慢,为0.13.1

时间:2014-12-09 06:02:43

标签: python pandas

我每天都在工作中使用大熊猫。我最近从0.13.1升级到0.15.1,现在在迭代相对较小的DataFrame时,一堆代码太慢而无法完成。

(我意识到在DataFrame上通常有更好/更快的方法来完成迭代,但有时它非常清晰且简洁,有一个for循环结构)

我在混合类型时将问题缩小到一个问题:

def iterGet(df,col):
    for i in df.index:
        tmp = df[col].loc[i]

def iterLocSet(df,col,val):
    for i in df.index:
        #df[col].loc[i] = val
        df.loc[i,col] = val
        df.at[i,col] = val
return df

N = 100
df = pd.DataFrame(rand(N,3),columns = ['a','b','c'])

df['listCol'] = [[] for i in range(df.shape[0])]
df['strCol'] = [str(i) for i in range(df.shape[0])]
df['intCol'] = [i for i in range(df.shape[0])]
df['float64Col'] = [float64(i) for i in range(df.shape[0])]

print df.a[:5]

%time iterGet(df[['a','intCol']].copy(),'a')
%time tmpDf = iterLocSet(df[['a','intCol']].copy(),'a',0.)
print tmpDf.a[:5]

%time iterGet(df[['a','float64Col']].copy(),'a')
%time tmpDf = iterLocSet(df[['a','float64Col']].copy(),'a',0.)
print tmpDf.a[:5]

在Pandas 0.15.1上,结果是:

0    0.114738
1    0.586447
2    0.296024
3    0.446697
4    0.720984
Name: a, dtype: float64
Wall time: 6 ms
Wall time: 3.41 s
0    0
1    0
2    0
3    0
4    0
Name: a, dtype: float64
Wall time: 6 ms
Wall time: 18 ms
0    0
1    0
2    0
3    0
4    0
Name: a, dtype: float64

但是在Pandas 0.13.1上,结果如下:

0    0.651796
1    0.738661
2    0.885366
3    0.513006
4    0.846323
Name: a, dtype: float64
Wall time: 6 ms
Wall time: 14 ms
0    0
1    0
2    0
3    0
4    0
Name: a, dtype: float64
Wall time: 5 ms
Wall time: 15 ms
0    0
1    0
2    0
3    0
4    0
Name: a, dtype: float6

在Pandas 0.15.1中,使用多类型数组上的行索引进行分配似乎要慢200倍?

我知道通过分配可能是数组的副本可能存在潜在的陷阱,但我承认我也不完全理解这个问题。至少我可以看到作业正在发挥作用。 EDIT 虽然我现在看到在for循环中使用其中任何一个都可以解决问题:

df.loc[i,col] = val
df.at[i,col] = val

我不太了解诊断这一点的实施方法。任何人都可以重现这个吗?这是你所期望的吗?我究竟做错了什么? 谢谢!

1 个答案:

答案 0 :(得分:2)

即使在单一的dtyped框架上使用.loc也可以在部分分配中生成数据的副本。 (当你有对象 dtypes时,这几乎总是如此,对于数字类型则更少)。

部分分配时,我的意思是:

df.loc[1,'B'] = value

IOW。这是在这种情况下设置单个值(设置多个值类似)。但是,设置是非常不同的。

df['B'] = values
df[:,'B'] = values

效率很高,不会复制。

因此,您应该完全避免迭代,只需这样做。

df['B'] = [ ..... ]  # if you want to set with a list-like
df['B'] = value # for a scalar

因此,在上面的示例中,它可能会在每次迭代时进行复制。 0.13.1在处理部分赋值时有点麻烦,并且会错误地处理某些情况,因此需要复制一些。