假设这是我的 Dataframe :
id c1 c3 c5 c7
1 10 11 12 13
2 10 14 11 13
3 15 14 12 10
我想将每列与每行的下一列进行比较。
如果c1〉c3且c3〉c5,以此类推,则该行的结果为1,如果c1〈c3且c3〈c5,以此类推,则该行的结果为-1,否则结果应为0。
这可以通过一个简单的循环来完成,如下所示:
number_of_rows = df.shape(0)
for i in range(0, number_of_rows):
if df[i, c1] < df[i, c3] and df[i, c3] < df[i, c5] and df[i, c5] < df[i, c7]:
df[i, 'result'] = -1
elif df[i, c1] > df[i, c3] and df[i, c3] > df[i, c5] and df[i, c5] > df[i, c7]:
df[i, 'result'] = 1
else:
df[i, 'result'] = 0
预期结果应该是这样的 Dataframe :
id result
1 1
2 0
3 -1
我觉得一定有更快/更干净的方法来做到这一点,使用Pandas功能。
另外,我不确定这是否有帮助,但如您所见,列名具有一种模式
4条答案
按热度按时间lp0sw83n1#
可以使用
df.diff
查看增量/减量:zmeyuzjn2#
输出:
htrmnn0y3#
简单的单线解决方案
输出:-
hk8txs484#
TL;医生:
永远不要迭代行。这是Pandas的第一条规则。
python是一种非常慢的语言,它之所以也是目前最流行的语言,以及许多非常快的应用程序都是用python编写的,是因为python程序员会尽一切努力使耗时的代码不在python中。
而这样做的方法是使用panda和numpy这样的库,这些库不是用python写的,来做繁重的计算。在处理大量数据的情况下,耗时的代码是你应用在一个大 Dataframe 的所有行上的代码;因此您使用一个库,它将对所有行执行迭代,并为您对每一行执行计算。
如果你使用pandom但仍然自己迭代行,你就错过了重点,在这种情况下,你最好简单地使用python列表或字典。
请注意,apply也是如此:这只是下一件不要做的事情。自己编写for循环仍然更好,因为至少for循环是在Pandas代码内部编写的,但仍然,你在每一行上所做的仍然是Python代码。
所以,在你的例子中,你必须找到一种方法来批量计算整列(注意,我假设你的行数比列数多......不像你的例子, Dataframe 通常是这样)。
例如,
df.c1 > df.c3
计算布尔值数组你可以把这些结合起来,得到你想要的东西
一些计时注意事项
对于只有3行的情况,批处理计算的开销使得基于for循环的(您的解决方案)仍然更快。
但是对于更大的行数会显示差异。请参见下表
| 方法|定时3行|1000行|10k行|10万行|1个月|10个月|
| - ------|- ------|- ------|- ------|- ------|- ------|- ------|
| 您的(用于循环)|1.3毫秒|394毫秒|3808毫秒|38400毫秒|||
| 金藻(agg)|2.4毫秒|140毫秒|1290毫秒|13800毫秒|||
| Nehal's(适用)|1.0毫秒|71毫秒|695毫秒|6930毫秒|||
| 安基的|2.6毫秒|2.8毫秒|4.2毫秒|18毫秒|220毫秒|2300毫秒|
| 我的(df ['c1 ']〉df ['c3']...)|2.0毫秒|2.0毫秒|2.2毫秒|7.5毫秒|33毫秒|400毫秒|
| 我的第二个(变量编号列)|2.8毫秒|2.9毫秒|3.2毫秒|9.4毫秒|52毫秒|480毫秒|
注意,394/1.3等于303,所以行比几乎等于333,你的解是O(n),它已经显示出来了。
Chrysophylax(和其他基于lambda的解决方案)已经更快了。因为它节省了python for循环本身,但没有节省在for循环中所做的纯python执行。同样,panda中最糟糕的错误是迭代for循环。第二糟糕的错误是使用lambda。如果n足够大,你会从它那里得到3倍的增益。
我的解决方案,以及其他非for、非基于lambda的解决方案也是O(n)-没有免费餐,任何方法,无论是否基于Pandas,在每一行上计算的东西都必须至少为O但即使在n = 10000时,它也不会显示出来,因为它太快了,即使在n = 10000时,它仍然是我们所支付的开销,计算本身仍然可以忽略不计。对于n = 100000,时间仍然只有7. 5 ms(它终于开始增加,但仍然不成比例)。
因此,对于足够大的数据,增益至少为× 5000。
编辑:我在anky的解决方案发布之前写了这篇文章。注意,他们的解决方案也避免了for和lambda,所以它有同样的时间因素。当n = 100000时,他们的代码在我的计算机上运行一次需要18毫秒。当然,这比我的7.5毫秒要慢。但数量级是一样的。另外,他们的解决方案比我的解决方案有一个重要的优势:它可以在不涉及任何列数的代码的情况下工作(对于我的代码,您必须向代码中添加一些
& (df.c7 > df.c9)
才能添加c9
列)编辑(回复您的评论):
如果列数是可变的,你可以使用Anky的解,在这种情况下是有效的。
或者修改我的,在列上进行迭代
它比我之前的答案稍微慢了一点,但是它仍然比任何其他的解决方案都快(包括,我必须承认,我没有预料到,Anky的)。我已经更新了时间表来添加它。
(Note我习惯使用
itertools
,但这与性能无关。列的迭代对于正常使用来说是可以忽略的。因此,您还可以使用更传统的索引进行迭代,例如在这种情况下,更多的是出于美学考虑而不是性能考虑)