【发布时间】:2015-06-09 09:48:32
【问题描述】:
我正在寻找加速我编写的函数的解决方案,该函数用于循环遍历 pandas 数据帧并比较当前行和前一行之间的列值。
例如,这是我的问题的简化版本:
User Time Col1 newcol1 newcol2 newcol3 newcol4
0 1 6 [cat, dog, goat] 0 0 0 0
1 1 6 [cat, sheep] 0 0 0 0
2 1 12 [sheep, goat] 0 0 0 0
3 2 3 [cat, lion] 0 0 0 0
4 2 5 [fish, goat, lemur] 0 0 0 0
5 3 9 [cat, dog] 0 0 0 0
6 4 4 [dog, goat] 0 0 0 0
7 4 11 [cat] 0 0 0 0
目前我有一个函数可以循环并根据“User”自上一行以来是否发生变化以及“newcol1”和“newcol2”的值'Time' 值大于 1。它还会查看存储在 'Col1' 和 'Col2' 中的数组中的第一个值,如果这些值更新 'newcol3' 和 'newcol4'与上一行相比发生了变化。
这是我目前正在做的事情的伪代码(因为我已经简化了问题,所以我没有对此进行测试,但它与我在 ipython notebook 中实际做的事情非常相似):
def myJFunc(df):
... #initialize jnum counter
... jnum = 0;
... #loop through each row of dataframe (not including the first/zeroeth)
... for i in range(1,len(df)):
... #has user changed?
... if df.User.loc[i] == df.User.loc[i-1]:
... #has time increased by more than 1 (hour)?
... if abs(df.Time.loc[i]-df.Time.loc[i-1])>1:
... #update new columns
... df['newcol2'].loc[i-1] = 1;
... df['newcol1'].loc[i] = 1;
... #increase jnum
... jnum += 1;
... #has content changed?
... if df.Col1.loc[i][0] != df.Col1.loc[i-1][0]:
... #record this change
... df['newcol4'].loc[i-1] = [df.Col1.loc[i-1][0], df.Col2.loc[i][0]];
... #different user?
... elif df.User.loc[i] != df.User.loc[i-1]:
... #update new columns
... df['newcol1'].loc[i] = 1;
... df['newcol2'].loc[i-1] = 1;
... #store jnum elsewhere (code not included here) and reset jnum
... jnum = 1;
我现在需要将此函数应用于数百万行,而且速度非常慢,因此我正在尝试找出加速它的最佳方法。我听说 Cython 可以提高函数的速度,但我没有这方面的经验(而且我对 pandas 和 python 都是新手)。是否可以将数据帧的两行作为参数传递给函数,然后使用 Cython 来加速它,或者是否有必要创建带有“diff”值的新列,以便函数只读取和写入一次到一行数据帧,以便从使用 Cython 中受益?任何其他速度技巧将不胜感激!
(至于使用 .loc,我比较了 .loc、.iloc 和 .ix,这个稍微快一点,所以这是我目前使用它的唯一原因)
(另外,我的 User 列实际上是 unicode 而不是 int,这对于快速比较可能会有问题)
【问题讨论】:
-
拥有一百万行,为什么不使用 Python 可以轻松连接的专用数据库,例如 MySQL 或 SQLlite?关系数据库可以使用 if/then 逻辑运行复杂的 SQL 查询,用于通过索引连接的行间比较。它们旨在扩展到数百万行。甚至可以设置触发器,因此可以在任何用户更改时更新特定列。
标签: python performance pandas bigdata cython