【问题标题】:Slice DataFrame using indices from other columns使用来自其他列的索引切片 DataFrame
【发布时间】:2018-12-11 13:48:43
【问题描述】:

我有一个这样的数据框:

index   value   idxmin  idxmax
0       300     nan     nan
1       200     nan     nan
2       100     nan     nan
3       200     0       2
4       300     1       2
5       400     1       3
6       500     2       5
7       600     4       5
8       700     4       7
9       800     5       8
10      900     5       8
11      800     7       9
12      700     8       10
13      600     10      12
14      500     12      13
15      400     12      14
16      500     12      15
17      400     13      15
18      500     13      16
19      600     15      17
20      700     15      19

我想创建一个新列(最大值),它将返回行范围的“值”列的最大值。 示例:对于第 9 行,第 5 到第 8 行的“值”的最大值为 800。

我做了这段代码,实际运行但效率不高

df['maxvalue'] = df.apply(lambda x : (df['value'].loc[x['idxmin']:x['idxmax']].max(), axis=1)

您有更高效的代码来执行该功能吗?

我期望的结果(最后一栏):

index   value   idxmin  idxmax  maxvalue
0       300     nan     nan     nan
1       200     nan     nan     nan
2       100     nan     nan     nan
3       200     0       2       300
4       300     1       2       200
5       400     1       3       200
6       500     2       5       400
7       600     4       5       400
8       700     4       7       600
9       800     5       8       700
10      900     5       8       700
11      800     7       9       800
12      700     8       10      900
13      600     10      12      900
14      500     12      13      700
15      400     12      14      700
16      500     12      15      700
17      400     13      15      600
18      500     13      16      600
19      600     15      17      500
20      700     15      19      600

非常感谢您的帮助!!

【问题讨论】:

  • 您的问题存在冲突。您声明第 9 行,“值”rows5 到 8 的最大值为 800。但是,在您的预期输出中,您有 700。我怀疑 700 是正确的。
  • 嗨斯科特!你是对的,这是一个错误。理解:第 5 行到第 8 行的最大值为 700。

标签: python pandas python-2.7 dataframe


【解决方案1】:

这个操作本质上很难向量化,因为数组没有排序,索引似乎不代表同样大小的范围。我可以建议将其转换为列表理解,以规避来自 apply 的开销,但之后您就只能靠自己了。

df['maxvalue'] = [
    df['value'].values[int(s):int(e)].max() if pd.notna([s,e]).all() 
    else np.nan for s, e in zip(df['idxmin'], df['idxmax'])
]

df.head()
    index  value  idxmin  idxmax  maxvalue
0       0    300     NaN     NaN       NaN
1       1    200     NaN     NaN       NaN
2       2    100     NaN     NaN       NaN
3       3    200     0.0     2.0     300.0
4       4    300     1.0     2.0     200.0

为了充分利用这一点,有必要将尽可能多的繁重工作从 pandas 转移到 numpy。我在我的机器上看到一个只有 1000 行的小型 DataFrame 的速度提高了 15 倍。

df_ = df
df = pd.concat([df_] * 1000, ignore_index=True)

%timeit df.apply(
    lambda x: df['value'].loc[x['idxmin']:x['idxmax']].max(), axis=1)
%%timeit 
[
    df['value'].values[int(s):int(e)].max() if pd.notna([s,e]).all() 
    else np.nan for s, e in zip(df['idxmin'], df['idxmax'])
]

4.79 s ± 68.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
268 ms ± 3.74 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

【讨论】:

  • @coldspeed - 任何时间比较? bobo 建议他的解决方案很慢。很高兴看到改进的程度......
  • @sophros 添加了一些时间。我意识到我需要将尽可能多的繁重工作从 pandas 转移到 numpy 才能看到任何明显的改进。
  • 再怎么努力也想不出更好的方法。
猜你喜欢
  • 2020-05-03
  • 1970-01-01
  • 1970-01-01
  • 2019-03-23
  • 2018-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多