【问题标题】:Is there a more efficient method than apply(), to check and replace row values in a Pandas Dataframe?是否有比 apply() 更有效的方法来检查和替换 Pandas Dataframe 中的行值?
【发布时间】:2021-11-12 18:14:36
【问题描述】:

我在我的 Dataframe 上运行下面的函数,如果日期与出现警报 ('Y') 的日期相同,则 'tdelta' 列中的数字应替换为 250。

这是原来的df:

   reset category       date     id  group  tdelta  tdelta reverse
6      N      low 2021-06-23  16860    2.0    33.0             0.0
5      Y      low 2021-05-21  16860    2.0     0.0           -33.0
10     N   medium 2020-12-06   1111    1.0    29.0             0.0
1      Y      low 2020-12-06  16860    1.0     0.0             0.0
2      N      low 2020-12-06  16860    1.0     0.0             0.0
8      Y   medium 2020-11-07   1111    1.0     0.0           -29.0
9      N   medium 2020-11-07   1111    1.0     0.0           -29.0
4      N      low 2019-11-08  16860    0.0    65.0             0.0
3      N      low 2019-09-07  16860    0.0     3.0           -62.0
7      N   medium 2019-09-04   1111    0.0     0.0             0.0

这是代码和结果输出:

def format(row):

    r_dates = df[(df['id'] == row['id']) & (df['reset'] == 'Y')]['date']
    r_dates = r_dates.tolist()

    if row['date'] in r_dates:
        val = 250
    else:
        val = row['tdelta']
    
    return val


df['tdelta'] = df.apply(format, axis =1)

print(df)

   reset category       date     id  group  tdelta  tdelta reverse
6      N      low 2021-06-23  16860    2.0    33.0             0.0
5      Y      low 2021-05-21  16860    2.0   250.0           -33.0
10     N   medium 2020-12-06   1111    1.0    29.0             0.0
1      Y      low 2020-12-06  16860    1.0   250.0             0.0
2      N      low 2020-12-06  16860    1.0   250.0             0.0
8      Y   medium 2020-11-07   1111    1.0   250.0           -29.0
9      N   medium 2020-11-07   1111    1.0   250.0           -29.0
4      N      low 2019-11-08  16860    0.0    65.0             0.0
3      N      low 2019-09-07  16860    0.0     3.0           -62.0
7      N   medium 2019-09-04   1111    0.0     0.0             0.0
0      N      low 2019-09-04  16860    0.0     0.0           -65.0

但是,当我应用这个非更大的数据集(大约 200k 行)时,它似乎需要很长时间。我想知道是否有更有效的实用方法来完成上述代码。

编辑:

我更改了“id”列中的一些 id,以反映不同 id 会发生什么。

还必须考虑 id 列,因为在更大的数据集中(id 列中有不同的 id),这些 id 有唯一的重置日期。

因此,我需要计算该 ID 的所有“Y”重置。

问题是会有其他 id 可能与另一个 id 的警报在同一日期,但是,这些不应该改变,如第三行(索引 10)所示,其中日期相同与 id 16860 相同,但由于该 id 不在该日期的警报,因此保持不变。

尝试后:

r_id = df[df['reset'] == 'Y']['id']
r_dates = df[df['reset'] == 'Y']['date']

df['tdelta'] = np.where((df['id'].isin(r_id) & df['date'].isin(r_dates)),250,df['tdelta'])

下面显示了一个不正确的输出:

   reset category       date     id  group  tdelta  tdelta reverse
6      N      low 2021-06-23  16860    2.0    33.0             0.0
5      Y      low 2021-05-21  16860    2.0   250.0           -33.0
10     N   medium 2020-12-06   1111    1.0   250.0             0.0
1      Y      low 2020-12-06  16860    1.0   250.0             0.0
2      N      low 2020-12-06  16860    1.0   250.0             0.0
8      Y   medium 2020-11-07   1111    1.0   250.0           -29.0
9      N   medium 2020-11-07   1111    1.0   250.0           -29.0
4      N      low 2019-11-08  16860    0.0    65.0             0.0
3      N      low 2019-09-07  16860    0.0     3.0           -62.0
7      N   medium 2019-09-04   1111    0.0     0.0             0.0
0      N      low 2019-09-04  16860    0.0     0.0           -65.0

【问题讨论】:

  • 试过 numpy.where 吗?

标签: python pandas dataframe numpy time-series


【解决方案1】:

apply() 的时间安排:

In: %timeit df['tdelta'] = df.apply(format, axis =1)
Out: 11.3 ms ± 470 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

我上次测量 apply 时没有

df['id'] == row['id']

我的错,现在我明白它的用途了。

为了加快速度,我们需要 2 个列表:

r_id = df[df['reset'] == 'Y']['id']
r_dates = df[df['reset'] == 'Y']['date']

更新了 numpy.where:

df['tdelta'] = np.where((df['id'].isin(r_id) & df['date'].isin(r_dates)),250,df['tdelta'])

生成这些列表中的每一个大约是每个 np.where 时间的一半,全部加在一起(生成列表和 numpy where:)

1.63 ms ± 110 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

示例 df:

df = pd.DataFrame({'id':[223, 227, 2214, 2215, 226, 2215, 2215, 238, 253],
    'reset':['N','Y','N','Y','N','Y','N','Y','Y'],
                   'date':[3, 7, 15, 16, 15, 15, 15, 38, 53],
                   'tdelta':[3, 7, 14, 15, 17, 26, 32, 38, 53]})
r_id = df[df['reset'] == 'Y']['id']
r_dates = df[df['reset'] == 'Y']['date']
df['tdelta'] = np.where((df['id'].isin(r_id) & df['date'].isin(r_dates)),250,df['tdelta'])
df

出来:

    id  reset   date    tdelta
0   223     N   3       3
1   227     Y   7       250
2   2214    N   15      14
3   2215    Y   16      250
4   226     N   15      17
5   2215    Y   15      250
6   2215    N   15      250
7   238     Y   38      250
8   253     Y   53      250

【讨论】:

  • 由于 OP 专门要求一种“更有效”的方法,因此提供一些基本的基准测试将有助于 OP 和未来的读者。
  • 这就是你激励我学习 %timeit...
  • 如果我不使用 apply() 方法,这将如何考虑 id 列?每个 id 都有一组唯一的警报,因此我必须创建 reset_group 以考虑到这一点
  • 以上如有不妥请举个例子
  • 您是否尝试过将日期转换为 int 并运行它?只是为了确保它是日期列?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-25
  • 2016-10-28
  • 2023-04-06
  • 1970-01-01
  • 2010-10-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多