Python索引(一)

前言

  Python及其numpy、pandas几个库里数据类型的索引真的是很多陷阱,初学者往往容易混淆。本篇尽量把理解对的总结一下。

几种数据类型索引

1、python list

  多维列表可以看成嵌套的列表

1) 获取单个元素

  正确✅打开方式:

>>> a = [[1,2,3], [4,5,6]]
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> a[0][0]
1
>>> a[1][0]
4
>>> a[1][2]
6

  错误❌打开方式:

>>> a[1,0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: list indices must be integers or slices, not tuple

2) 获取多个元素

  正确✅打开方式:

>>> a[:][:]
[[1, 2, 3], [4, 5, 6]]
>>> a[0]  
[1, 2, 3]
# 多维列表可以看成嵌套的列表,这里第一层是[1,2,3]和[4,5,6]两个列表,
# 所以a[0]这是获取第一层的第一个列表

>>> a[0][0:1] # 这是获取列表第一层第一个列表[1,2,3]的由0:1组成的列表
[1]   #这里需要注意⚠️的是:a[0][0:1] 返回的是一个列表,而a[0][0]返回的是一个值
>>> type(a[0][0:1])
<class 'list'>
>>> type(a[0][0])
<class 'int'>

  容易混淆的打开方式:

>>> a[0:1][0] # 你以为返回的是1或者[1],其实正确答案如下:
[1, 2, 3]
# 为什么?因为a[0:1]是返回列表第一层第0:1个列表组成的列表,
# 所以是[[1,2,3]],还是一个二维列表,所以a[0:1][0]返回的是[1, 2, 3]
# 这样就能理解为什么下面的索引会失败了
>>> a[0:1][1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
# 也能理解下面为什么二维列表居然能用三维下标了
>>> a[0:1][0][0]
1

2、 numpy array

>>> import numpy as np
>>> b = np.array(a)
>>> b
array([[1, 2, 3],
       [4, 5, 6]])
>>> b[0][0]
1
>>> b[0,0]   # 惊奇地发现这种方式合法了,amazing!
1

  list和array如此之相像,在写程序过程中有时候会混淆,而如果搞不清楚list和array,例如把list当成了array,则上述索引a[0,0] 就会报错。

  array实际上是矩阵的形式,[0, 0]这种方式就是按照矩阵的思路来理解的,所以它可以按列来获取元素

>>> b[:2, :1]。# 获取到了0、1行的第0列
array([[1],
       [4]])

  同时,array保留了类似[0][0]方式,和list操作及结果一样。我们来对比一下:

>>> b[:2][:1]
array([[1, 2, 3]])
>>> a[:2][:1]
[[1, 2, 3]]

3、pandas DataFrame

>>> import pandas as pd
>>> c = pd.DataFrame(a, columns=['col0','col1', 'col2'])
>>> c
   col0  col1  col2
0     1     2     3
1     4     5     6

  在DataFrame里,体系是完全不一样的,不能用list和array的方式来做索引。如果非要那么做的话,要采用iloc。iloc基本是把DataFrame看成array,可以用行/列序号来索引。

>>> c[0][0]
Traceback (most recent call last):
  File "/Users/xxx/anaconda3/lib/python3.6/site-packages/pandas/core/indexes/base.py", line 3063, in get_loc
    return self._engine.get_loc(key)
  File "pandas/_libs/index.pyx", line 140, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/index.pyx", line 162, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/hashtable_class_helper.pxi", line 1492, in pandas._libs.hashtable.PyObjectHashTable.get_item
  File "pandas/_libs/hashtable_class_helper.pxi", line 1500, in pandas._libs.hashtable.PyObjectHashTable.get_item
KeyError: 0.  # ...未完,相当长一段错误提示

# 正确✅打开方式
>>> c.iloc[0][0]
1

  DataFrame非常好的一点是把列都取了名字,可以直接按列名字获取一列或者多列。

>>> c['col0']   #返回的是Series类型
0    1
1    4
>>> c[['col0','col1']] #返回的是DataFrame类型
   col0  col1
0     1     2
1     4     5

  但是在获取多列的时候要⚠️注意,必须把多列用[]括起来,否则....出错没商量...

>>> c['col0','col1']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/l....   #此处省略错误提示若干

  那么,怎么获取行呢?用loc。loc还可以获取指定名字的行、列。

# 获取第0行
>>> c.loc[0]
col0    1
col1    2
col2    3
Name: 0, dtype: int64
>>> c.loc[:2]
   col0  col1  col2
0     1     2     3
1     4     5     6
# 获取指定行、列
>>> c.loc[:2, 'col0']
0    1
1    4
Name: col0, dtype: int64
>>> c.loc[:2, ['col0']]
   col0
0     1
1     4
# c.loc[:2, 'col0'] 和 c.loc[:2, ['col0']]区别在哪里?返回的类型不一样!!!
>>> type(c.loc[:2, 'col0'])
<class 'pandas.core.series.Series'>   #Series类型
>>> type(c.loc[:2, ['col0']])
<class 'pandas.core.frame.DataFrame'>   #DataFrame类型

>>> for each in c.loc[:2, 'col0']:
...     print(each)
... 
1
4
>>> for each in c.loc[:2, 'col0'].iterrows():  # Series不能iterrows
...     print(each)
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/U

  摘抄一段Series的描述:“Series是Pandas中的一维数据结构,类似于Python中的列表和Numpy中的Ndarray,不同之处在于:Series是一维的,能存储不同类型的数据,有一组索引与元素对应。”
  我们再来看一下有无[]的values的差别:

>>> c.loc[:2, 'col0'].values   # 这个是行
array([1, 4])
>>> c.loc[:2, ['col0']].values # 这个返回列的形式的numpy array
array([[1],
       [4]])

  当要获取多个列时,必须用[]括起来:

#错误❌
>>> c.loc[:2, 'col0', 'col1']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/xxx/anaconda3/lib/python3.6/site-packages/pandas/core/indexing.py", line 1472, in __getitem__
    return self._getitem_tuple(key)
  File "/Users/liqiong/anaconda3/lib/python3.6/site-packages/pandas/core/indexing.py", line 875, in _getitem_tuple
    self._has_valid_tuple
.... # 此处省去错误提示若干行

# 正确✅示范:
>>> c.loc[:2, ['col0', 'col1']]
   col0  col1
0     1     2
1     4     5

关于赋值:

# 单行多累赋值
>>> c.loc[0, ['col0','col1']] = [7,8]
>>> c
   col0  col1  col2
0     7     8     3
1     4     5     6
# 多行多列赋值
>>> c.loc[:2, ['col0','col1']] = [[7,8],[0,9]]
>>> c
   col0  col1  col2
0     7     8     3
1     0     9     6

# Series单列赋值
>>> c.loc[0, 'col0'] = 3  #这里不能是c.loc[0, 'col0'] = [3],否则出错
>>> c
   col0  col1  col2
0     3     8     3
1     0     9     6
>>> c.loc[:2, 'col0'] = [3,4]
>>> c
   col0  col1  col2
0     3     8     3
1     4     9     6

# iloc也同样可以赋值,我们用iloc把c赋值回最初的值
>>> c.iloc[:2,:2] = [[1,2],[4,5]]
>>> c
   col0  col1  col2
0     1     2     3
1     4     5     6
>>> c.iloc[:1,0] = [3]
>>> c
   col0  col1  col2
0     3     2     3
1     4     5     6
>>> c.iloc[:1,0] = 1  #这里1为什么不需要[],还不是很清楚
>>> c
   col0  col1  col2
0     1     2     3
1     4     5     6

  我们把行索引换成名字吧,再体会一下不同行、列输入的差别。

>>> c = c.rename({0:'row0',1:'row1'}, axis='index')
>>> c
      col0  col1  col2
row0     1     2     3
row1     4     5     6

>>> c.loc['row0','col0']
1
>>> c.loc[['row0'],'col0']
row0    1
Name: col0, dtype: int64
>>> c.loc[['row0'],['col0']]
      col0
row0     1
>>> c.loc[['row0','row1'],'col0']
row0    1
row1    4
Name: col0, dtype: int64
>>> c.loc[['row0','row1'],['col0']]
      col0
row0     1
row1     4

  冒号的正确与错误用法

>>> c.loc[[:],['col0']] #错误❌ 
  File "<stdin>", line 1
    c.loc[[:],['col0']]
           ^
SyntaxError: invalid syntax

>>> c.loc[:,['col0']]  # 正确✅
      col0
row0     1
row1     4

>>> c.loc[:,:]
      col0  col1  col2
row0     1     2     3
row1     4     5     6
>>> c.loc[:,:].values
array([[1, 2, 3],
       [4, 5, 6]])
>>> c.loc[:'row2',['col0']]
      col0
row0     1
row1     4
>>> c.loc['row1':'row2',['col0']]
      col0
row1     4
# 神奇的是行是不包含最后一个‘row2’的,而列是包含最后一个'col2'的,
# 这真的确认不是pandas的bug?
>>> c.loc['row1':'row2','col0':'col2'] 
      col0  col1  col2
row1     4     5     6
>>> c.loc['row1':'row2','col0':'col1']
      col0  col1
row1     4     5

  关于使用冒号进行赋值

>>> c
      col0  col1  col2
row0     1     2     3
row1     4     5     6
>>> c.loc['row1':'row2','col0':'col1']=[1,2] #把前两行前两列都赋成[1,2]
>>> c
      col0  col1  col2
row0     1     2     3
row1     1     2     6
>>> c.loc[:,'col0':'col1']=[3,4]
>>> c
      col0  col1  col2
row0     3     4     3
row1     3     4     6
>>> c.loc[:,'col0']=[1,4]
>>> c
      col0  col1  col2
row0     1     4     3
row1     4     4     6
>>> c.loc[:,'col0']=[1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/xxx/anaconda3/lib/python3.6/site-packages/pandas/core
# 此处省略出错信息若干
>>> c.loc[:,'col0']=1
>>> c
      col0  col1  col2
row0     1     4     3
row1     1     4     6

  估计能坚持到这里不晕的没有几个人,所以多重索引的问题,留到下次吧。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容