pandas mysql索引_pandas练习-多层索引的创建和各种操作(multiindex)第二部分

本文介绍了如何使用Pandas的切片操作选择MultiIndex DataFrame,包括通过`slice`和`IndexSlice`进行选择。示例展示了如何选择特定层级的行和列,并演示了按索引聚合数据、数据对齐和多层索引的层序交换。文章还讨论了排序和切片时的注意事项,强调了排序对切片操作的重要性。
摘要由CSDN通过智能技术生成

使用切片(slicers)

你可以使用切片来选择MultiIndex, slice是python内置的函数(其实是一个类), 他的用法是这样的:

1

2

3alist = list('abcdefg' * 3)

selector = slice(1, 6, 2)

alist[selector]

输出(plain):

['b', 'd', 'f']

我们可以使用slice来选择MultiIndex。

下面先创建一个DataFrame:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22import pandas as pd

import numpy as np

def mklbl(prefix,n):

return ["%s%s" % (prefix,i) for i in range(n)]

miindex = pd.MultiIndex.from_product([mklbl('A',4),

mklbl('B',2),

mklbl('C',4),

mklbl('D',2)])

micolumns = pd.MultiIndex.from_tuples([('a','foo'),('a','bar'),

('b','foo'),('b','bah')],

names=['lvl0', 'lvl1'])

dfmi = pd.DataFrame(np.arange(len(miindex)*len(micolumns)).reshape((len(miindex),len(micolumns))),

index=miindex,

columns=micolumns).sort_index().sort_index(axis=1)

dfmi.head()

输出(html):

lvl0

a

b

lvl1

bar

foo

bah

foo

A0

B0

C0

D0

1

0

3

2

D1

5

4

7

6

C1

D0

9

8

11

10

D1

13

12

15

14

C2

D0

17

16

19

18

下面我们需要选择出MultiIndex第一层为A1或A2或A3, 第二层不做选择, 第三层只包括C1和C3的行:

1dfmi.loc[(slice('A1', 'A3'), slice(None), ['C1', 'C3']), :]

输出(html):

lvl0

a

b

lvl1

bar

foo

bah

foo

A1

B0

C1

D0

73

72

75

74

D1

77

76

79

78

C3

D0

89

88

91

90

D1

93

92

95

94

B1

C1

D0

105

104

107

106

D1

109

108

111

110

C3

D0

121

120

123

122

D1

125

124

127

126

A2

B0

C1

D0

137

136

139

138

D1

141

140

143

142

C3

D0

153

152

155

154

D1

157

156

159

158

B1

C1

D0

169

168

171

170

D1

173

172

175

174

C3

D0

185

184

187

186

D1

189

188

191

190

A3

B0

C1

D0

201

200

203

202

D1

205

204

207

206

C3

D0

217

216

219

218

D1

221

220

223

222

B1

C1

D0

233

232

235

234

D1

237

236

239

238

C3

D0

249

248

251

250

D1

253

252

255

254

你还可以使用pandas.IndexSlic类来实现类似的选择:

1

2

3idx = pd.IndexSlice

dfmi.loc[idx['A1': 'A3', :, ['C1', 'C3']], :]

输出(html):

lvl0

a

b

lvl1

bar

foo

bah

foo

A1

B0

C1

D0

73

72

75

74

D1

77

76

79

78

C3

D0

89

88

91

90

D1

93

92

95

94

B1

C1

D0

105

104

107

106

D1

109

108

111

110

C3

D0

121

120

123

122

D1

125

124

127

126

A2

B0

C1

D0

137

136

139

138

D1

141

140

143

142

C3

D0

153

152

155

154

D1

157

156

159

158

B1

C1

D0

169

168

171

170

D1

173

172

175

174

C3

D0

185

184

187

186

D1

189

188

191

190

A3

B0

C1

D0

201

200

203

202

D1

205

204

207

206

C3

D0

217

216

219

218

D1

221

220

223

222

B1

C1

D0

233

232

235

234

D1

237

236

239

238

C3

D0

249

248

251

250

D1

253

252

255

254

同样是上面的例子, 我们可以选择出列索引第二层为bar的列:

1dfmi.loc[idx['A1': 'A3', :, ['C1', 'C3']], idx[:, 'foo']]

输出(html):

lvl0

a

b

lvl1

foo

foo

A1

B0

C1

D0

72

74

D1

76

78

C3

D0

88

90

D1

92

94

B1

C1

D0

104

106

D1

108

110

C3

D0

120

122

D1

124

126

A2

B0

C1

D0

136

138

D1

140

142

C3

D0

152

154

D1

156

158

B1

C1

D0

168

170

D1

172

174

C3

D0

184

186

D1

188

190

A3

B0

C1

D0

200

202

D1

204

206

C3

D0

216

218

D1

220

222

B1

C1

D0

232

234

D1

236

238

C3

D0

248

250

D1

252

254

另外, 我们可以使用布尔的蒙版来配合IndexSlice选择数据, 下面我们选择出foo列的数值小于100的行:

1

2

3mask = (dfmi[('a', 'foo')] < 100) & (dfmi[('b', 'foo')] < 100)

dfmi.loc[idx[mask, :, ['C1', 'C2']], idx[:, 'foo']]

输出(html):

lvl0

a

b

lvl1

foo

foo

A0

B0

C1

D0

8

10

D1

12

14

C2

D0

16

18

D1

20

22

B1

C1

D0

40

42

D1

44

46

C2

D0

48

50

D1

52

54

A1

B0

C1

D0

72

74

D1

76

78

C2

D0

80

82

D1

84

86

按索引聚合数据和数据对齐

在多层索引中, 我们可以依据某一层进行数据聚合, 比如求和, 求均值, 下面我们先来创建一个dataframe:

1

2

3

4

5

6

7midx = pd.MultiIndex(levels=[['zero', 'one'], ['x','y']],

labels=[[1,1,0,0],[1,0,1,0]])

df = pd.DataFrame(np.random.randn(4,2), index=midx)

df

输出(html):

0

1

one

y

-0.634407

0.272985

x

-0.546991

0.001771

zero

y

1.801089

-1.132311

x

0.213100

2.339203

求第一层索引的均值:

1

2df2 = df.mean(level=0)

df2

输出(html):

0

1

one

-0.590699

0.137378

zero

1.007094

0.603446

如果我们想用均值替换原先的所有值, 我们可以恢复到原始数据的形状和索引:

1

2df3 = df2.reindex(df.index, level=0)

df3

输出(html):

0

1

one

y

-0.590699

0.137378

x

-0.590699

0.137378

zero

y

1.007094

0.603446

x

1.007094

0.603446

上面就是一个数据对齐的过程, df2的索引和df的索引按照第一层对齐, 也就是[one, zero]对齐, 假如不对齐, 我们会得到什么结果?

1

2df4 = df2.reindex(df.index)

df4

输出(html):

0

1

one

y

NaN

NaN

x

NaN

NaN

zero

y

NaN

NaN

x

NaN

NaN

我们可以使用更直观的方式去对齐数据:

1

2df_a, df2_a = df.align(df2, level=0)

df2_a

输出(html):

0

1

one

y

-0.590699

0.137378

x

-0.590699

0.137378

zero

y

1.007094

0.603446

x

1.007094

0.603446

需要注意的是, 上面的方法可能会更改df和df2, 所以有两个返回值。

交换多层索引的层序

直接看例子就好了, 对比交换前后的index:

1df

输出(html):

0

1

one

y

-0.634407

0.272985

x

-0.546991

0.001771

zero

y

1.801089

-1.132311

x

0.213100

2.339203

1df.swaplevel(0, 1, axis=0)

输出(html):

0

1

y

one

-0.634407

0.272985

x

one

-0.546991

0.001771

y

zero

1.801089

-1.132311

x

zero

0.213100

2.339203

另外, 可以使用reorder_levels达到相同的目的, 只不过它可以一次性修改多层index的次序:

1df.reorder_levels([1, 0], axis=0)

输出(html):

0

1

y

one

-0.634407

0.272985

x

one

-0.546991

0.001771

y

zero

1.801089

-1.132311

x

zero

0.213100

2.339203

排序

我们可以使用sort_index对索引进行排序。

1

2

3

4

5

6

7

8

9

10

11import random;

arrays = [['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'],

['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']]

tuples = list(zip(*arrays))

random.shuffle(tuples)

index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])

s = pd.Series(np.random.randn(8), index=pd.MultiIndex.from_tuples(tuples))

s

输出(plain):

baz one 0.035299

foo one -1.021257

baz two -0.225705

foo two -0.369259

bar one -0.681788

two 0.873609

qux two 0.325956

one -1.330222

dtype: float64

默认情况下, sort_index可以逐层排序, 首先排level=0的层:

1s.sort_index()

输出(plain):

bar one -0.681788

two 0.873609

baz one 0.035299

two -0.225705

foo one -1.021257

two -0.369259

qux one -1.330222

two 0.325956

dtype: float64

但是我们可以选择只对某一层排序:

1s.sort_index(level=1)

输出(plain):

bar one -0.681788

baz one 0.035299

foo one -1.021257

qux one -1.330222

bar two 0.873609

baz two -0.225705

foo two -0.369259

qux two 0.325956

dtype: float64

如果多层索引设置了names属性, 我们可以使用名称作为参数:

1

2s.index.names=['a', 'b']

s.sort_index(level='b')

输出(plain):

a b

bar one -0.681788

baz one 0.035299

foo one -1.021257

qux one -1.330222

bar two 0.873609

baz two -0.225705

foo two -0.369259

qux two 0.325956

dtype: float64

除了对索引进行排序, 我们还可以对DataFrame.columns排序, 先来看一下我们的数据:

1

2dft = df.T

dft

输出(html):

one

zero

y

x

y

x

0

-0.634407

-0.546991

1.801089

0.213100

1

0.272985

0.001771

-1.132311

2.339203

1dft.sort_index(level=1, axis=1)

输出(html):

one

zero

one

zero

x

x

y

y

0

-0.546991

0.213100

-0.634407

1.801089

1

0.001771

2.339203

0.272985

-1.132311

index排序后有一个好处, 就是你可以使用切片来选择数据, 但是如果index没有排序, 你可能会遇到错误:

1s.loc[('baz', 'one' ): ('bar', 'one')]

---------------------------------------------------------------------------

UnsortedIndexError Traceback (most recent call last)

in

----> 1 s.loc[('baz', 'one' ): ('bar', 'one')]

d:\mysites\deeplearning.ai-master\.env\lib\site-packages\pandas\core\indexing.py in __getitem__(self, key)

1476

1477 maybe_callable = com._apply_if_callable(key, self.obj)

-> 1478 return self._getitem_axis(maybe_callable, axis=axis)

1479

1480 def _is_scalar_access(self, key):

d:\mysites\deeplearning.ai-master\.env\lib\site-packages\pandas\core\indexing.py in _getitem_axis(self, key, axis)

1864 if isinstance(key, slice):

1865 self._validate_key(key, axis)

-> 1866 return self._get_slice_axis(key, axis=axis)

1867 elif com.is_bool_indexer(key):

1868 return self._getbool_axis(key, axis=axis)

d:\mysites\deeplearning.ai-master\.env\lib\site-packages\pandas\core\indexing.py in _get_slice_axis(self, slice_obj, axis)

1509 labels = obj._get_axis(axis)

1510 indexer = labels.slice_indexer(slice_obj.start, slice_obj.stop,

-> 1511 slice_obj.step, kind=self.name)

1512

1513 if isinstance(indexer, slice):

d:\mysites\deeplearning.ai-master\.env\lib\site-packages\pandas\core\indexes\base.py in slice_indexer(self, start, end, step, kind)

4105 """

4106 start_slice, end_slice = self.slice_locs(start, end, step=step,

-> 4107 kind=kind)

4108

4109 # return a slice

d:\mysites\deeplearning.ai-master\.env\lib\site-packages\pandas\core\indexes\multi.py in slice_locs(self, start, end, step, kind)

2144 # This function adds nothing to its parent implementation (the magic

2145 # happens in get_slice_bound method), but it adds meaningful doc.

-> 2146 return super(MultiIndex, self).slice_locs(start, end, step, kind=kind)

2147

2148 def _partial_tup_index(self, tup, side='left'):

d:\mysites\deeplearning.ai-master\.env\lib\site-packages\pandas\core\indexes\base.py in slice_locs(self, start, end, step, kind)

4306 start_slice = None

4307 if start is not None:

-> 4308 start_slice = self.get_slice_bound(start, 'left', kind)

4309 if start_slice is None:

4310 start_slice = 0

d:\mysites\deeplearning.ai-master\.env\lib\site-packages\pandas\core\indexes\multi.py in get_slice_bound(self, label, side, kind)

2088 if not isinstance(label, tuple):

2089 label = label,

-> 2090 return self._partial_tup_index(label, side=side)

2091

2092 def slice_locs(self, start=None, end=None, step=None, kind=None):

d:\mysites\deeplearning.ai-master\.env\lib\site-packages\pandas\core\indexes\multi.py in _partial_tup_index(self, tup, side)

2151 'Key length (%d) was greater than MultiIndex'

2152 ' lexsort depth (%d)' %

-> 2153 (len(tup), self.lexsort_depth))

2154

2155 n = len(tup)

UnsortedIndexError: 'Key length (2) was greater than MultiIndex lexsort depth (0)'

我们可以使用is_lexsorted来判断是否经过了排序:

1s.index.is_lexsorted()

输出(plain):

False

1

2ss = s.sort_index()

ss.loc[('bar', 'one' ): ('baz', 'one')]

输出(plain):

a b

bar one -0.681788

two 0.873609

baz one 0.035299

dtype: float64

注意

本文由jupyter notebook转换而来, 您可以在这里下载notebook第二部分.ipynb)

有问题可以直接在下方留言

或者给我发邮件675495787[at]qq.com

请记住我的网址: mlln.cn 或者 jupyter.cn

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值