数据帧分层索引加快

问题描述 投票:3回答:3

我有这样的数据帧

+----+------------+------------+------------+
|    |            |    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])

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

python pandas dataframe
3个回答
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
投票

Option 5

将.loc与axis参数一起使用

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

输出:

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

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"]] 

timing

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个查询来恢复创建索引的成本。

同样,索引需要排序。

热门问题
推荐问题
最新问题