DataFrame的Series.map等价方法是什么?
使用 Series.map
方法时,如果我给它一个 Series 作为参数,它就能把这个 Series 的元素当作索引去查找另一个 Series 的值。我想用同样的方法来处理 DataFrame 的一些列,把每一行当作一组索引,去查找一个有多重索引的 Series。下面是一个例子:
>>> d = pandas.DataFrame([["A", 1], ["B", 2], ["C", 3]], columns=["X", "Y"])
>>> d
X Y
0 A 1
1 B 2
2 C 3
[3 rows x 2 columns]
>>> s = pandas.Series(np.arange(9), index=pandas.MultiIndex.from_product([["A", "B", "C"], [1, 2, 3]]))
>>> s
A 1 0
2 1
3 2
B 1 3
2 4
3 5
C 1 6
2 7
3 8
dtype: int32
我希望能够使用 d.map(s)
,这样 d
的每一行就可以作为一个元组,用来在 s
的多重索引中查找对应的值。也就是说,我想要的结果和下面这个是一样的:
>>> s.ix[[("A", 1), ("B", 2), ("C", 3)]]
A 1 0
B 2 4
C 3 8
dtype: int32
不过,DataFrame 和 Series 不一样,它没有 map
这个方法。另一个明显的选择 s.ix[d]
会报错“无法用多维键进行索引”,所以这显然也不支持。
我知道可以通过把 DataFrame 转换成一个列表的列表,或者使用逐行的 apply
方法来一个一个地抓取每个项目,但有没有什么方法可以避免这么大的开销呢?我该如何一次性对多个列做出类似于 Series.map
的操作呢?
1 个回答
2
你可以从数据表(DataFrame)创建一个多重索引(MultiIndex),然后使用 ix 或 loc 来进行操作:
In [11]: mi = pd.MultiIndex.from_arrays(d.values.T)
In [12]: s.loc[mi] # can use ix too
Out[12]:
A 1 0
B 2 4
C 3 8
dtype: int64
这样做是相当高效的:
In [21]: s = pandas.Series(np.arange(1000*1000), index=pandas.MultiIndex.from_product([range(1000), range(1000)]))
In [22]: d = pandas.DataFrame(zip(range(1000), range(1000)), columns=["X", "Y"])
In [23]: %timeit mi = pd.MultiIndex.from_arrays(d.values.T); s.loc[mi]
100 loops, best of 3: 2.77 ms per loop
In [24]: %timeit s.apply(lambda x: x + 1) # at least compared to apply
1 loops, best of 3: 3.14 s per loop