【问题标题】:Use apply function to simpify nested for loop?使用apply函数来简化嵌套for循环?
【发布时间】:2020-06-21 17:51:56
【问题描述】:

我有一个数据框,其中包含一列值(“一”列)。对于 (product(sma1, sma2)) 给出的每一对值,我想:

  • 使用 SMA1 和 SMA2 计算 2 个简单移动平均线
  • 当满足条件 A 或 B 时,将 SMA1、SMA2 和价格的值附加到结果中

下面的代码展示了我的方法。是否可以做同样的事情来删除嵌套的 for 循环(可能使用 apply)?那会更快/更好吗?

from itertools import product 
import pandas as pd 


data = pd.DataFrame( [3,2,5,8,5,12,7,8,9,10,11,12,13,14,17,19,15,18] ,columns=['One'])
sma1 = range(2, 5)  
sma2 = range(5, 8)
results=pd.DataFrame()

for SMA1, SMA2 in product(sma1, sma2): #for each pair SMA1, SMA2, perfomr the following
    data['SMA1'] = data['One'].rolling(SMA1).mean()
    data['SMA2'] = data['One'].rolling(SMA2).mean()
    
    data.dropna(inplace=True)
    
    for i in range( len(data)):
        #Condition A:
        if data.iloc[i, 1] > data.iloc[i, 2] and data.iloc[i-1, 1] < data.iloc[i-1,2]: 
          #Buy
          price = data.iloc[i, 0]
        #Condition B
        elif data.iloc[i, 1] < data.iloc[i, 2] and data.iloc[i-1, 1] > data.iloc[i-1,2]:
          #Sell
          price = data.iloc[i, 0] 
        #if neither condition is true, dont append anything 
        else: 
          continue
          
        results = results.append(pd.DataFrame(
              {'SMA1': SMA1,
               'SMA2': SMA2,
               'price': price,
               
              },
               index=[0]), ignore_index = True)

    
results

输出:

    SMA1 SMA2   price
0   2    5      5
1   2    5      8
2   2    5      9
3   2    5      18

来自 Hugolmn 的回答中的 EIDT 我看到了使用 [i-1] 的问题。 但是,通过您的方法,我没有得到正确的答案, 我已将问题简化为仅查找 2 列是否满足条件 A、B。

data = pd.DataFrame({'col1': [3,2,6,8,6,11], 'col2': [3,3,5,8,5,12]})

#columns with shifted data
data['col1_shift']=data['col1'].shift(1)
data['col2_shift']=data['col2'].shift(1)

#condition A  
data['Con1_col1>col2'] = data['col1']>data['col2']
data['Con1_col1<col2_shift'] = data['col1_shift'] < data['col2_shift']
data['ConA'] = data['Con1_col1>col2'] & data['Con1_col1<col2_shift']

#condition B
data['Con2_col1<col2'] = data['col1']<data['col2']
data['Con2_col1>col2_shift'] = data['col1_shift'] > data['col2_shift']
data['ConB'] = data['Con2_col1<col2'] & data['Con2_col1>col2_shift']


# data['part1']= ((data.col1 - data.col2) > 0)
data['Hugolmn_method']= ((data.col1 - data.col2) >= 0).diff() > 0
data['expected']= data['ConA'] | data['ConB']

data

输出:

   col1  col2  col1_shift  col2_shift  Con1_col1>col2  Con1_col1<col2_shift  \
0     3     3         NaN         NaN           False                 False   
1     2     3         3.0         3.0           False                 False   
2     6     5         2.0         3.0            True                  True   
3     8     8         6.0         5.0           False                 False   
4     6     5         8.0         8.0            True                 False   
5    11    12         6.0         5.0           False                 False   

    ConA  Con2_col1<col2  Con2_col1>col2_shift   ConB  Hugolmn_method  \
0  False           False                 False  False           False   
1  False            True                 False  False            True   
2   True           False                 False  False            True   
3  False           False                  True  False           False
4  False           False                 False  False           False
5  False            True                  True   True            True   

   expected  
0     False  
1     False  
2      True  
3     False  
4     False  
5      True  

【问题讨论】:

  • 嗨,最好避免在 pandas 中出现手写循环。可以查看这个方法stackoverflow.com/questions/19913659/…
  • 谢谢,我不清楚 for with itertool prodcuts 是否很快?什么是更好的方法,因为我想不出一种使用“where”的方法
  • 嗨!我刚刚看到您的编辑并修改了我的答案。现在它工作正常!这只是使用&gt;= 而不是&gt; 的问题。看看吧!

标签: python pandas apply


【解决方案1】:

我检查了您的代码并提出了这些 cmets:

  • 您不需要循环来迭代数据
  • 您可以直接将 dict 附加到数据帧
  • 你的结果是错误的 price=5,它是比较索引 0 和索引 -1,所以在第一行和最后一行数据之间。这可能不是预期的行为

相反,我建议您使用.shift() 对之前的行进行测试。

data.iloc[i, 1] > data.iloc[i, 2] and data.iloc[i-1, 1] < data.iloc[i-1,2]

# would become
(data.SMA1 > data.SMA2) & (data.SMA1.shift() < data.SMA2.shift())

【讨论】:

  • 我已经更新了代码:data['Hugolmn_method']= ((data.col1 - data.col2) >= 0).diff() > 0,不幸的是这仍然没有工作,因为它在第二行失败,当第一行相等时:在它给出假之前,现在是真的。
  • 有趣的代码虽然,这是一个比以前弱的条件,但它可能是有用的!
  • 您对第一行的计算不相关:您无法与上一行进行比较。这就是我添加dropna 的原因。这样,您可以获得预期的结果,并充分尊重您的条件:)
  • 你是对的。不使用 dropna 解决了第一行的问题,但没有解决下一行的问题。我会尝试解决这个问题:)
  • 我撤回了我的解决方案。我能想到的最好的方法是使用(data.SMA1 &gt; data.SMA2) &amp; (data.SMA1.shift() &lt; data.SMA2.shift())
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-23
相关资源
最近更新 更多