Dataframe分层索引加速

时间:2018-03-05 04:30:39

标签: python pandas dataframe

我有像这样的数据框

+----+------------+------------+------------+
|    |            |    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是分层行值,而type,payment是普通列值。我想得到的是下面的内容。

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

它的编号为' id(= a)'无论什么' res_number'来了,我知道

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

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

所以我按

索引数据框
df.iloc[1].values

但它只带来了

array(['toys', 20000])

在索引层次结构时,是否有更快的索引方法?

3 个答案:

答案 0 :(得分:4)

选项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)

答案 1 :(得分:1)

选项5

将.loc与轴参数

一起使用
 df.loc(axis=0)['a',:].values

输出:

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

答案 2 :(得分:0)

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

选项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 使用第一个和最后一个索引在numpy上使用df.values的索引切片进行查询。

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 ms /(300 us - 7 us)≈56个查询来恢复创建索引的成本。

同样,索引需要排序。