【问题标题】:How to write code in a vectorized way instead of using loops?如何以矢量化方式编写代码而不是使用循环?
【发布时间】:2017-06-22 15:04:58
【问题描述】:

我想以矢量化方式编写以下代码,因为当前代码非常慢(并且想学习 Python 最佳实践)。基本上,代码是说如果今天的值在昨天值的 10% 以内,那么今天的值(在新列中)与昨天的值相同。否则,今天的值不变:

def test(df):
    df['OldCol']=(100,115,101,100,99,70,72,75,78,80,110)
    df['NewCol']=df['OldCol']
    for i in range(1,len(df)-1):
        if df['OldCol'][i]/df['OldCol'][i-1]>0.9 and df['OldCol'][i]/df['OldCol'][i-1]<1.1:
            df['NewCol'][i]=df['NewCol'][i-1]
        else:
            df['NewCol'][i]=df['OldCol'][i]
    return df['NewCol']

输出应该如下:

    OldCol  NewCol
0      100     100
1      115     115
2      101     101
3      100     101
4       99     101
5       70      70
6       72      70
7       75      70
8       78      70
9       80      70
10     110     110

你能帮忙吗?

我想使用这样的东西,但我没有设法解决我的问题:

def test(df):
    df['NewCol']=df['OldCol']
    cond=np.where((df['OldCol'].shift(1)/df['OldCol']>0.9) & (df['OldCol'].shift(1)/df['OldCol']<1.1))
    df['NewCol'][cond[0]]=df['NewCol'][cond[0]-1]     
    return df     

【问题讨论】:

  • df 是一个数据框,对吧? df['OldCol'] 中的 dtype 或“NewCol”是什么?我认为这更像是一个很好的 pandas 编码问题,而不是 Pythonic 问题。
  • OldCol = (100,115,101,100,99,70,72,75,78,80,81,82,110) 的期望结果是什么?

标签: python loops numpy vectorization


【解决方案1】:

三步解决方案:

df['variation']=(df.OldCol/df.OldCol.shift())
df['gap']=~df.variation.between(0.9,1.1)
df['NewCol']=df.OldCol.where(df.gap).fillna(method='ffill')

对于:

    OldCol  variation    gap  NewCol
0      100        nan   True     100
1      115       1.15   True     115
2      101       0.88   True     101
3      100       0.99  False     101
4       99       0.99  False     101
5       70       0.71   True      70
6       72       1.03  False      70
7       75       1.04  False      70
8       78       1.04  False      70
9       80       1.03  False      70
10     110       1.38   True     110

在这个例子中,它似乎比循环快 30 倍。

一行:

x=df.OldCol;df['NewCol']=x.where(~(x/x.shift()).between(0.9,1.1)).fillna(method='ffill')

【讨论】:

  • 这正是我所需要的——非常感谢
【解决方案2】:

您应该对原始数据框进行布尔掩码:

df[(0.9 &lt;= df['NewCol']/df['OldCol']) &amp; (df['NewCol']/df['OldCol'] &lt;= 1.1)] 将提供NewColOldCol 10% 以内的所有行

所以要在这些行中设置NewCol 字段:

within_10 = df[(0.9 <= df['NewCol']/df['OldCol']) & (df['NewCol']/df['OldCol'] <= 1.1)]
within_10['NewCol'] = within_10['OldCol']

【讨论】:

    【解决方案3】:

    由于您自己似乎在寻找“跳跃”日子的好方法,所以我只会展示更棘手的部分。所以让我们假设你有一个长度为Nold 的numpy 数组和一个相同大小的布尔numpy 数组jump。按照惯例,jump 的第零个元素设置为True。然后你可以先计算跳跃之间的重复次数:

    jump_indices = np.where(jumps)[0]
    repeats = np.diff(np.r_[jump_indices, [N]])
    

    一旦你有了这些,你就可以使用np.repeat:

    new = np.repeat(old[jump_indices], repeats)
    

    【讨论】:

      猜你喜欢
      • 2015-12-08
      • 2013-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-11
      • 2019-09-08
      • 1970-01-01
      • 2017-01-04
      相关资源
      最近更新 更多