数据帧分层索引加速



>我有这样的数据帧

+----+------------+------------+------------+
|    |            |    type    | payment    | 
+----+------------+------------+------------+
| id | res_number |            |            | 
+----+------------+------------+------------+
|  a |     1      |    toys    | 20000      |
|    |     2      |  clothing  | 30000      |
|    |     3      |    food    | 40000      |
|  b |     4      |    food    | 40000      |
|    |     5      |   laptop   | 30000      |
+----+------------+------------+------------+

如您所见,ID和res_number是分层行值,类型,付款是正常列值。我想得到的在下面。

array([['toys', 20000],
   ['clothing', 30000],
   ['food', 40000]])

无论"res_number"是什么,它都由"id(=a("索引,我知道

df.loc[['a']].values

完美地适用于它。但是索引的速度太慢了...我必须索引 150000 个值。

所以我将数据帧索引为

df.iloc[1].values

但它只带来了

array(['toys', 20000])

在索引层次结构中是否有任何更快的索引方法?

选项 1
pd.DataFrame.xs

df.xs('a').values

选项 2
pd.DataFrame.loc

df.loc['a'].values

选项 3
pd.DataFrame.query

df.query('ilevel_0 == 'a'').values

选项 4
更迂回一点,使用 pd.MultiIndex.get_level_values 创建蒙版:

df[df.index.get_level_values(0) == 'a'].values

array([['toys', 20000],
       ['clothing', 30000],
       ['food', 40000]], dtype=object)

选项 5

将 .loc 与轴参数一起使用

 df.loc(axis=0)['a',:].values

输出:

array([['toys', 20000],
       ['clothing', 30000],
       ['food', 40000]], dtype=object)

另一种选择。保留每个组的开始和结束索引的额外字典。(假设索引已排序。

选项 1 使用组中的第一个和最后一个索引进行查询 iloc

d = {k: slice(v[0], v[-1]+1) for k, v in df.groupby("id").indices.items()}
df.iloc[d["b"]]
array([['food', 40000],
       ['laptop', 30000]], dtype=object)

选项 2 使用第一个和最后一个索引对df.values进行numpy索引切片查询。

df.values[d["a"]] 

定时

df_testing = pd.DataFrame({"id": [str(v) for v in np.random.randint(0, 100, 150000)],
                        "res_number": np.arange(150000),
                        "payment": [v for v in np.random.randint(0, 100000, 150000)]}
             ).set_index(["id","res_number"]).sort_index()
d = {k: slice(v[0], v[-1]+1) for k, v in df_testing.groupby("id").indices.items()}
# by COLDSPEED
%timeit df_testing.xs('5').values
303 µs ± 17.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
# by OP
%timeit df_testing.loc['5'].values
358 µs ± 22.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
# Tai 1
%timeit df_testing.iloc[d["5"]].values 
130 µs ± 3.04 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
# Tai 2
%timeit df_testing.values[d["5"]] 
7.26 µs ± 845 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

但是,获得d并非没有成本。

%timeit {k: slice(v[0], v[-1]+1) for k, v in df_testing.groupby("id").indices.items()}
16.3 ms ± 6.89 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

创建一个额外的查找表是否值得?

创建索引的成本将分摊到执行查询的收益上。在我的玩具数据集中,它将是 16.3 毫秒/(300 us - 7 us(≈ 56 个查询来恢复创建索引的成本。

同样,需要对索引进行排序。

最新更新