Pandas

一、基础

1 基础概念

1.1 isinstance函数和len函数

#isinstance函数
#isinstance (x,y)函数查询数据x是否是类型y
a="1234"
print(isinstance(a,str)) #>>True
print(isinstance(a,int)) #>>False
#len函数(Python独特格式)
#len函数可以用来求组合数据类型的元素个数(长度)
print(len("12345"))#>>5 求字符串长度
print(len([1,2,3,4])#>>4 求列表长度
print(len((1,2,3)))#>>3 求元组长度
print(len({1,2,3}))#>>3 求集合元素个数
print(len({'tom':2,'jack':3})) #>>2 求字典元素个数
​

1.2 python指针

在计算机编程里,指针是一个变量,它存储了一个值的内存地址。Python是一种高级语言,用起来通常不需要手动操作内存地址,所以 Python 的指针概念与 C 或 C++ 等语言中的指针概念略有不同。
​
Python中存在两种数据类型:可变数据类型和不可变数据类型。不可变数据类型包括数字、字符串和元组,可变数据类型包括列表、字典和集合。对于不可变数据类型,每当它们被修改时,Python会创建一个新的对象,并将原对象的指针指向新对象。对于可变数据类型,原对象的指针不会改变,因为对象在原地被修改。
​
在Python中,变量可以看作是指向对象的指针。所以,当你将一个对象赋值给变量时,实际上是把指针给了这个变量。当你使用多个变量引用同一个对象时,这些变量其实指向同一个对象的指针。当你改变其中的一个变量时,指向该变量的指针会指向一个新的对象,但其他变量还是指向原来的对象的指针。
​
如果你需要更好地理解 Python 的指针概念,建议你深入学习 Python 内存模型和垃圾回收机制。
Python内存管理通过内存池来实现。内存池使Python在申请内存时更加高效。内存池分为两层实现。第一层是内存池接口,第二层是Python内部的内存管理接口。
​
在Python中所有内存分配都来自于内存池。当Python进程启动时,它会预先为各种对象类型申请必要的内存池。当需要申请一个新的对象时,对象管理系统会从内存池中提取。 对象管理系统负责跟踪未使用内存块和已使用内存块,确保内存使用得尽可能地高效。由于内存池可以重用内存块,所以Python的内存分配效率相对较高。
​
Python内存中的对象分为两类: 可变对象和不可变对象。Python中不可变对象一旦创建就不能修改。这意味着它们被创建后不能改变它们的内部状态。这些对象包括数字、字符串和元组。由于这些对象不能改变状态,因此也不需要经常分配新的内存。
​
可变对象包括字典、列表和集合。这些对象的内部状态可以随时更改。可以向列表添加或删除元素,并更改字典中的键值对。由于这些对象具有可变性,因此每当它们更改时,Python会动态地分配和释放内存。
​
Python通过垃圾回收机制来回收不再使用的内存。垃圾回收器会找到在内存中已经不再使用的对象,并清除它们所占用的内存。当对象不再被使用时,Python会自动将其标记为可回收的。然后,垃圾回收器会检查这些未使用的对象,找到不再需要的对象并删除它们。Python会自动管理网络套接字、文件句柄和其他的外部资源,所以你不必手动释放它们。
​
Python的垃圾回收器采用的是引用计数的机制。每个对象都有一个引用计数,记录着有多少个变量引用了这个对象。当一个对象的引用计数变为0时,表示这个对象不再被使用,可以将其内存释放。但这种机制会出现循环引用的情况,导致引用计数不为0,还有内存泄漏的情况,这时Python会采用标记清除、分代回收等策略来清理这些循环引用和泄漏内存。

1.3 is和==的区别

在Python中,`==`用于检查两个对象的值是否相等,而`is`用于检查两个对象是否是同一个对象。
​
具体来说,`==`比较的是对象的值是否相同,它会比较操作符两侧的对象的值,如果值相等,则返回True,否则返回False。例如:
​
```python
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)  # True
```
​
`is`比较的是对象的身份是否相同,也就是说,它比较的是操作符两侧的对象是否占用相同的内存地址。如果两个对象占用相同的地址,则返回True,否则返回False。例如:
​
```python
a = [1, 2, 3]
b = [1, 2, 3]
print(a is b)  # False
```
​
尽管a和b的值相同,但是它们却分别占用了不同的内存地址,因此返回的结果是False。
​
需要注意的是,在比较Python中的数字、字符串和布尔类型对象时,`is`和`==`通常会返回相同的结果,因为解释器优化了这些类型的对象的创建。但是对于其他类型的对象,比如列表、字典、集合等,`is`和`==`的结果可能不同,这时我们需要谨慎选择合适的比较方式。

1.4 函数的传递

Python中的函数参数传递方式包括值传递和引用传递两种方式。但是需要注意的是,Python不像其他语言那样直接支持值传递或引用传递,实际上它是通过对象引用来实现函数参数的传递。
​
### 值传递
​
当你将简单类型的参数传递给函数时(如整数、浮点数、布尔值等),Python会将其值复制一份并传递给函数。在函数内部,对这个参数的修改不会影响到函数外部。
​
```python
def func(foo):
    foo += 1
    print(foo)
​
bar = 1
func(bar)
print(bar)  # 输出1
```
​
在这个例子里,我们定义了一个简单的函数,它会将传递进来的参数值加1,并打印出来。我们将变量 `bar` 的值设定为1,并将其传递给函数 `func()`。在函数内部,我们对这个参数的值进行了修改,并打印出来,结果是2。但当我们再次打印变量 `bar` 的值时,结果仍然是1。这是因为我们将变量 `bar` 的一个复制传递给了函数,并没有将原始的变量传递给函数。
​
### 引用传递
​
当你将复杂类型的参数传递给函数时(如列表、字典、对象等),Python会将这个参数的内存地址传递给函数。在函数内部,对这个参数的修改会影响到函数外部。
​
```python
def func(foo):
    foo.append(1)
    print(foo)
​
bar = [0]
func(bar)
print(bar)  # 输出[0, 1]
```
​
在这个例子里,我们定义了一个列表,将其包含的数字 `0` 传递给函数。在函数内部,我们修改了这个列表,向其中添加了数字 `1`。当我们再次打印变量 `bar` 的值时,可以看到它的值已经发生了改变,变成了 `[0, 1]`。
​
需要注意的是,当我们将一个参数作为引用传递给函数时,其实并没有真正地传递引用,而是传递了对象的引用。这意味着在函数内部,我们可以使用这个引用去修改对象的状态,但是如果我们重新赋值这个引用,就会失去对原始对象的引用。

1.5 转义字符

- \n:换行符
- \r:回车符
- \t:制表符
- \b:退格符
- \\:反斜杠字符(用两个反斜杠表示一个反斜杠)
- \':单引号字符(用反斜杠转义表示)
- \":双引号字符(用反斜杠转义表示)
- \a:响铃(bell)符号
- \f:换页符

1.6 字符串切片

a="ABCDE"
print(a[1:2])#B区间是左闭右开,终点不算
print(a[0:-1])#ABCD
print(a[-3:-1])#CD
print(a[2:])#CDE终点省略就是一直取到最后一个字符
print(a[:3])#ABC起点省略就是从头开始取
print("abcd"[2:4])#cd
a[x:y:z]表示,从a[x]取到a[y](a[y]不算),每z个字符取一个,最后拼起来。
z为负数则代表倒着取
x,y可以省略。x,y全省略表示从头取到尾或从尾取到头
print("1234"[3:1:-1]) #>>43
print("abcde"[::-1]) #>>edcba可用于反转字符串
print("12345678"[1:7:2]) #>>246
print("12345678"[7:1:-2]) #>>864
字符串切片的用法也适用于元组和列表

1.7split 函数

s.split(x)
用字符串x做分隔符分割字符串s,得到分隔后的列表
两个相邻分隔符之间会被分隔出一个空串
a = "12..34.5346...a"
print(a.split("..")) #>> ['12', '34.5346', '.a']
print(a.split(".")) #>> ['12', '', '34', '5346', '', '', 'a']
print(a.split("34")) #>> ['12..', '.5', '6...a']

1.8 字符串高级分割

import re
re.split(x,s) :用正则表达式x里面的分隔串分割s,x里面不同分隔串用"|"隔开
一些特殊字符,比如: ? ! " '( ) | * $ \ [ ] ^ { } . ,在正则表达式里出现时,前面需要加 \
字符串高级分割:
通过正则表达式用多个分隔串进行分割

1.9 字符串函数

replace:替换
s="1234abc567abc12"
b = s.replace("abc","FGHI") #b由把s里所有abc换成FGHI而得
print(b)#>> 1234FGHI567FGHI12
print(s)#>> 1234abc567abc12
print(s.replace("abc","")) #>> 123456712
isdigit(), islower(), isupper() 判断字符串是否是数,是否全是小写等,适合字符串  数字的话先转换为字符串
print(“123.4”.isdigit())#>>False
print(“1234”.isdigit())#>>True
print(“a123.4”.isdigit())#>>False
print(“Ab123.4”.islower())#>>False
print(“ab123.4”.islower())#>>True
startswith, endswith 判断字符串是否以某子串开头、结尾
print("abcd".startswith("ab")) #>> True
print("abcd".endswith("bcd")) #>> True
print("abcd".endswith("bed")) #>> False
• strip() 返回除去头尾空白字符(空格, '\r' '\t' '\n')后的字符串
• lstrip() 返回除去头部(左端)空白字符后的字符串
• rstrip() 返回除去尾部(右端)空白字符后的字符串
print ( " \t12 34 \n ".strip()) #>>12 34
print ( " \t12 34 5".lstrip()) #>>12 34 5
strip(s), lstrip(s), rstrip(s) 返回除去两端、左端、右端 在s 中出现的字符后的字符串
print ( "takeab \n".strip("ba \n")) #>>take#去除两端 'b','a',' ','\n'
print ( "cd\t12 34 5".lstrip("d\tc")) #>>12 34 5#去除左端 'd','\t','c'

1.10字符串编码

字符串的编码在内存中的编码是unicode的,虽然写入文件时
可能是gbk或者utf-8的
print (ord("a")) #>>97
print(ord("好")) #>>22920
print(chr(22900)) #>>奴
print(chr(97)) #>>a
`ord()` 是 Python 内置函数,用于返回一个 ASCII 字符或 Unicode 字符的十进制表示。对于 ASCII 字符,`ord()`函数返回其 ASCII 编码的十进制值,对于 Unicode 字符,则返回其对应的 Unicode 编码的十进制值。

例如,`ord("a")` 返回的是小写字母 "a" 的 ASCII 编码,即 97;`ord("好")` 返回的是汉字 "好" 的 Unicode 编码,即 22920。

`chr()` 是 Python 内置函数,用于将一个十进制数表示的 Unicode 字符转换为其对应的字符。注意,这个数必须在合法的 Unicode 范围内,否则将抛出 `ValueError` 异常。

例如,`chr(22900)` 返回的是 Unicode 编码为 22900 的字符,即 "奴";`chr(97)` 返回的是 ASCII 编码为 97 的字符 "a"。

1.11 字符串格式化

{序号:宽度.精度 类型}   宽度可以是0
> : 右对齐
< : 左对齐
^ : 中对齐
如 {0:>10.4f} 表示第0项是小数,以宽度至少是10字符,右对齐(宽度不足时空格补在
左边),保留小数点后面4位的方式输出。
print("today %s,%d,%.1f"%('xing',13,10.00))#>>today xing,13,10.0
print("%s,%d today %.4f"%('xing',13,10.00))#>>xing,13 today 10.0000
print("today is %s,%d"%('Monday',1))#>>today is Monday,1

1.12 lambda表达式

#lambda x:x[n] 表示一个函数,参数是x,返回值是x[n]
k=lambda x,y:x+y#k是一个函数,参数是x,y,返回值是x+y
print(k(4,5))#9
多级排序
def f(x):
    return (-x[2],x[1],x[0])
students=[('John','A',15),('Mike','C',19),('Wang','B',12),('Bob','D',10)]
students.sort(key=f)#先按年龄从高到底,在成绩从高到低,再按姓名字典
print(students)#[('Mike', 'C', 19), ('John', 'A', 15), ('Wang', 'B', 12), ('Bob', 'D', 10)]
#元组不能修改,因此无sort函数,可以用sorted得到新的排序后的列表

1.13 python中init()的作用

在Python中,`__init__`是一个特殊的方法,用于初始化/构造一个类的实例。它是类的一个实例方法,需要在实例化之后调用。在`__init__`方法中,你可以定义实例属性和其他初始化逻辑。`__init__`方法的第一个参数是`self`,它指代当前实例对象,你可以在该方法中通过`self`访问和修改实例属性。在Python中,以双下划线开头和结尾的方法和属性称为魔法方法和魔法属性,是Python提供的特殊功能。`__init__`方法就是其中之一,它允许创建一个类的新实例,以及提供初始化方法来设置实例变量的初始值。如果你省略了`__init__`方法,Python会提供一个默认的空实现。

1.14 NaN与None

在Python中,NaN(Not a Number)和None是两种不同的特殊值。

NaN是一种浮点数类型的特殊值,表示“不是一个数”或“无效数字”。它通常用于计算中出现无效数据的情况,例如计算结果为无穷大或除以零。NaN可通过math.nan或numpy.nan常量来表示。

而None则表示空值或缺失值,通常用于表示变量或参数没有被赋值或无返回值的情况。None是Python中唯一的一种空值类型,可以通过None关键字来表示。

需要注意的是,NaN是数值类型,而None是一个对象类型。在进行比较操作时,它们之间是不相等的,即NaN != None。

1.15 range和arange的区别

在Python中,`range`和`arange`是常用的两个生成数字序列的函数,它们的区别在于以下几点:

1. `range`生成的是一个可迭代的range对象,`arange`生成的则是一个数组对象;
2. `range`函数可以设置步长、起始值和结束值(不包括),`arange`函数可以设置步长、起始值和结束值(包括);
3. `range`函数适用于Python 2和Python 3,`arange`只适用于Python 3。

下面分别对两个函数进行一些详细的说明:

1. `range(start, stop[,step])`:生成一个从`start`到`stop`(不包括)的数字序列,步长为`step`。其中`start`和`step`参数可省略,默认为0和1。如果只传一个参数,那么它表示`stop`,`start`默认为0。
```python
>>> a = range(10)  # 生成一个0到9的整数序列
>>> print(list(a))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> b = range(0,10,2)  # 生成一个0到9,步长为2的序列
>>> print(list(b))
[0, 2, 4, 6, 8]
```

2. `numpy.arange([start, ]stop, [step, ]dtype=None)`:生成一个从`start`到`stop`,步长为`step`的数组。其中`start`和`step`参数可省略,默认为0和1。如果只传一个参数,那么它表示`stop`,`start`默认为0。`dtype`参数表示数组的数据类型,默认为`None`,即根据输入的参数决定数据类型。
```python
>>> import numpy as np
>>> a = np.arange(10)  # 生成一个0到9的数组
>>> print(a)
[0 1 2 3 4 5 6 7 8 9]

>>> b = np.arange(0, 10, 2)  # 生成一个0到9,步长为2的数组
>>> print(b)
[0 2 4 6 8]
```

需要注意的是,在Python中使用`range`函数生成的是一个迭代器对象,不能直接访问其中的元素,需要通过`list`函数将其转换为列表。而在`numpy`模块中,`arange`函数生成的是一个数组对象,可以直接访问其中的元素。

2 列表

2.1 列表的增删和修改

列表可以增删元素,可以是任何类型
列表:有序的数据类型并且值可变,内容也可以是任意的数据类型,用[]或list函数表转换

2.2 列表的创建和赋值

a=[]#表示空列表
a=['1',12,'c',12.0]
b=('1','2',12)
c=list(b)
a[1]=100#列表元素可以赋值
print(a)#['1', 100, 'c', 12.0]
print(type(a),type(b),type(c))#<class 'list'> <class 'tuple'> <class 'list'>
print(c)#['1', '2', 12]

2.3 列表的元素变更及索引及切片的使用

a=[1,2,3]
print(a)#[1, 2, 3]
a[0]=9
print(a)#[9, 2, 3]
print(a[2])#3
print(a[:2])#[9, 2]

2.4 列表中元素的添加

a=[1,2,"a"]
a.append(3)#列表最末尾处添加
print(a)#[1, 2, 'a', 3]
a.extend([2,3])#添加多个元素
print(a)#[1, 2, 'a', 3, 2, 3]
a+=[100,110]#添加另一列表元素100和110,在a原地添加,没有新建一个列表
print(a)#[1, 2, 'a', 3, 2, 3, 100, 110]
m=['a','b','c']
n=[1,2,3]
x=[m,n]#a若变x也变
print(x)#[['a', 'b', 'c'], [1, 2, 3]]
m[0]=1
print(x)#[[1, 'b', 'c'], [1, 2, 3]]
print(x[0])#[1, 'b', 'c']
print(x[0][1])#b

2.5列表增加

#列表相加可以得到新的列表
c=m+n
print(c)#[1, 'b', 'c', 1, 2, 3]
m[0]=100
print(c)#[1, 'b', 'c', 1, 2, 3]
#相加后再次修改某一元素数值,结构不发生变化

2.6 删除列表元素

a=[1,2,3,'a','c',2,3,2]
del a[0]
print(a)#[2, 3, 'a', 'c', 2, 3, 2]
a.remove(2)#按照索引 值 删除,删除最开始出现的那个
print(a)#[3, 'a', 'c', 2, 3, 2]
b=a.pop(0)#删除索引值并返回该值
print(b,a)#3 ['a', 'c', 2, 3, 2]
a.clear()#删除所以元素
print(a)#[]

2.7 列表和+=

对于列表来说,a+=b和a=a+b不同
b=a=[1,2]
a+=[3]#b和a相同地方,在a末尾添加元素,b也受影响
print(a,b)#[1, 2, 3] [1, 2, 3]
a=a+[4,5]#对a重新赋值不会影响到b
print(a)#[1, 2, 3, 4, 5]
print(b)#[1, 2, 3]

2.8 列表乘法

print([True]*3)#[True, True, True]
a=[1,2]
b=a*3
print(b)#[1, 2, 1, 2, 1, 2]
print([a*3])#[[1, 2, 1, 2, 1, 2]]
c=[a]*3
print(c)#[[1, 2], [1, 2], [1, 2]]
a.append([3])
print(c)#[[1, 2, [3]], [1, 2, [3]], [1, 2, [3]]]
#对a修改后,c也会发生变化
print(b)#[1, 2, 1, 2, 1, 2]

2.9 列表比较大小

#两个列表比大小,就是逐个元素比大小,直到分出胜负,如果有两个对应元素不可比大小,则出runtime error
print([1,'a',3]<[1,'d',2])#True
列表的遍历
lst=[1,2,3]
for x in lst:
    print(x,end=" ")#1 2 3 [100, 2, 3]
x=100#不会修改列表的元素
for i in range(len(lst)):
    lst[i]=100
    print(lst)#[100, 100, 100]

2.10 用缺省的比较规则排序

#a.sort()可以对列表a从小到大排序
#sorted(a)返回a经过从小到大排序后的新列表,a不变
a=[5,6,3,2,1,7,4]
a.sort()
print(a)#[1, 2, 3, 4, 5, 6, 7]
a=[3,1,4,5,32,6,43]
b=sorted(a)
print(b)#[1, 3, 4, 5, 6, 32, 43]
print(a)#[3, 1, 4, 5, 32, 6, 43]
a.sort(reverse=True)#对a从大到小排序
print(a)#[43, 32, 6, 5, 4, 3, 1]
students=[('John','C',20),
          ('Mike','A',29),
          ('Bob','B',10)]
students.sort()#先姓名后成绩,在年龄
print(students)#[('Bob', 'B', 10), ('John', 'C', 20), ('Mike', 'A', 29)]
students.sort(key=lambda x:x[1])#按成绩排序
print(students)#[('Mike', 'A', 29), ('Bob', 'B', 10), ('John', 'C', 20)]

2.11 自定义比较的规则--关键函数 key

def myKey(x):
    return x%10
a=[43, 32,2,35, 4, 30, 1]
a.sort(key=myKey)#按个位数排序
#key是函数,sort按对每个元素调用该函数的返回值从大到小排序
print(a)#[30, 1, 32, 2, 43, 4, 35]
#sorted("This is a students".split(),key=str.lower())#不区分大小写,报错

2.12 列表相关函数 append extend insert map filter

a,b=[1,2,3],[5,6]
a.append(b)
print(a)#[1, 2, 3, [5, 6]]
b.insert(1,100)
print(a)#[1, 2, 3, [5, 100, 6]]
a.extend(b)
print(a)#[1, 2, 3, [5, 100, 6], 5, 100, 6]
a.insert(1,'k')
a.insert(3,'k')
print(a)#[1, 'k', 2, 'k', 3, [5, 100, 6], 5, 100, 6]
a.reverse()#将整个序列颠倒
print(a)#[6, 100, 5, [5, 100, 6], 3, 'k', 2, 1]
print(a.index('k'))#>>5
try:
    print(a.index('m'))#'m' is not in list
except Exception as e:
    print(e)
    
    
print("==================")
#map(function,sequence)可用于将一个序列(列表,元组,集合)映射到另一个序列
#返回一个延时求值对象,可以转换成list,tuple,set
def f(x):
    print(x,end=" ")
    return x*x
a=map(f,[1,2,3])
print(list(a))
print(tuple(a))
a=list(map(lambda x:2*x,[2,3,4]))
print(a)
x,y,z=map(int,input().split())#map用于输入
print(x,y,z)
map映射多个序列
list1=[1,2,300]
list2={12,23,20}
tuple1=[122,20,30]
x=list(map(lambda x,y,z:x+y+z,list1,list2,tuple1))
print(x)#[135, 42, 353]
print("==================")
#filter(function,sequence),抽取序列中令function(x)为True的元素x,返回一个延时求值对象,可以转换成list,tuple,set...
def f(x):
    return x%2==0
lst=tuple(filter(f,[1,2,3,4,5]))
print(lst)#(2, 4)

2.13 列表、元组、二维列表、元组的生成

[x*x for x in range(1,11)]#[1,4,9,16,25,36,49,64,81,100]
[x*x for x in range(1,11) if x%2==0]#[4,16,36,64,100]
[m+n for m in 'ABC' for n in 'XYZ']#['AX','AY','AZ','BX','BY','BZ','CX','CY','CZ']
[[m+n for m in 'ABC']for n in 'XYZ']#[['AX','BX','CX'],['AY','BY','CY'],['AZ','BZ','CZ']]
L=['Hello','World',18,'Apple',None]
[s.lower() for s in L if isinstance(s,str)]#['hello','world','apple']
[s for s in L if isinstance(s,int)]#[18]
print("==================================")
print(tuple(x*x for x in range(1,11)))#(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)
可以看做是矩阵,a[i][j]就是第i行第j列的元素
matrix=[[1,2,3],[4,5,6],[7,8,9]]
print(matrix)#[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(matrix[1][2],matrix[2][2])#6 9
matrix[1][1]=100
print(matrix)#[[1, 2, 3], [4, 100, 6], [7, 8, 9]]
matrix=[[0 for i in range(3)] for i in range(3)]
print(matrix)#[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
matrix=[[i*3+j for j in range(3)] for i in range(2)]
print(matrix)#[[0, 1, 2], [3, 4, 5]]
生成一个3行4列的矩阵,所有的元素都是0
lst=[]
for i in range(3):
    lst.append([0]*4)
lst[0][0]=lst[2][3]=100
print(lst)#[[100, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 100]]
print("=========================================")
matrix=((1,2,3),(4,5,6),(7,8,9))
print(matrix)#((1, 2, 3), (4, 5, 6), (7, 8, 9))
matrix=tuple(tuple(0 for i in range(3))for i in range(3))
print(matrix)#((0, 0, 0), (0, 0, 0), (0, 0, 0))

2.14 列表的拷贝、深拷贝

a=[1,2,3,4]
b=a[:]#b是a的拷贝,b和a不是同一个对象,指向不同的东西
b[0]=5
print(a)#[1, 2, 3, 4]
b+=[10]
print(a)#[1, 2, 3, 4]
print(b)#[5, 2, 3, 4, 10]


a=[1,[2]]
b=a[:]
b.append(4)
print(b)#[1, [2], 4]
a[1].append(3)
print(a)#[1, [2, 3]]
print(b)#[1, [2, 3], 4]#未能进行深拷贝
import copy
a=[1,[2]]
b=copy.deepcopy(a)
b.append(4)#[1, [2], 4]
print(b)
a[1].append(3)
print(a)#[1, [2, 3]]
print(b)#[1, [2], 4]

2.15 元组和列表、字符串的转换

a=[1,2,3]
b=tuple(a)
print(b)#(1, 2, 3)
c=list(b)
print(c)#[1, 2, 3]
t=(1,3,2)
(a,b,c)=t
print(t)#a=1,b=3, c=2
s=[1,2,3]
[a,b,c]=s#a=1,b=2,c=3
元组列表和字符串互转
print(list("hello"))#['h', 'e', 'l', 'l', 'o']
print("".join(['a','44','c']))#a44c
print(tuple("hello"))#('h', 'e', 'l', 'l', 'o')
print("".join((('a','44','c'))))#a44c
#.join()将序列中的元素以指定的字符连接生产一个新的字符串,对列表进行操作,对字符串进行操作,对元组进行操作,对字典进行操作

3 元组

不可变,可作为字典的建值使用,使用逗号把元素隔开,并用()把内容括起来,()可以省略,内容的类型可以不同,不可对元素赋值,不可修改元素顺序,不可修改成指向别的,是指不可改变元素的指向,但是元组指向的内容,是可以被修改的(eg,球队人员不可改变,但是可以缺胳膊少腿)

3.1 元组的创建

a=((1,2,3),"i",123,[1,2,3])
print(type(a))#<class 'tuple'>
print(a)# ((1, 2, 3), 'i', 123, [1, 2, 3]))
print(a[1])#i
print(a[-1])# [1, 2, 3] 
a[3][1]='hello'#((1, 2, 3), 'i', 123, [1, 'hello', 3])
print(len(a))#4
print(a)#但如果元素是列表就可以修改成别的
b=(a,a)
print(b)#(((1, 2, 3), 'i', 123), ((1, 2, 3), 'i', 123))
单元素的元组
empty=()#空元组
singleton='hello',#注意末尾的,如果没有就成字符串了
print(len(empty))#0
print(len(singleton))#1
x=('hello')
print(x)#hello

3.2 元组的连接组合

tup1=("h",'a',[1,23])
tup2=('hello',)#单元素一定要加,,不然就是字符串
#创建新元组
tup3=tup1+tup2
print(tup3)#('h', 'a', [1, 23],’hello’)
tup3+=(10,20)
print(tup3)#('h', 'a', [1, 23],’hello’, 10, 20)

3.3 元组运算和迭代

x=(1,2,3)*3
print(x)#(1, 2, 3, 1, 2, 3, 1, 2, 3)
print(3 in (1,2,3))#True
for i in (1,2,3):
    print(i,end="")#1 2 3

3.4 元组赋值

a=(1,2,3)
b=x
print(b is x)#True is 表示两个操作数是否指向同一个东西,即是否是同一个对象
x+=(100,)#等价于 x=x+(100,),新建了一个元组
print(x)#(1,2,3,100)
print(b)#(1,2,3)
元组的切片同字符串一样

3.5 分解元组中的多个元素

tup_1=(1,2,3)
one,two,three =tup_1
print(one,two,three)#1 2 3
tup_2=(1,2,(1,2,3))
one,two,three =tup_2
print(three)#(1,2,3)
元组方法的确认:count,index
a=("a","c","c","s","r")
print("c出现的次数:",a.count("c"),"s在最开始位置出现的索引值:",a.index("s"))#c出现的次数: 2 s在最开始位置出现的索引值: 3

4 字典

4.1 基础知识

表示方法:{},字典的每个元素是由“键:值”两部分组成,可以根据 “键”进行快速查找,格式:d={key1:value,key2:value2...},字典元素是可以赋值的,因此也是指针,所有元素的键都不相同,
dt={'Jack':18,'Mike':19,128:37,(1,2):[4,5]}#键必须是不可变的数据类型,比如字符串,整数,小数,元组。(一个元组如果包含可变数据类型,也不能作为集合的元素)列表,集合,字典等可变的数据类型,不可以作为字典的键
print(dt['Jack'])
print(dt[128])
print(dt[(1,2)])
print(dt['Mike'])
不存在键为'c'的元素,产生异常,导致运行错误
dt['Mike']='ok'#将键为Mike的值改为‘ok'
dt['School']='Plu'#添加键为’School‘的元素,其值为’Plu'
print(dt)#{'Jack': 18, 'Mike': 'ok', 128: 37, (1, 2): [4, 5], 'School': 'Plu'}
del(dt['Mike'])#删除键为‘Mike’的元素
print(dt)#{'Jack': 18, 128: 37, (1, 2): [4, 5], 'School': 'Plu'}
scope={}#空字典
scope['a']=3#添加元素a=3
scope['b']=4#添加元素b=4
print(scope)
print('b' in scope)#判断是否有元素键为‘b'
scope['k']=scope.get('k',0)+3#get(key,v):如果键key存在,则返回键为key的元素值,否则返回v,括号外面加数字最终结果就是他们的和

具体来说,如果scope['k']不存在,则利用scope.get('k',0)获取默认值0,并将其加上3,得到3,然后将3赋值给scope['k']。如果scope['k']存在,则将其当前的值加上3,并将相加之后的结果赋值给scope['k']

print(scope['k'])
print(scope)#{'a': 3, 'b': 4, 'k': 3}
scope['k']=scope.get('k',0)+1#如果再次寻找那个没找到的键值对,就会在刚才和的基础上结果继续相加
print(scope['k'])
scope['b']=scope.get('b',3)
print(scope['b'])

4.2 字典的键不可重复,指的是字典的键的内容不能一样

a=(1,2,3)
b=(1,2,3)
d={a:60,b:70,(1,2,3):80,(1,2,3):50}#此处的a,b代表元组,数据类型都是一样的
print(d[a])#50
print(d[b])#50
print(d[(1,2,3)])#50
#出的结果都是一样的
for x in d.keys():
    print(x)#此循环值输出一个(1,2,3)

4.3 字典的构造

items=[('name','Gumby'),('age',42)]
d=dict(items)#创建字典的键
print(d)
d=dict(name='Gunby',age=42,height=1.76)#给键赋值
print(d)

4.4 字典的函数

#clear()清空函数  keys()取字典的键的序列 items()取字典 values()取字典值序列  pop(x) 删除键为x的元素,如果不存在,产生异常
#上述“序列”,不是list,tuple或set
#copy()浅拷贝 get(k,v)如果有元素的键为k,则返回该元素的值,如果没有,则返回v

不可哈希:字典,带列表的元组,列表
$:小数
Append添加在末尾
深拷贝复制内容并且指向他的方向
浅拷贝只复制内容

二、Numpy

1.1numpy.array()

numpy.array(object, dtype = None, copy = True, order = None,subok=False,ndmin = 0)
各个参数的意义
1	object	表示一个数组序列,直接填写数据。
2	dtype	可选参数,通过它可以更改数组的数据类型。
3	copy	可选参数,表示数组能否被复制,默认是 True,但是当新数值被复制时新数值不会被修改,因为二者的指向地址不相同,当值为False时,新数据被修改后原数据也会被修改,因为指向同一个地址。
4	ndmin	用于指定数组的维度。
5	subok	可选参数,类型为bool值,默认False。为True,使用object的内部数据类型,也就是内部数据类是小类;False:使用object数组的数据类型是一大类。
subok参数
#创建一个矩阵
a=np.mat([1,2,3,4])
#输出为矩阵类型
print(type(a))#<class 'numpy.matrix'>
print(a)
#既要复制一份副本,又要保持原类型
at=np.array(a,subok=True)
af=np.array(a)#默认为false
print('at,subok为True:',type(at))#at,subok为True: <class 'numpy.matrix'>
print('af,subok为False:',type(af))#af,subok为False: <class 'numpy.ndarray'>
print(id(at),id(a))#2229856736448 2229856750784
e=np.array([1,2,3,4,5,'a'])
print(e)#['1' '2' '3' '4' '5' 'a']
print(e.dtype)#<U11

ar3=np.array([
             [1,2,3],
             ('a','b','c')
])
print(ar3)#如果嵌套序列数量不一致,会报错

1.1.1 NumPy 数组属性

| ndarray.ndim | 秩,即轴的数量或维度的数量 | 
| ndarray.shape | 数组的维度,对于矩阵,n 行 m 列 |
| ndarray.size | 数组元素的总个数,相当于 .shape 中 n*m 的值 |
| ndarray.dtype | ndarray 对象的元素类型 |

ndarray.astype()修改数据类型,原类型不改变

| ndarray.itemsize | ndarray 对象中每个元素的大小,以字节为单位 |

调整维度 reshape
返回调整维度后的副本,而不改变原 ndarray。
a=np.array([1,2,3,4,5,6])
print('一维数组a:',a.shape)
#使用a数组,创建一个新的数组b,并向形状修改为2行3列
b=a.reshape((2,3))
print('b的形状:',b.shape)#b的形状: (2, 3)
print('b:',b)
结果:b: [[1 2 3]
    [4 5 6]]

调整维度 resize
numpy.resize(a, new_shape) 如果新数组大于原始数组,则新数组将填充a的重复副本。
请注意,此行为与a.resize(new_shape)不同,后者用零而不是重复的a填充。
a=np.array([[0,1],
           [2,3]
           ])
#a为原数组创建的2行2列的新数组
b_2_3=np.resize(a,(2,10))
print(b_2_3)
结果:[[0 1 2 3 0 1 2 3 0 1]
      [2 3 0 1 2 3 0 1 2 3]]

1.3.1 自定义数类型

data=np.dtype([('name',np.str_,2),('age','i1'),('salary','float')])
print(data)#[('name', '<U'), ('age', 'i1'), ('salary', '<f8')]
teachers=np.array([('zz',24,3000),('dd',33,1000)],dtype=data)
print(teachers)#[('zz', 24, 3000.) ('dd', 33, 1000.)]

1.2 numpy.arange()

numpy.arange(start, stop, step, dtype)
1	start	起始值,默认为0
2	stop	终止值(不包含)
3	step	步长,默认为1
4	dtype	返回ndarray的数据类型,如果没有提供,则会使用输入数据的类型。
#错误书写
ar1=np.arange(10,2)#起始0,终止10,步长2
print(ar1)#[]
#正确书写
ar2=np.arange(0,10,2)
print(ar2)
ar3=np.arange(20,step=2)
print(ar3)

1.3 np.linspace() 创建等差数列

np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)

1	start	必填项,序列的起始值,
2	stop	必填项,序列的终止值,如果endpoint为true,该值包含于数列中
3	num	要生成的等步长的样本数量,默认为50
4	endpoint	该值为 true 时,数列中包含stop值,反之不包含,默认是True。
5	retstep	如果为 True 时,生成的数组中会显示间距,反之不显示。
6	dtype	ndarray 的数据类型
#设置restep显示计算后的步长
ar2=np.linspace(0,5,num=5,retstep=True)
print(ar2)#(array([0.  , 1.25, 2.5 , 3.75, 5.  ]), 1.25)

1.4 np.logspace()等比数列

np.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None)
参数说明
序号	参数	描述说明
1	start	必填项,序列的起始值,
2	stop	必填项,序列的终止值,如果endpoint为true,该值包含于数列中
3	num	要生成的等步长的样本数量,默认为50
4	endpoint	该值为 true 时,数列中包含stop值,反之不包含,默认是True。
5	base	对数 log 的底数
6	dtype	ndarray 的数据类型
m=np.logspace(1,5,3,base=2)
print(m)
#[ 2.  8. 32.]

1.5 numpy.zeros()

numpy.zeros(shape, dtype = float, order = 'C')
1	shape	数组形状
2	dtype	数据类型,可选
a=np.zeros(5)#默认是浮点数
 print(a)
 b=np.zeros((5,),dtype='int')#设置为整形
 print(b)
 #2行3列的全为0数组
 c=np.zeros((2,3),dtype='int')
 print(c)
 #zeros_like返回具有与给定数组相同的类型和形状的零数组
 d=np.array([[1,2,3],[3,4,5]])
 ar1=np.zeros_like(d)
 print(ar1)

1.6 随机函数random

np.random.rand(int1,[int2,[int3,]]) 生成(0,1)均匀分布随机数  (a),(a,b),(a,b,c)
np.random.randn(int1,[int2,[int3,]])    生成标准正态分布随机数 (a),(a,b),(a,b,c)
np.random.randint(low[,hight,size,dtype])   生成随机整数  (a,b),(a,b,c),(a,b,(c,d))
np.random.sample(size)  生成[0,1)随机数  (a),((a,b)),((a,b,c))
numpy.random.sample(size=None)
np.random.seed()
a=np.random.normal(0,1,(3,2))
print(a)#标准正态分布,3行2列
答案:
[[-1.25824438 -1.34081499]
 [-0.29187456 -2.66152465]
 [ 0.94193507  0.87134781]]
print('-'*10)
b=np.random.normal(1,3,(3,2))
print(b)#均值为1,标准差为3
答案:
[[ 1.61762335  3.03539927]
 [ 5.12487931 -5.52974249]
 [ 5.33508522 -0.52389582]]
​
ar2=np.random.sample((2,2,3))#创建2块2行三列的数组
print(ar2)
答案:[[[0.71636426 0.11516745 0.06585794]
  [0.90240284 0.71298369 0.820767  ]]
​
 [[0.92777128 0.02184985 0.47884555]
  [0.0334488  0.5479613  0.09193634]]]
​
​
使用相同的seed()值,则每次生成的随机数都相同,使得随机数可以预测
但是,只在调用的时候seed()一下并不能使生成的随机数相同,需要每次调用都seed()一下,表示种子相同,从而生成的随机数相同。
    a=np.random.seed(3)
    L1=np.random.randn(3,3)#写了几个种子就需要同时敲几个数据
    L2=np.random.randn(3,3)
    L3=np.random.randint(1,99,(5,3))
    print(L3)
    print(L1)
    print('-'*10)
    print((L2))
答案:[[ 1.78862847  0.43650985  0.09649747]
 [-1.8634927  -0.2773882  -0.35475898]
 [-0.08274148 -0.62700068 -0.04381817]]
----------
[[-0.47721803 -1.31386475  0.88462238]
 [ 0.88131804  1.70957306  0.05003364]
 [-0.40467741 -0.54535995 -1.54647732]]
​

1.7 数组其他函数

resize	返回指定形状的新数组。
append	将元素值添加到数组的末尾。
insert	沿规定的轴将元素值插入到指定的元素前。
delete	删掉某个轴上的子数组,并返回删除后的新数组。
argwhere	返回数组内符合条件的元素的索引值。
unique	用于删除数组中重复的元素,并按元素值由大到小返回一个新数组。
sort()	对输入数组执行排序,并返回一个数组副本
argsort	沿着指定的轴,对输入数组的元素值进行排序,并返回排序后的元素索引数组

1.7.1 resize

numpy.resize(arr,shape) 和ndarray.resize(shape, refcheck=False)区别:
•	numpy.resize(arr,shape),有返回值,返回复制内容.如果维度不够,会使用原数组数据补齐
•	ndarray.resize(shape, refcheck=False),修改原数组,不会返回数据,如果维度不够,会使用0补齐

1.7.2 append

在数组的末尾添加值,默认返回一个一维数组。
numpy.append(arr, values, axis=None)
参数说明:
•	arr:输入的数组;
•	values:向 arr 数组中添加的值,需要和 arr 数组的形状保持一致;
•	axis:默认为 None,返回的是一维数组;当 axis =0 时,追加的值会被添加到行,而列数保持不变,若 axis=1 则与其恰好相反。
a=np.array([[1,2,3],[3,4,5]])#[1 2 3 3 4 5 7 8 9]
#将数组a添加元素
print(np.append(a,[7,8,9]))#向数组a添加元素
print(np.append(a,[[7,8,9],[6,4,3]],axis=0))#沿轴0添加元素
答案:
[[1 2 3]
 [3 4 5]
 [7 8 9]]
print(np.append(a,[[5,5,5],[5,6,7]],axis=1))#沿轴1添加元素
答案:
 [[1 2 3 5 5 5]
  [3 4 5 5 6 7]]

1.7.3 delete

该方法表示从输入数组中删除指定的子数组,并返回一个新数组。它与 insert() 函数相似,若不提供 axis 参数,则输入数组被展开为一维数组。 numpy.delete(arr, obj, axis) 参数说明:
•	arr:要输入的数组;
•	obj:整数或者整数数组,表示要被删除数组元素或者子数组;
•	axis:沿着哪条轴删除子数组。
a=np.arange(12).reshape(3,4)
print(a)
#不提供axis参数情况
print(np.delete(a,5))#删除a数组的5元素,只删除此刻的5,不改变原数组a中的5
结果:
	[[ 0  1  2  3]
	 [ 4  5  6  7]
 	[ 8  9 10 11]]
	[ 0  1  2  3  4  6  7  8  9 10 11]
print(a)
#删除第二列
print(np.delete(a,1,axis=1))
print(a)

在 np.delete(a,1,axis=0) 中,参数 1 表示要删除的行或列的索引。具体来说,它表示要删除数组 a 的第二行(因为索引从0开始)。

此外,参数 axis=0 指定要沿着第一个维度(即行)删除元素。如果 axis=1,则会沿着第二个维度(即列)删除元素。因此,np.delete(a,1,axis=0) 会从数组 a 中删除第二行,并返回一个新的数组,该数组中不再包含该行。



a=np.array([[1,2,3],[1,6,8],[3,4,4]])
print(a)
 结果:
 [[1 2 3]
  [1 6 8]
  [3 4 4]]
print(np.delete(a,[1,2],axis=0))#删除多行
 [[1 2 3]]
#注意不能用切片的形式
ar1=np.s_[1:4]
print(ar1)#slice(1, 4, None)
ar2=np.r_[1:4]
print(ar2)#[1 2 3]
ar3=np.c_[1:4]
print(ar3)
结果:
[[1]
[2]
[3]]

r1 是一个切片对象,它代表从索引 1 到索引 4(不包括 4)的连续整数序列。使用 slice() 函数也可以得到同样的结果。在打印时,它显示为 "slice(1, 4, None)"。
ar2 是一个一维数组,由从 1 到 3 的连续整数组成。不像 ar1,它包含了 4 本身。
ar3 是一个二维数组,由一行三列的元素组成。每个元素都是从 1 到 3 的连续整数的一部分。在这个例子中,我们将每个数字转换为一个单独的列,并将它们堆叠在一起以形成一个数组。

1.7.4 argwhere

该函数返回数组中非 0 元素的索引,若是多维数组则返回行、列索引组成的索引坐标。
#普通索引寻找
x=np.arange(6).reshape(2,3)
print(x)
print(x[x>2])#返回所有索引大于2的数组元素
#numpy索引寻找
print(x)
y=np.argwhere(x>1)#返回所有大于1的元素索引
print(y,y.shape)
答案:
[[0 2]
 [1 0]
 [1 1]
 [1 2]] (4, 2)

1.7.5 unique

用于删除数组中重复的元素,其语法格式如下: numpy.unique(arr, return_index, return_inverse, return_counts)
参数说明:
•	arr:输入数组,若是多维数组则以一维数组形式展开;
•	return_index:如果为 True,则返回新数组元素在原数组中的位置(索引);
•	return_inverse:如果为 True,则返回原数组元素在新数组中的位置(索引);
•	return_counts:如果为 True,则返回去重后的数组元素在原数组中出现的次数。
a=np.array([3,4,3,2,3,446,556,45,45,3])
print(a)
uq=np.unique(a)#对数组a去重
print(uq)#[  2   3   4  45 446 556]
#数组去重后的索引数组
print('a:',a)
u,indices=np.unique(a,return_index=True)
#打印去重后数组的索引
print(u)#[  2   3   4  45 446 556]
print('-'*10)
print(indices)#[3 0 1 7 5 6]
#去重数组的下标
print(a)#[  3   4   3   2   3 446 556  45  45   3]
ui,indices=np.unique(a,return_inverse=True)
print(ui)#[  2   3   4  45 446 556]
print(indices)#[1 2 1 0 1 4 5 3 3 1]
print('-'*10)
#返回去重元素的重复数量
uc,indices=np.unique(a,return_counts=True)
print(uc)#[  2   3   4  45 446 556]
print(indices)#[1 4 1 2 1 1]

1.7.6 sort

对输入数组执行排序,并返回一个数组副本。 numpy.sort(a, axis, kind, order)
参数说明:
•	a:要排序的数组;
•	axis:沿着指定轴进行排序,如果没有指定 axis,默认在最后一个轴上排序,若 axis=0 表示按列排序,axis=1 表示按行排序;
•	kind:默认为 quicksort(快速排序);
•	order:若数组设置了字段,则 order 表示要排序的字段。
a=np.array([[1,0,5,2],[9,3,1,5]])
print('a的数组:',a)
#调用sort()函数
print('排序后的内容:',np.sort(a))
print(np.sort(a,axis=0))
print(np.sort(a,axis=1))
dt=np.dtype([('name','S10'),('age',int)])
a=np.array([('raju',21),('anni','10'),('cfs','20')],dtype=dt)
print(a)
print(np.sort(a,order='name'))#[(b'anni', 10) (b'cfs', 20) (b'raju', 21)]
print(np.sort(a,order='age'))#[(b'anni', 10) (b'cfs', 20) (b'raju', 21)]
numpy.argsort()
argsort() 沿着指定的轴,对输入数组的元素值进行排序,并返回排序后的元素索引数组。
a=np.array([1,2,3,1,2])
print('原数组:',a)
sort_ind=np.argsort(a)
print('排序后的索引值:',sort_ind)# [0 3 1 4 2]
#使用索引数组对原数组排序
sort_a=a[sort_ind]
print("打印排序数组")
for i in sort_ind:
    print(a[i],end=' ')#1 1 2 2 3
print(a[sort_ind])#[1 1 2 2 3]

1.8 切片索引

1.8.1 基本操作

#一维数组
ar1=np.arange(10)
print(ar1)
#从索引 2开始到索引 7停止,间隔为2
ar2=ar1[2:7:2]
print(ar2)#[2 4 6]
#返回索引对应的数据,(注意从0开始)
print('ar1[4]:',ar1[4])#4
print(ar1[3:])#[3 4 5 6 7 8 9]#从索引3开始,取后面所有的数据
print(ar1[9])#取元素9就填索引9
#从索引开始到索引结束(不包含结束)
ar3=np.arange(0,20,3)
print(ar3)
print(ar3[2:7])#[ 6  9 12 15 18]
print(ar3[:-2])#[ 0  3  6  9 12],到-2但不取-2
#步长,取所有数据,步长为-1
print(ar3[::-1])#[18 15 12  9  6  3  0]#相当于从大到小排序
#二维数组
#定义4行5列的数据
ar4_5=np.arange(20).reshape(4,5)
print(ar4_5)
print(ar4_5.ndim)#2#返回ar4_5的秩
#切片为下一个维度的一个元素,所以是一维数组
print(ar4_5[2])#[10 11 12 13 14]
#二次索引取得,一维数组中的元素
print(ar4_5[2][2])#12
print(ar4_5[2:])
答案:
[[10 11 12 13 14]
[15 16 17 18 19]]
#注意:切片还可以使用省略号“…”,如果在行位置使用省略号,那么返回值将包含所有行元素,反之,则包含所有列元素。
#需要获取第二列数据
print(ar4_5[...,1])#[ 1  6 11 16]
print(ar4_5[1:,...])
[[ 5  6  7  8  9]
[10 11 12 13 14]
[15 16 17 18 19]]#返回第二列后的所有项
print(ar4_5[...][2])
答案:
[10 11 12 13 14]

1.8.2 高级操作

在 NumPy 中还可以使用高级索引方式,比如整数数组索引、布尔索引,以下将对两种种索引方式做详细介绍。
​
#整数数组索引
#创建二维数组
x=np.array([
    [1,2,3,1],
    [1,2,3,4],
    [4,2,3,2]
])
#[0,1,2]代表 行索引;[0,1,0]代表 列索引
y=x[
    [0,1,2],[0,1,0]
]
#y分别获取x中的(0,0),(1,1),(2,0)的数据
x[
    [0,1,2],:
]
print(x)
#获取了4*3数组中的四个角上元素,他们对应的行索引是[0,0]和[3,3],列索引是[0,2]和[0,2]
b=np.array([[0,1,2],#(0,0)(0,2)(3,0)(3,2)
            [3,4,5],
            [6,7,8],
            [9,10,11]])
a=b[[0,0,3,3],[0,2,0,2]]
r=np.array([[0,0],[3,3]]).reshape(4)
l=np.array([[0,2],[0,2]]).reshape(4)
s=b[r,l].reshape((2,2))
print(s)
答案:
[[ 0  2]
 [ 9 11]]
#1:3==[1,2]
a=np.array([
    [1,2,3],
    [2,3,4],
    [4,5,6]
])
print(b)
答案:
[[3,4],
[5,6]]
c=a[1:3,[1,2]]
print(c)
答案:
[[3 4]
[5 6]]
d=a[...,1:]
print(d)
答案:
 [[2 3]
  [3 4]
  [5 6]]

1.8.3 布尔数组索引

# 布尔索引 实现的是通过一维数组中的每个元素的布尔型数值对一个与一维数组有着同样行数或列数的矩阵进行符合匹配。 这种作用,其实是把一维数组中布尔值为True的相应行或列给抽取了出来
# (注意:一维数组的长度必须和想要切片的维度或轴的长度一致)。
#筛选出指定区间内数据 &和 |或
x=np.array([[1,2,3],[3,4,5],[5,5,6]])
print(x[(x>2)&(x<5)])#[3 3 4]
print(x[(x<4)|(x>5)])#[1 2 3 3 6]
#True和False的形式表示需要和不需要的数据
#创建3*4的数组
a3_4=np.arange(12).reshape((3,4))
print(a3_4)
#行变量 存在3个元素
row1=np.array([False,True,True])
#列变量 存在4个元素
column1=np.array([True,False,True,False])
print(a3_4[row1])#a3_4是3行,做切片也提供3个元素的数组,轴的长度一致
[[ 4  5  6  7]
[ 8  9 10 11]]
print(a3_4[:,column1])
[[ 0  2]
[ 4  6]
[ 8 10]]
#索引形状不匹配
#从上面的结果可以知道,能够进行切片的前提是:两个一维布尔数组中True的个数需要相等,否则会出现报错
报错信息如下:indexError: shape mismatch: indexing arrays could not be broadcast together with shapes (2,) (3,)
是因为所选索引形状不匹配:索引数组无法与该形状一起广播。 当访问numpy多维数组时,用于索引的数组需要具有相同的形状(行和列)。numpy将有可能去广播,所以,若要为了实现不同维度的选择, 可分两步对数组进行选择。
1.  例如我需要选择第1行和最后一行的第1,3,4列时,先选择行,再选择列。
2.先读取数组 a3_4 的第一行和最后一行,保存到 temp ,然后再筛选相应的列即可。
print(a3_4)
#选择第一行和最后一行的第1,3,4列,操作步骤
#第一步:先选行
temp=a3_4[[0,-1],:]
print(temp)
答案:
[[ 0  1  2  3]
[ 8  9 10 11]]
#第二步:再选择列
print(temp[:,[0,2,3]])
答案:
[[ 0  2  3]
 [ 8 10 11]]
#第三步:合并一条
print(a3_4[[0,-1],:][:,[0,2,3]])
答案:
 [[ 0  2  3]
  [ 8 10 11]]
#数组索引及切片的值更改会修改原数组
ar=np.arange(10)
print(ar)#[0 1 2 3 4 5 6 7 8 9]
ab=ar[:]
ar[5]=100
print(ab)#[  0   1   2   3   4 100   6   7   8   9]#一个标量赋值给一个索引/切片时,会自动改变/传播原始数组
#可以使用复制操作
ar=np.arange(10)
b=ar.copy()
#或者b=np.array(ar)
b[7:9]=200
print('ar:',ar)#ar: [0 1 2 3 4 5 6 7 8 9]
print('b:',b)#b: [  0   1   2   3   4   5   6 200 200   9]

1.9 广播机制

广播是指 NumPy 在执行二元操作时自动处理不同形状的数组之间的情况。在进行操作之前,NumPy 将自动调整数组的形状以使它们兼容。
​
以下是一个简单的例子:
​
import numpy as np
​
# 创建两个不同形状的数组
arr1 = np.array([[1, 2, 3], [4, 5, 6]])
arr2 = np.array([10, 20, 30])
​
# 对它们执行加法操作
result = arr1 + arr2
​
print(result)
在这个例子中,我们有两个不同形状的数组:arr1 是一个 2 行 3 列的数组,而 arr2 是一个 1 行 3 列的数组。根据广播机制的规则,arr2 可以被视为一个 2 行 3 列的数组,其中每行都是 [10, 20, 30]。因此,在对两个数组执行加法操作时,NumPy 会自动将 arr2 扩展为一个 2 行 3 列的数组,以匹配 arr1 的形状,然后执行逐元素相加的操作。
​
最终结果将是以下数组:
​
[[11 22 33]
 [14 25 36]]
这就是广播机制的作用,它让我们可以轻松地对不同形状的数组进行操作,避免了手动调整数组形状的麻烦。
​
​
那怎样的数组 不能进行广播机制
​
​
数组可以广播的前提是它们的形状在某些维度上是兼容的,即这些维度的长度相等。具体来说,以下是一些必要条件:
​
数组的维数相同(或者其中一个数组是标量);
在每个维度上,两个数组的长度相等,或其中一个数组的长度为 1。
如果以上条件不满足,则不能进行广播。例如,下面的代码生成了两个不兼容的数组,无法进行广播:
​
import numpy as np
​
arr1 = np.array([1, 2, 3])       # 形状为 (3,)
arr2 = np.array([[10], [20]])   # 形状为 (2, 1)
​
result = arr1 + arr2             # 报错:ValueError: operands could not be broadcast together with shapes (3,) (2,1)
在这个例子中,arr1 是一个形状为 (3,) 的一维数组,而 arr2 是一个形状为 (2, 1) 的二维数组。由于这两个数组在第一个维度上的长度不相等,所以无法进行广播。
​
因此,在使用广播机制时,需要特别注意数组的形状,以确保它们是兼容的。
​
​
如何理解这个数组的兼容和不兼容
​
​
在编程中,数组的兼容性指的是两个或多个数组是否可以进行某些操作(如相加、拼接等)而不会发生类型或长度等方面的错误。如果操作可以成功执行,则这些数组被认为是兼容的。
​
如果两个或多个数组在其维度、元素类型或长度等方面有任何差异,则它们被认为是不兼容的。例如,一个存储整数的数组和一个存储字符串的数组就是不兼容的,因为它们的元素类型不同。又如,一个长度为3的一维数组和一个长度为2的一维数组也是不兼容的,因为它们的长度不同。
​
需要注意的是,在某些情况下,两个数组可能具有相同的维度、元素类型和长度,但由于它们在内存中的布局方式不同,它们仍可能是不兼容的。这种情况通常出现在使用不同的编程语言或者不同的编译器时。

1.10 统计函数

mean() 平均数 
•	axis = 0,将从上往下计算
•	axis = 1,将从左往右计算
median() 中位数
std() 标准差
var() 方差
max() 最大值 
min() 最小值
sum() 求和
average() 加权平均数

1.11 数据中的空值处理

需要借助用于 converters参数,传递一个字典,key为列索引,value为对列中值得处理
def parse_age(age):
    try:
        return int(age)
    except:
        return 0
user_info=np.dtype([('age','i1'),('height','i2')])
print(user_info)
data=np.loadtxt('has_title.txt',dtype=user_info,delimiter=',',usecols=(1,3),encoding='utf-8',converters={1:parse_age,3:parse_age})
print(data)

三、Series

1.1 数据结构Series创建

pd.Series(data=None, index=None, dtype=None, name=None, copy=False)
data 输入的数据,可以是列表、常量、ndarray 数组等,如果是字典,则保持参数顺序
index 索引值,必须是可散列的(不可变数据类型(str,bytes和数值类型)),并且与数据具有相同的长度,允许使用非唯一索引值。如果未提供,将默认为RangeIndex(0,1,2,…,n)
dtype 输出系列的数据类型。如果未指定,将从数据中推断
name 为Series定义一个名称
copy 表示对 data 进行拷贝,默认为 False,仅影响Series和ndarray数组
#列表/数组作为数据源创建Series
ar_list=[3,10,3,4,5]
np_rand=np.arange(1,6)
d={'a':1,1:3,'b':3,'c':2} #字典会将key做为索引
print(type(ar_list))
print('np_rand',np_rand)
s=pd.Series(ar_list)
s1=pd.Series(np_rand)
s2=pd.Series(data=d)
print("===================")
print(s)
print("===================")
print(s1)
print("===================")
print('===================')
print(s2)
print('===================')
print(type(s))
print("===================")
print(type(s1))
print("===================")
print(s.index)
print("==========通过index 和values属性取得对应的标签和值=========")
print(s1.index)#RangeIndex(start=0, stop=5, step=1)# 默认为RangeIndex(0,1,2,…,n)
print("======标签索引=========")
print(s2.index)
print("======Series值=========")
print(s2.values)#Series通过索引取值,优先使用是标签索引
print(s.values,type(s.values))#[ 3 10  3  4  5] <class 'numpy.ndarray'>
print('========通过标签取得对应的值,或者修改对应的值==========')
print(s[1])#取得索引为1 的数据
print("===========")
print(s2['a'])#1
#print(s2[0])
#1#如果标签非数值型,既可以用标签获取值,也可以用标签的下标获取值
#print(s2[1])#标签如果存在数值型的数据,就不能使用标签的下标获取值
# 和列表索引区别:
# 默认的索引RangeIndex,不能使用负值,来表示从后往前找元素,
# 获取不存在的索引值对应数据,会报错,但是可以赋值,相当于新增数据
# 可以新增不同类型索引的数据,新增不同类型索引的数据,索引的类型会发生自动变化
s[-1]=20
s["a"]=40#③新增不同类型索引的数据,索引的类型会发生自动变化
s2['s']=50#如果无值则直接添加
print(s)#①.默认的索引RangeIndex,不能使用负值,来表示从后往前找元素,
print(s.index)#Index([0, 1, 2, 3, 4, -1, 'a'], dtype='object')#②当前索引为-1,不存在,不会报错,可以添加
print(s2)
d={'a':1,'b':2,'c':3}#取得数据时,先进行标签的检查,如果标签中没有,再进行索引的检查,都不存在则报错
s=pd.Series(100,index=range(5))#通过标量创建,创建5个一样的值
0    100
1    100
2    100
3    100
4    100
print(s)
ser=pd.Series(data=d)
print(ser)
print("==================")
#取得第一个元素
print('ser["a"]:%s'%ser["a"],'ser[0]:%s'%ser[0])
print('ser["c"]:%s'%ser["c"],'ser[-1]:%s'%ser[-1])#获取最后一个值
	结果:
    ser["a"]:1 ser[0]:1
	ser["c"]:3 ser[-1]:3
index参数
	索引值,必须是可散列的(不可变数据类型(str,bytes和数值类型)),并且与数据具有相同的长度,允许使用非唯一索引值。如果未提供,将默认为RangeIndex(0,1,2,…,n)
data=np.array(['a','b','c','d'])
s=pd.Series(data,index=[100,101,102,103])#
-------------------------------------------------------====
name参数
ser.name="Data"
ser.index.name="index"
print(ser)
index
 a    1
 b    2
 c    3
 Name: Data, dtype: int64
 
 copy 表示对 data 进行拷贝,默认为 False,仅影响Series和ndarray数组
# 数组作为数据源
np_rand = np.arange(1,6)
# 使用数组创建Series
s1 = pd.Series(np_rand)
Print(s1)
# 改变Series标签为1的值
s1[1] = 50
# 输出Series对象s1
print("s1:",s1)
# 输出数组对象np_rand
print("np_rand:",np_rand)
s1: 0     1
1    50
2     3
3     4
4     5
dtype: int32
np_rand: [ 1 50  3  4  5]#源数据非Series和ndarray类型时,改变其中一个值,原列表中的值不会改变

1.2 Series的索引/切片

1.2.1 下标索引

类似于 列表索引
s = pd.Series(np.random.rand(5))
print(s)
print(s[3], type(s[3]), s[3].dtype)
上面的位置索引和标签索引刚好一致,会使用标签索引
当使用负值时,实际并不存在负数的标签索引

1.2.2 标签索引

当索引为object类型时,既可以使用标签索引也可以使用位置索引
Series 类似于固定大小的 dict,把 index 中的索引标签当做 key,而把 Series 序列中的元素值当做 value,然后通过 index 索引标签来访问或者修改元素值。
使用索标签访问单个元素值:
s = pd.Series(np.random.rand(5),index=list("abcde"))
print(s["b"], type(s["b"]), s["b"].dtype)
使用索引标签访问多个元素值
s = pd.Series([6,7,8,9,10],index = ['a','b','c','d','e'])
print(s)
# 注意需要选择多个标签的值,用[[]]来表示(相当于[]中包含一个列表)
print(s[['a','c','d']]) # s['a','c','d']
print(s1)
多标签会创建一个新的数组
s1 = s[["b","a","e"]]
s1["b"] = 10
print("s1:",s1)
print("s源数据:",s)
s1: b    10
a     6
e    10
dtype: int64
s源数据: a     6
b     7
c     8
d     9
e    10
dtype: int64

1.2.3 切片

•	Series使用标签切片运算与普通的Python切片运算不同:Series使用标签切片时,其末端是包含的。
•	Series使用python切片运算即使用位置数值切片,其末端是不包含。
通过下标切片的方式访问 Series 序列中的数据,示例如下:
s = pd.Series(np.random.rand(10))
srint(s)
# 位置索引和标签索引刚好一致,使用切片时,如果是数值会认为是python切片运算,不包含末端
print(s[1:5])
1    0.019639
2    0.542934
3    0.699685
4    0.898765
dtype: float64
s = pd.Series([1,2,3,4,5],index = ['a','b','c','d','e'])
print(s)
print(s[1:4])
# print(s[0])  #位置下标
# print(s['a']) #标签
s = pd.Series([1,2,3,4,5],index = ['a','b','c','d','e'])
print(s[:3])
# 如果想要获取最后三个元素,也可以使用下面的方式: 
s = pd.Series([1,2,3,4,5],index = ['a','b','c','d','e'])
print(s[-3:])
c    3
d    4
e    5
dtype: int64

通过标签切片的方式访问 Series 序列中的数据,示例如下:
•	Series使用标签切片时,其末端是包含的
s1= pd.Series([6,7,8,9,10],index = ['a','b','c','d','e'])
s1["b":"d"]
b    7
c    8
d    9
dtype: int64
s1= pd.Series([6,7,8,9,10],index = ['e','d','c','b','a'])
s1["c":"a"] 
s1["c":"c"]
s1= pd.Series([6,7,8,9,10],index = ['e','d','a','b','a'])
print(s1)
注意:
在上面的索引方式,我们知道了位置索引和标签索引在index为数值类型时候的不同,
当index为数值类型的时候,使用位置索引会抛出keyerror的异常,也就是说当index为数值类型的时候,索引使用的是名称索引。
但是在切片的时候,有很大的不同,如果index为数值类型的时候,切片使用的是位置切片。总的来说,当index为数值类型的时候:
进行索引的时候,相当于使用的是名称索引;
进行切片的时候,相当于使用的是位置切片;

1.3 Series 数据结构基本技巧

1.3.1 head与tail 查看数据

s = pd.Series(np.random.rand(15))
print(s)
0     0.161195
1     0.502379
2     0.627239
3     0.802458
4     0.939026
5     0.950890
6     0.506432
7     0.868867
8     0.038031
9     0.228175
10    0.668703
11    0.533114
12    0.413045
13    0.777960
14    0.758143
dtype: float64
print(s.head()) # 默认查看前5条数据
0    0.161195
1    0.502379
2    0.627239
3    0.802458
4    0.939026
dtype: float64
print(s.head(1)) # 默认查看前1条数据
print(s.tail()) # 默认查看后5条数据
10    0.668703
11    0.533114
12    0.413045
13    0.777960
14    0.758143
dtype: float64

1.3.2 reindex重新索引

使用可选填充逻辑, 使Series符合新索引
将NaN放在上一个索引中没有值的位置。除非新索引等同于当前索引,并且生成新对象。
s = pd.Series(np.random.rand(5),index=list("abcde"))
print("============s=========")
#print(s)
# 新索引在上一个索引中不存在,生成新对象时,对应的值,设置为NaN
s1 = s.reindex(list("cde"))
print("============s1=========")
print(s1)
print("============s=========")
print(s)
# 设置填充值
s2 = s.reindex(list("cde12"), fill_value=0)
print(s2)
c    0.769133
d    0.892347
e    0.703847
1    0.000000
2    0.000000
dtype: float64

1.3.3 对齐运算

是数据清洗的重要过程,可以按索引对齐进行运算,如果没对齐的位置则补NaN,最后也可以填充NaN
s1 = pd.Series(np.random.rand(3), index=["Kelly","Anne","T-C"])
s2 = pd.Series(np.random.rand(3), index=["Anne","Kelly","LiLy"])
print("==========s1=========")
print(s1)
print("==========s2=========")
print(s2)
print("==========s1+s2=========")
print(s1+s2)
==========s1=========
Kelly    0.673689
Anne     0.829721
T-C      0.592040
dtype: float64
==========s2=========
Anne     0.213418
Kelly    0.836719
LiLy     0.483435
dtype: float64
==========s1+s2=========
Anne     1.043139
Kelly    1.510409
LiLy          NaN
T-C           NaN
dtype: float64

1.3.4 删除和添加

删除
s = pd.Series(np.random.rand(5),index=list("abcde"))
print(s)
s1 = s.drop("a") # 返回删除后的值,原值不改变 ,默认inplace=False
print(s1) 
print(s)
a    0.985453
b    0.664467
c    0.654108
d    0.667644
e    0.376470
dtype: float64
b    0.664467
c    0.654108
d    0.667644
e    0.376470
dtype: float64
a    0.985453
b    0.664467
c    0.654108
d    0.667644
e    0.376470
dtype: float64
s = pd.Series(np.random.rand(5),index=list("abcde"))
s1 = s.drop("a",inplace=True) # 原值发生变化,返回None,inplace默认默认为True,返回None
#s = s.drop("a")
print(s1) 
print(s)
None
b    0.859807
c    0.412193
d    0.748246
e    0.435928
dtype: float64
# 添加
s1 = pd.Series(np.random.rand(5),index=list("abcde"))
print(s1)
s1["s"] = 100  # 对应的标签没有就是添加,,有就是修改
print(s1)

四、DataFrame

4.1创建DataFrame对象

pandas.DataFrame(data=None, index=None, columns=None, dtype=None, copy=None)
•   data: 输入的数据,可以是 ndarray,series,list,dict,标量以及一个 DataFrame
•   index: 行标签,如果没有传递 index 值,则默认行标签是 RangeIndex(0, 1, 2, …, n),n 代表 data 的元素个数。
•   columns: 列标签,如果没有传递 columns 值,则默认列标签是 RangeIndex(0, 1, 2, …, n)。
•   dtype: 要强制的数据类型。只允许使用一种数据类型。如果没有,自行推断
•   copy: 从输入复制数据。对于dict数据,copy=True,重新复制一份。对于DataFrame或ndarray输入,类似于copy=False,使用的是试图

4.1.1使用普通列表创建

# 引入numpy和pandas
import numpy as np
import pandas as pd
data = [1,2,3,4,5]
df = pd.DataFrame(data)
print(df)
   0
0  1
1  2
2  3
3  4
4  5
data = [1,2,3,4,5]
df = pd.Series(data)
print(df)
0    1
1    2
2    3
3    4
4    5
dtype: int64

4.1.2 使用嵌套列表创建

# 列表中每个元素代表一行数据
data = [['xiaowang',20],['Lily',30],['Anne',40]]
# 未分配列标签
df = pd.DataFrame(data)
print(df)
          0   1
0  xiaowang  20
1      Lily  30
2      Anne  40
data = [['xiaowang',20],['Lily',30],['Anne',40]]
# 分配列标签
df = pd.DataFrame(data,columns=['Name','Age'])
print(df)
     Name  Age
0  xiaowang   20
1      Lily   30
2      Anne   40

4.1.3 指定数值元素的数据类型为float

•	需要注意,dtype只能设置一个, 设置多个列的数据类型,需要使用其他方式
data = [['xiaowang', 20, "男", 5000],['Lily', 30, "男", 8000],['Anne', 40, "女", 10000]]
分配列标签 
df = pd.DataFrame(data,columns=['Name','Age',"gender", "salary"], dtype=int)
# int满足某列特征,会自动使用, 不满足,则自动识别
print(df)
print(df['salary'].dtype)
       Name  Age gender   salary
0  xiaowang   20      男   5000.5
1      Lily   30      男   8000.0
2      Anne   40      女  10000.0
float64

4.1.4 字典嵌套列表创建

data 字典中,键对应的值的元素长度必须相同(也就是列表长度相同)。如果传递了索引,那么索引的长度应该等于数组的长度;如果没有传递索引,那么默认情况下,索引将是 RangeIndex(0.1...n),其中 n 代表数组长度。
# 字典.3.6之前是没有的 key--->values  变量: 变量携带数据位置
# 3.7以后是有顺序的.
data = {'Name':['关羽', '刘备', '张飞', '曹操'],'Age':[28,34,29,42]}
# 通过字典创建DataFrame
df = pd.DataFrame(data)
print(df)
# 输入行标签
print(df.index)
# 输入列表区
print(df.columns)
  Name  Age
0   关羽   28
1   刘备   34
2   张飞   29
3   曹操   42
RangeIndex(start=0, stop=4, step=1)
Index(['Name', 'Age'], dtype='object')
注意:这里使用了默认行标签,也就是 RangeIndex(0.1...n)。它生成了 0,1,2,3,并分别对应了列表中的每个元素值。

4.1.5 添加自定义的行标签

# 字典
data = {'Name':['关羽', '刘备', '张飞', '曹操'],'Age':[28,34,29,42]}
# 定义行标签
index = ["rank1", "rank2", "rank3", "rank4"]
# 通过字典创建DataFrame
df = pd.DataFrame(data, index=index)
print(df)
# 输入行标签
print(df.index)
# 输出列表标签
print(df.columns)
      Name  Age
rank1   关羽   28
rank2   刘备   34
rank3   张飞   29
rank4   曹操   42
Index(['rank1', 'rank2', 'rank3', 'rank4'], dtype='object')
Index(['Name', 'Age'], dtype='object')

4.1.6 列表嵌套字典创建DataFrame对象

列表嵌套字典可以作为输入数据传递给 DataFrame 构造函数。默认情况下,字典的键被用作列名。
data = [{'a': 1, 'b': 2},{'a': 5, 'b': 10, 'c': 20}]
#df = pd.DataFrame(data)
df = pd.DataFrame(data, index=['first', 'second'])
​
print(df)
        a   b     c
first   1   2   NaN
second  5  10  20.0
注意:如果其中某个元素值缺失,也就是字典的 key 无法找到对应的 value,将使用 NaN 代替。
如何使用列表嵌套字典创建一个 DataFrame 对象,可以设置结果需要那些列
data = [{'a': 1, 'b': 2},{'a': 5, 'b': 10, 'c': 20}]
# 注意:因为 b1 在字典键中不存在,所以对应值为 NaN。 
df2 = pd.DataFrame(data, index=['first', 'second'], columns=['a', 'b1'])
print("===========df1============")
print(df1)
print("===========df2============")
print(df2)
===========df1============
        a   b
first   1   2
second  5  10
===========df2============
        a  b1
first   1 NaN
second  5 NaN

4.1.7 Series创建DataFrame对象

您也可以传递一个字典形式的 Series,从而创建一个 DataFrame 对象,其输出结果的行索引是所有 index 的合集
d = {'one' : pd.Series([1, 2, 3], index=['a', 'b', 'c']),
   'two' : pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])}
df = pd.DataFrame(d)
print(df)
   one  two
a  1.0    1
b  2.0    2
c  3.0    3
d  NaN    4
print(type(np.NaN))
float
注意:对于 one 列而言,此处虽然显示了行索引 'd',但由于没有与其对应的值,所以它的值为 NaN。
# 创建数据
data = {
    "Name":pd.Series(['xiaowang', 'Lily', 'Anne']),
    "Age":pd.Series([20, 30, 40],  dtype=float),
    "gender":pd.Series(["男", "男", "女"]),
    "salary":pd.Series([5000, 8000, 10000], dtype=float)
}
df = pd.DataFrame(data)
# int满足某列特征,会自动使用, 不满足,则自动识别
print(df)# 解决不同列 设置自定义数据类型
Name        Age      gender  salary
0    xiaowang    20.0        男    5000.0
1     Lily       30.0        男    8000.0
2     Anne       40.0        女    10000.0

4.2 列操作DataFrame

4.2.1 选取数据列

•	可以使用列索引,轻松实现数据选取
data = {'Name':['关羽', '刘备', '张飞', '曹操'],'Age':[28,34,29,42]}
# 定义行标签
index = ["rank1", "rank2", "rank3", "rank4"]
# 通过字典创建DataFrame
df = pd.DataFrame(data, index=index)
print(df)
print("=========df['Name']:取得Name列===============")
print(df['Name'])
print("=========df['Age']:取得Age列===============")
print(df['Age'])
      Name  Age
rank1   关羽   28
rank2   刘备   34
rank3   张飞   29
rank4   曹操   42
=========df['Name']:取得Name列===============
rank1    关羽
rank2    刘备
rank3    张飞
rank4    曹操
Name: Name, dtype: object
=========df['Age']:取得Age列===============
rank1    28
rank2    34
rank3    29
rank4    42
Name: Age, dtype: int64
print("=========df[['Name', 'Age']]:df选取多列===============")
print(df[['Name', 'Age']])


=========df[['Name', 'Age']]:df选取多列===============
      Name  Age
rank1   关羽   28
rank2   刘备   34
rank3   张飞   29
rank4   曹操   42
In [ ]:
 
# 注意列不是能使用切片选取多列
print("=========df不能使用切片选取多列===============")
print(df['Name': 'Age'])   # 空DataFrame
没有办法直接通过标签位置去获取列
print(df[1])  # 会报错

4.2.2 列添加

•   使用 columns 列索引标签可以实现添加新的数据列,示例如下
In [36]:
 
d = {'one' : pd.Series([1, 2, 3], index=['a', 'b', 'c']),
   'two' : pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])}
df = pd.DataFrame(d)
#使用df['列']=值,插入新的数据列
print ("====通过Series添加一个新的列====:")
df['three']=pd.Series([10,20,30],index=['a','b','c'])
print(df)
#将已经存在的数据列相加运算,从而创建一个新的列
print ("======将已经存在的数据列相加运算,从而创建一个新的列:=======")
df['four']=df['one']+df['three']
print(df)
​
​
====通过Series添加一个新的列====:
   one  two  three
a  1.0    1   10.0
b  2.0    2   20.0
c  3.0    3   30.0
d  NaN    4    NaN
======将已经存在的数据列相加运算,从而创建一个新的列:=======
   one  two  three  four
a  1.0    1   10.0  11.0
b  2.0    2   20.0  22.0
c  3.0    3   30.0  33.0
d  NaN    4    NaN   NaN
df['error']=pd.Series([10,20,30],index=['b','a','s3'])
print(df)
   one  two  three  four  error
a  1.0    1   10.0  11.0   20.0
b  2.0    2   20.0  22.0   10.0
c  3.0    3   30.0  33.0    NaN
d  NaN    4    NaN   NaN    NaN

4.2.3 insert()方法添加

上述示例,我们初次使用了 DataFrame 的算术运算,这和 NumPy 非常相似。除了使用df[]=value的方式外,您还可以使用 insert() 方法插入新的列,示例如下: df.insert(loc, column, value, allow_duplicates=False)
•   loc : 整型,插入索引,必须验证0<=loc<=len(列)
•   column : 插入列的标签,类型可以是(字符串/数字/散列对象)
•   value : 数值,Series或者数组
•   allow_duplicates : 允许重复,可以有相同的列标签数据,默认为False
info=[['王杰',18],['李杰',19],['刘杰',17]]
df=pd.DataFrame(info,columns=['name','age'])
print(df)
#注意是column参数
#数值1代表插入到columns列表的索引位置 :loc : 整型,插入索引,必须验证0<=loc<=len(列)
df.insert(1,column='score',value=[91,90,75])
print("=====df.insert插入数据:=======")
print(df)
  name  age
0   王杰   18
1   李杰   19
2   刘杰   17
=====df.insert插入数据:=======
  name  score  age
0   王杰     91   18
1   李杰     90   19
2   刘杰     75   17
# 可以添加重复列标签数据
df.insert(1,column='score',value=[80,70,90],allow_duplicates=True)#取决于值是否可以重复
print(df)
  name  score  score  age
0   王杰     80     91   18
1   李杰     70     90   19
2   刘杰     90     75   17
df['score']
    score   score
0   80  91
1   70  90
2   90  75
# 如果存在相同的列名,会报错
df.insert(1,column='score',value=[80,70,90]) # 错误 cannot insert name, already exists

4.2.4 删除列数据

•	通过 del 和 pop() 都能够删除 DataFrame 中的数据列,pop有返回值
示例如下:
d = {'one' : pd.Series([1, 2, 3], index=['a', 'b', 'c']),
     'two' : pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd']),
     'three' : pd.Series([10,20,30], index=['a','b','c'])}
df = pd.DataFrame(d)
print ("Our dataframe is:")
print(df)
#使用del删除
del df['one']
print("=======del df['one']=========")
print(df)
#使用pop方法删除
res_pop = df.pop('two')
print("=======df.pop('two')=========")
print(df)
print("=======res_pop = df.pop('two')=========")
print(res_pop)#删除的那列的数据
Our dataframe is:
   one  two  three
a  1.0    1   10.0
b  2.0    2   20.0
c  3.0    3   30.0
d  NaN    4    NaN
=======del df['one']=========
   two  three
a    1   10.0
b    2   20.0
c    3   30.0
d    4    NaN
=======df.pop('two')=========
   three
a   10.0
b   20.0
c   30.0
d    NaN
=======res_pop = df.pop('two')=========
a    1
b    2
c    3
d    4
Name: two, dtype: int64
my_dict ={"name":"xiao网","age":20}
del my_dict["name"]
my_dict

4.3 行操作DataFrame

4.3.1 标签选取

•   行操作需要借助loc属性来完成:按标签或布尔数组访问一组行和列
# 定义字典
d = {'one' : pd.Series([1, 2, 3], index=['a', 'b', 'c']),
     'two' : pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])}
# 创建DataFrame数据结构
df = pd.DataFrame(d)
print("===========df原始数据========")
print(df)
# 确定标签为b的数据
print("===========标签为b的数据========")
print(df.loc['b'])
===========df原始数据========
   one  two
a  1.0    1
b  2.0    2
c  3.0    3
d  NaN    4
===========标签为b的数据========
one    2.0
two    2.0
Name: b, dtype: float64
注意:loc 允许接受两个参数分别是行和列
# b行 one列交叉的数据
df.loc['b',"one"]
2.0
行和列还可以使用切片
# 标签为b的行到标签为d的行, 对应标签为one的列
df.loc['b':'d',"one"]   # 注意使用行标签切片,包含结束的行
b    2.0
c    3.0
d    NaN
Name: one, dtype: float64
# 注意这里和numpy整数数组索引区别
df.loc[['a','b'],["one","two"]]
# 这里两个参数,第一个代表行,第二个代表列
    one two
a   1.0 1
b   2.0 2
s = np.arange(12).reshape((3,4))
print(s)
# 1行1列和3行4列分别相交的数据
s[[0,2],[0,3]]#array([ 0, 11])

4.3.2 数值型索引和切片

•   使用数据型索引 需要使用iloc属性
直接使用索引,会优先查找的是列标签,如果找不到会报错.列没有位置索引
•   可以使用iloc :行基于整数位置的按位置选择索引
data = {'Name':['关羽', '刘备', '张飞', '曹操'],'Age':[28,34,29,42]}
# 定义行标签
index = ["rank1", "rank2", "rank3", "rank4"]
# 通过字典创建DataFrame
df = pd.DataFrame(data, index=index)
print(df)
    Name    Age
rank1   关羽  28
rank2   刘备  34
rank3   张飞  29
rank4   曹操  42
# 取得位置索引为2的数据
df.iloc[2]
Name    张飞
Age     29
Name: rank3, dtype: object
# 取得位置索引分别为0和2的数据
df.iloc[[0,2]]
    Name    Age
rank1   关羽  28
rank3   张飞  29
# 表示行索引为0,列索引为1的数据
df.iloc[0,1]
28
注意:
•   loc使用的是标签
•   iloc使用的是位置索引
两者不能混用,比如在loc中使用位置索引,或者在iloc中使用标签索引
错误写法:
# 错误写法:
#df.loc[1,"Name"]
# 或者
#df.iloc[1,"Name"]

4.3.3 切片操作多行选取

可以直接使用数值型切片操作行.和使用iloc同样的结果
data = {'Name':['关羽', '刘备', '张飞', '曹操'],'Age':[28,34,29,42]}
# 定义行标签
index = ["rank1", "rank2", "rank3", "rank4"]
# 通过字典创建DataFrame
df = pd.DataFrame(data, index=index)
print(df)
    Name    Age
rank1   关羽  28
rank2   刘备  34
rank3   张飞  29
rank4   曹操  42
# 取得位置索引1到3行,但是不包含3的数据
print("=====df.iloc[1:3]:=======")
print(df.iloc[1:3])
=====df.iloc[1:3]:=======
      Name  Age
rank2   刘备   34
rank3   张飞   29
# 使用切片可以直接提取行
print("=====df[1:3]:=======")
print(df[1:3])
=====df[1:3]:=======
      Name  Age
rank2   刘备   34
rank3   张飞   29

4.3.4 添加数据行

使用 append() 函数,可以将新的数据行添加到 DataFrame 中,该函数会在行末追加数据行
df.append(other, ignore_index=False, verify_integrity=False, sort=False)
将"other"追加到调用者的末尾,返回一个新对象。"other"行中不在调用者中的列将作为新列添加。
•   other : DataFrame或Series/dict类对象,或这些对象的列表
•   ignore_index : 默认为False,如果为True将不适用index 标签.
•   verify_integrity : 默认为False如果为True,则在创建具有重复项的索引时引发ValueError.
•   sort : 排序
import pandas as pd
data = {
            'Name':['关羽', '刘备', '张飞', '曹操'], 
            'Age':[28, 34, 29, 42],
            "Salary":[5000, 8000, 4500, 10000]
       }
df = pd.DataFrame(data)
print(df)
    Name    Age Salary
0   关羽  28  5000
1   刘备  34  8000
2   张飞  29  4500
3   曹操  42  10000
1). 追加字典
d2 = {"Name":"诸葛亮", "Age":30}
#在行末追加新数据行
df3 = df.append(d2) # 需要添加 ignore_index=True
print(df3)
错误提示:
Can only append a Series if ignore_index=True or if the Series has a name
仅当ignore_index=True或序列有名称时,才能追加序列
或者
Series数据有name
d2 = {"Name":"诸葛亮", "Age":30}
#在行末追加新数据行
df3 = df.append(d2, ignore_index=True) # 需要添加 
print(df3)
  Name  Age   Salary
0   关羽   28   5000.0
1   刘备   34   8000.0
2   张飞   29   4500.0
3   曹操   42  10000.0
4  诸葛亮   30      NaN
d2 = {"Name":"诸葛亮", "Age":30}
s = pd.Series(d2, name="a")
print(s)
#在行末追加新数据行
df3 = df.append(s) # 需要添加 
print(df3)
Name    诸葛亮
Age      30
Name: a, dtype: object
  Name  Age   Salary
0   关羽   28   5000.0
1   刘备   34   8000.0
2   张飞   29   4500.0
3   曹操   42  10000.0
2).追加列表
•   如果list是一维的,则以列的形式追加
•   如果list是二维的,则以行的形式追加
•   如果list是三维的,只添加一个值
注意:使用append可能会出现相同的index,想避免的话,可以使用ignore_index=True
data = [
            [1, 2, 3, 4],
            [5, 6, 7, 8]
       ]
            
df = pd.DataFrame(data)
print(df)
   0  1  2  3
0  1  2  3  4
1  5  6  7  8
•   list是一维,则以列的形式追加
a_l = [10,20]
df3 = df.append(a_l) # 需要添加 
print(df3)
    0    1    2    3
0   1  2.0  3.0  4.0
1   5  6.0  7.0  8.0
0  10  NaN  NaN  NaN
1  20  NaN  NaN  NaN
a_l = [[10],[20]]
df3 = df.append(a_l) # 需要添加 
print(df3)
    0    1    2    3
0   1  2.0  3.0  4.0
1   5  6.0  7.0  8.0
0  10  NaN  NaN  NaN
1  20  NaN  NaN  NaN
a_l = [10,20,30]
df3 = df.append(a_l,ignore_index=True) # 需要添加 
print(df3)
•   list是二维的,则以行的形式追加
a_l = [[10,"20",30],[2,5,6]]
df4 = df.append(a_l) # 需要添加 
print(df4)
    0   1   2    3
0   1   2   3  4.0
1   5   6   7  8.0
0  10  20  30  NaN
1   2   5   6  NaN
print("=========使用:ignore_index=True===========")
df5 = df.append(a_l,ignore_index=True) # 需要添加 
print(df5)
=========使用:ignore_index=True===========
    0   1   2    3
0   1   2   3  4.0
1   5   6   7  8.0
2  10  20  30  NaN
3   2   5   6  NaN
data = {
            'Name':['关羽', '刘备', '张飞', '曹操'], 
            'Age':[28, 34, 29, 42],
            "Salary":[5000, 8000, 4500, 10000]
       }
df = pd.DataFrame(data)
a_l = [[10,"20",30],[2,5,6]]
df2 = pd.DataFrame(a_l,columns=["Name","Age","Salary"])
# 将df2追加到df中返回
df4 = df.append(df2) # 需要添加  
print(df4)
  Age Name  Salary
0  28   关羽    5000
1  34   刘备    8000
2  29   张飞    4500
3  42   曹操   10000
0  20   10      30
1   5    2       6
data = [
            [1, 2, 3, 4],
            [5, 6, 7, 8]
       ]
            
df = pd.DataFrame(data)
print(df)
a_l = [[10,"20",30],[2,5,6]]
df5 = df.append(a_l,ignore_index=True)
df5
   0  1  2  3
0  1  2  3  4
1  5  6  7  8
Out[22]:
    0   1   2   3
0   1   2   3   4.0
1   5   6   7   8.0
2   10  20  30  NaN
3   2   5   6   NaN
注意:append不改变原数据  
s = [[[1,2,3,4]]]
df.append(s)
    0   1   2   3
0   1   2.0 3.0 4.0
1   5   6.0 7.0 8.0
0   [1, 2, 3, 4]    NaN NaN NaN

4.3.5 删除数据行

您可以使用行索引标签,从 DataFrame 中删除某一行数据。如果索引标签存在重复,那么它们将被一起删除。示例如下:
df = pd.DataFrame([[1, 2], [3, 4]], columns = ['a','b'])
df2 = pd.DataFrame([[5, 6], [7, 8]], columns = ['a','b'])
df = df.append(df2)
print("=======源数据df=======")
print(df)
=======源数据df=======
   a  b
0  1  2
1  3  4
0  5  6
1  7  8
print(df)
    a   b
0   1   2
1   3   4
0   5   6
1   7   8
#注意此处调用了drop()方法,注意drop默认不会更改源数据
df1 = df.drop(0)
print("=======修改后数据df1=======")
print(df1)
=======修改后数据df1=======
   a  b
1  3  4
1  7  8
df = df.drop(0)
df = df.drop(1,inplace=True)
print(df)
None
# 两种方式解决:
# 1. 源数据=修改后的数据
df = df.drop(0)
# 2.添加inplace=True
df = df.drop(1)

4.4 常用属性和方法

名称  属性&方法描述
T   行和列转置。
axes    返回一个仅以行轴标签和列轴标签为成员的列表。
dtypes  返回每列数据的数据类型。
empty   DataFrame中没有数据或者任意坐标轴的长度为0,则返回True
columns 返回DataFrame所有列标签
shape   返回一个元组,获取行数和列数,表示了 DataFrame 维度。
size    DataFrame中的元素数量。
values  使用 numpy 数组表示 DataFrame 中的元素值。
head()  返回前 n 行数据。
tail()  返回后 n 行数据。
rename()    rename(columns=字典) ,修改列名
info()  可以显示信息,例如行数/列数,总内存使用量,每列的数据类型以及不缺少值的元素数
sort_index()    默认根据行标签对所有行排序,或根据列标签对所有列排序,或根据指定某列或某几列对行排序。
sort_values()   既可以根据列数据,也可根据行数据排序
import pandas as pd
data = {
            'Name':['关羽', '刘备', '张飞', '曹操'], 
            'Age':[28, 34, 29, 42],
            "Salary":[5000, 8000, 4500, 10000]
       }
df = pd.DataFrame(data)
df
    Name    Age Salary
0   关羽  28  5000
1   刘备  34  8000
2   张飞  29  4500
3   曹操  42  10000
转置
返回 DataFrame 的转置,也就是把行和列进行交换。
df.T
#源数据没有发生变化
​
    0   1   2   3
Name    关羽  刘备  张飞  曹操
Age 28  34  29  42
Salary  5000    8000    4500    10000
axes
返回一个行标签、列标签组成的列表。
print(df.axes)
[df.index,df.columns]
[RangeIndex(start=0, stop=4, step=1), Index(['Name', 'Age', 'Salary'], dtype='object')]
[RangeIndex(start=0, stop=4, step=1),
 Index(['Name', 'Age', 'Salary'], dtype='object')]
dtypes
返回Series,每一列的数据类型。示例如下:
print(df.dtypes)
Name      object
Age        int64
Salary     int64
dtype: object
empty
返回一个布尔值,判断输出的数据对象是否为空,若为 True 表示对象为空。
print(df.empty)  # 返回假
False
# 创建一个空的DataFrame
empty_df = pd.DataFrame()
Print(empty_df.empty)   # 返回真
True
如果给DataFrame数据类型直接判断真假,报错:
The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
DataFrame是一个模糊的数据类型
def my_fun(df):   
    # df如果为真,我进行操作
    if not df.empty:
        print("提供的数据正常")
    else:
        # 不为真
        print("提供的数据为空")
# df----有数据   empty_df-没有数据
#my_fun(df)
my_fun(empty_df)
提供的数据为空
columns
返回DataFrame所有列标签
df.columns
Index(['Name', 'Age', 'Salary'], dtype='object')
# 可以通过df.columns的个数获取DataFrame列个数
len(df.columns)
3
df.columns.size
3
shape
返回一个元组,获取行数和列数,表示了 DataFrame 维度。
df.shape
(4, 3)
row_num,column_num = df.shape
print(row_num,column_num )
4 3
values
以 ndarray 数组的形式返回 DataFrame 中的数据
df.values
array([['关羽', 28, 5000],
       ['刘备', 34, 8000],
       ['张飞', 29, 4500],
       ['曹操', 42, 10000]], dtype=object)
head()&tail()查看数据
#获取前3行数据
df.head(3)
    Name    Age Salary
0   关羽  28  5000
1   刘备  34  8000
2   张飞  29  4500
#获取后3行数据
df.tail(3)
    Name    Age Salary
1   刘备  34  8000
2   张飞  29  4500
3   曹操  42  10000
修改标签名rename()
DataFrame.rename(index=None, columns=None, inplace=False)
•   index: 修改后的行标签
•   columns: 修改后的列标签
•   inplace: 默认为False,不改变源数据,返回修改后的数据. True更改源数据
可以修改部分行或者列
print(df)
    Name    Age Salary
0   关羽  28  5000
1   刘备  34  8000
2   张飞  29  4500
3   曹操  42  10000
# 修改变量df的行标签
df.rename(index={1:"row2", 2:"row3"})
    Name    Age Salary
0   关羽  28  5000
row2    刘备  34  8000
row3    张飞  29  4500
3   曹操  42  10000
# 修改变量df的列标签
df.rename(columns = {"Name":"name", "Age":"age"})
    name    age Salary
0   关羽  28  5000
1   刘备  34  8000
2   张飞  29  4500
3   曹操  42  10000
df
# 添加inplace参数,修改原数据
df.rename(index={1:"row2", 2:"row3"}, columns = {"Name":"name", "Age":"age"}, inplace=True)
df
    name    age Salary
0   关羽  28  5000
row2    刘备  34  8000
row3    张飞  29  4500
3   曹操  42  10000
info()函数
用于打印DataFrame的简要摘要,显示有关DataFrame的信息,包括索引的数据类型dtype和列的数据类型dtype,非空值的数量和内存使用情况。
# 创建一组数据
data = {"name":"诸葛亮","age":30}
# 将数据追加到df数据中
df = df.append(data, ignore_index =True)
df
    name    age Salary
0   关羽  28  5000.0
1   刘备  34  8000.0
2   张飞  29  4500.0
3   曹操  42  10000.0
4   诸葛亮 30  NaN
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5 entries, 0 to 4
Data columns (total 3 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   name    5 non-null      object 
 1   age     5 non-null      int64  
 2   Salary  4 non-null      float64
dtypes: float64(1), int64(1), object(1)
memory usage: 248.0+ bytes
我们来看一看都有些什么信息:
•   <class 'pandas.core.frame.DataFrame'>: 是说数据类型为DataFrame
•   RangeIndex: 5 entries, 0 to 4: 有5条数据(5行),索引为0-4
•   Data columns (total 3 columns): 该数据帧有3列
•   #: 索引号,不用太在意
•   column: 每列数据的列名
•   Non-Null count: 每列数据的数据个数,缺失值NaN不作计算。可以看出上面Salary列数据有缺失值。
•   Dtype: 数据的类型。
•   dtypes: float64(1), int64(1), object(1): 数据类型的统计
•   memory usage: 248.0+ bytes: 该数据帧占用的运行内存(RAM)
df. sort_index()
sort_index(axis=0, ascending=True, inplace=False)
作用:默认根据行标签对所有行排序,或根据列标签对所有列排序,或根据指定某列或某几列对行排序。
注意:df.sort_index()可以完成和df.sort_values()完全相同的功能,但python更推荐用只用df.sort_index()对“根据行标签”和“根据列标签”排序,其他排序方式用df.sort_values()。
•   axis:0按照行名排序;1按照列名排序
•   ascending:默认True升序排列;False降序排列
•   inplace:默认False,否则排序之后的数据直接替换原来的数据
df = pd.DataFrame({'b':[1,2,2,3],'a':[4,3,2,1],'c':[1,3,8,2]},index=[2,0,1,3]) 
df
    b   a   c
2   1   4   1
0   2   3   3
1   2   2   8
3   3   1   2
#默认按“行标签”升序排序,或df.sort_index(axis=0, ascending=True)
df.sort_index() 
    b   a   c
0   2   3   3
1   2   2   8
2   1   4   1
3   3   1   2
#按“列标签”升序排序
df.sort_index(axis=1) 
    a   b   c
2   4   1   1
0   3   2   3
1   2   2   8
3   1   3   2
#按“列标签”升序排序
df.sort_index(axis=1, inplace=True) 
df
    a   b   c
2   4   1   1
0   3   2   3
1   2   2   8
3   1   3   2
df.sort_values()
DataFrame.sort_values(by, axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last')
作用:既可以根据列数据,也可根据行数据排序。
注意:必须指定by参数,即必须指定哪几行或哪几列;无法根据index名和columns名排序(由.sort_index()执行)
•   by:str or list of str;如果axis=0,那么by="列名";如果axis=1,那么by="行名"。
•   axis:{0 or ‘index’, 1 or ‘columns’}, default 0,默认按照列排序,即纵向排序;如果为1,则是横向排序。
•   ascending:布尔型,True则升序,如果by=['列名1','列名2'],则该参数可以是[True, False],即第一字段升序,第二个降序。
•   inplace:布尔型,是否用排序后的数据框替换现有的数据框。
na_position:{‘first’, ‘last’}, default ‘last’,默认缺失值排在最后面。
# 源数据
df = pd.DataFrame({'b':[1,2,3,2],'a':[4,3,2,1],'c':[1,3,8,2]},index=[2,0,1,3]) 
df
    b   a   c
2   1   4   1
0   2   3   3
1   3   2   8
3   2   1   2
1.  按b列升序排序
#等同于df.sort_values(by='b',axis=0)
df.sort_values(by='b') 
    b   a   c
2   1   4   1
0   2   3   3
3   2   1   2
1   3   2   8
1.  先按b列降序,再按a列升序排序
df.sort_values(by=['b','a'],ascending=[False,True]) 
#等同于df.sort_values(by=['b','a'],axis=0,ascending=[False,True])
Out[98]:
    b   a   c
1   3   2   8
3   2   1   2
0   2   3   3
2   1   4   1
按行3升序排列
df.sort_values(by=3,axis=1) #必须指定axis=1
    a   b   c
2   4   1   1
0   3   2   3
1   2   3   8
3   1   2   2
1.  按行3升序,行0降排列
df.sort_values(by=[3,0],axis=1,ascending=[True,False])
    a   c   b
2   4   1   1
0   3   3   2
1   2   8   3
3   1   2   2
注意:指定多列(多行)排序时,先按排在前面的列(行)排序,如果内部有相同数据,再对相同数据内部用下一个列(行)排序,
以此类推。如何内部无重复数据,则后续排列不执行。即首先满足排在前面的参数的排序,再排后面参数
补充: 错误提示
错误提示:
•   If using all scalar values, you must pass an index: (直接传入一组标量,必须通过index写入)
# 一组数据,字典的value只有一个值
dict_1 = {"Name":"诸葛亮", "Age":30}
df = pd.DataFrame(dict_1) # 提示:If using all scalar values, you must pass an index
df
# 方案1:将字典的value修改为列表
dict_1 = {"Name":["诸葛亮"], "Age":[30]}
df = pd.DataFrame(dict_1) 
df
    Name    Age
0   诸葛亮 30
# 方案2:创建DF是添加一个index参数为[0]
dict_1 = {"Name":["诸葛亮"], "Age":[30]}
df = pd.DataFrame(dict_1,index =[0])
# index  不能直接=0 ,index个数对应的数据行数
df
    Name    Age
0   诸葛亮 30
错误提示:
•   The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().(数据为真是模糊的)
直接对DataFrame为空进行判断,出错
df = pd.DataFrame()
if df:
    print("df中存在数据")
else:
    print("df中不存在数据")
df = pd.DataFrame()
if not df.empty:
    print("df中存在数据")
else:
print("df中不存在数据")

五、Time与Datetime

1 time

一、time模块
不牵扯时区的问题,便于计算
a、timestamp时间戳,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量
b、struct_time时间元组,共有九个元素组。
c、format time 格式化时间,已格式化的结构使时间更具可读性。包括自定义格式和固定格式。
主要time生成方法和time格式转换方法实例:
# 导入time模块
import time
# 生成timestamp
time.time()
int(time.time())
# 程序开始时间
start_time = time.time()
# 程序
s = ""
for i in range(10000):
    s += str(i)
end_time = time.time()
print("程序消耗时间=",end_time-start_time)
#生成struct_time
# timestamp to struct_time 本地时间
my_time = time.localtime()
print(my_time)
print(my_time.tm_year)
print(my_time.tm_mon)
print(my_time.tm_mday)
# 将timsstamp转化为 struct_time
time.localtime(1650177058)
#格式化字符串到 struct_time
time.strptime('2011-05-05 16:37:06', '%Y-%m-%d %X')
time.mktime(time.strptime('2011-05-05 16:37:06', '%Y-%m-%d %X'))
#生成format_time
#struct_time to format_time
time.strftime("%Y-%m-%d %X")
#time.strftime("%Y-%m-%d %X",time.localtime())
#生成format_time
#struct_time to format_time
time.strftime("%Y-%m-%d")
#time.strftime("%Y-%m-%d %X",time.localtime())
#生成format_time
#struct_time to format_time
time.strftime("%m-%d-%Y")
#time.strftime("%Y-%m-%d %X",time.localtime())
struct_time元组元素结构
属性 值
•	tm_year(年) 比如2011
•	tm_mon(月) 1 - 12
•	tm_mday(日) 1 - 31
•	tm_hour(时) 0 - 23
•	tm_min(分) 0 - 59
•	tm_sec(秒) 0 - 61
•	tm_wday(weekday) 0 - 6(0表示周日)
•	tm_yday(一年中的第几天) 1 - 366
•	tm_isdst(是否是夏令时) 默认为-1
作用:
•	取得 时间戳/时间格式的字符串 中对应的 年/月/日等信息
•	作为时间戳和字符串时间之间的桥梁
time_stuct = time.strptime('2011-05-07 16:37:06', '%Y-%m-%d %X')
print(time_stuct.tm_year)
print(time_stuct.tm_mon)
print(time_stuct.tm_mday)
print(time_stuct.tm_hour)
print(time_stuct.tm_min)
my = 'aaa'
'%s'% my
my_int = 1
'%d'% my_int

"我们在{}工作".format('家里')
addr = "家里"

f"我们在{addr}工作"
format time结构化表示
格式 含义
•	%Y -年[0001,...,2018,2019,...,9999]
•	%m -月[01,02,...,11,12]
•	%d -天[01,02,...,30,31]
•	%H -小时[00,01,...,22,23
•	%M -分钟[00,01,...,58,59]
•	%S -秒[00,01,...,58,61]
•	%X 本地相应时间
•	%y 去掉世纪的年份(00 - 99)
常见结构化时间组合
time.strftime("%Y-%m-%d %X")
time.strftime("%Y-%m-%d")
time.strftime("%m")
time运算
#获取明天的这个时间点
import time
t1 = time.time()
#timestamp加减单位以秒为单位
t2=t1+24*60*60

time.strftime("%Y-%m-%d %X",time.localtime(t2))
# 倒计时
for i in range(5):
    print('\r',' %s 秒!' % (5-i), end='')
    # 暂停1s后运行
    time.sleep(1)
print('\r',"发射!!!!")

2 datetime

2.1date类

datetime.date(year, month, day)
静态方法和字段
•   date.today():返回一个表示当前本地日期的date对象;
•   date.fromtimestamp(timestamp):根据给定的时间戮,返回一个date对象;
from datetime import date
import time
print('date.today():', date.today())
print('date.fromtimestamp():', date.fromtimestamp(time.time()))
from datetime import date
print(type(date.fromtimestamp(1650177058)))
print(date.fromtimestamp(1650177058))
方法和属性
d1 = date(2011,06,03) #date对象
•   d1.year、date.month、date.day:年、月、日;
•   d1.replace(year, month, day):生成一个新的日期对象,用参数指定的年,月,日代替原有对象中的属性。(原有对象仍保持不变)
•   d1.timetuple():返回日期对应的time.struct_time对象;
•   d1.weekday():返回weekday,如果是星期一,返回0;如果是星期2,返回1,以此类推;
•   d1.isoweekday():返回weekday,如果是星期一,返回1;如果是星期2,返回2,以此类推;
•   d1.isoformat():返回格式如'YYYY-MM-DD’的字符串;
•   d1.strftime(fmt):和time模块format相同。
now = date.today()
now
print(now.replace(day=1))
date.today().replace(day=1)
now
now.isoformat()
now.isoweekday()
#'2022.04.18'  自定义输出格式
now.strftime('%Y.%m.%d')
now = date(2021, 10, 26)
print(now.year,now.month,now.day)
tomorrow = now.replace(day = 1)
print('now:', now, ', 当月第一天:', tomorrow)
print('timetuple():', now.timetuple()) 
print('weekday():', now.weekday())
print('isoweekday():', now.isoweekday())
print('isoformat():', now.isoformat())
print('strftime():', now.strftime("%Y.%m.%d")) 

2.2 datetime

datetime相当于date和time结合起来。
datetime.datetime (year, month, day[ , hour[ , minute[ , second[ , microsecond[ , tzinfo] ] ] ] ] )
静态方法
•   datetime.today():返回一个表示当前本地时间的datetime对象;
•   datetime.now([tz]):返回一个表示当前本地时间的datetime对象,如果提供了参数tz,则获取tz参数所指时区的本地时间;
•   datetime.fromtimestamp(timestamp[, tz]):根据时间戮创建一个datetime对象,参数tz指定时区信息;
•   datetime.strptime(date_string, format):将格式字符串转换为datetime对象;
    from  datetime import datetime
now = datetime.now()
print(type(now))
# 将datetime转化为指定格式的字符串
print(now.strftime('%Y-%m-%d %X'))
print(now.strftime('%Y-%m-%d %H:%M'))
# '2021-11-25 10:23' ,使用strptime 将字符串转datetime
my_str = '2021-11-10 10:23'
print(datetime.strptime(my_str,'%Y-%m-%d %H:%M'))
​
# 需要注意,将字符串转化为datetime数据类型,格式需要统一.
my_str = '10/11/2021 10:23'
datetime.strptime(my_str,'%d/%m/%Y %H:%M')
from  datetime import *
import time
now = datetime.now()
print('today():', datetime.today())
print('now():', datetime.now())
print('fromtimestamp(tmstmp):', datetime.fromtimestamp(time.time()))   
print('datetime.strptime(date_string, format):',datetime.strptime('2022-03-21', "%Y-%m-%d"))

2.3 timedelta

使用timedelta可以很方便的在日期上做天days,小时hour,分钟,秒,毫秒,微妙的时间计算,如果要计算月份则需要另外的办法
from  datetime import datetime
from  datetime import timedelta
dt = datetime.now()
#日期减一天
dt_1 = dt + timedelta(days=-1)#昨天
dt_11 = dt - timedelta(days=1)#昨天
dt3 = dt + timedelta(days=1)#明天
print("dt3:",dt_1)
print("dt_11:",dt_11)
print("dt3:",dt3)
# 明天的datetime  - 昨天的datetime
s= dt3 - dt_1
print(s.days)
print(s.total_seconds())
delta_obj = dt3-dt
print(type(delta_obj),delta_obj)
#<type 'datetime.timedelta'> 1 day, 0:00:00
# total_seconds():返回在该时间实例的给定持续时间内覆盖的总秒数
print(delta_obj.days ,delta_obj.total_seconds())#1 86400.0

六、jieba

代码对 Python 2/3 均兼容
•	全自动安装:easy_install jieba 或者 pip install jieba / pip3 install jieba
•	半自动安装:先下载 http://pypi.python.org/pypi/jieba/ ,解压后运行 python setup.py install
•	手动安装:将 jieba 目录放置于当前目录或者 site-packages 目录
•	通过 import jieba 来引用
In [ ]:
 
pip install jieba
•	jieba.cut 方法接受三个输入参数: 需要分词的字符串;cut_all 参数用来控制是否采用全模式;HMM 参数用来控制是否使用 HMM 模型
•	jieba.cut_for_search 方法接受两个参数:需要分词的字符串;是否使用 HMM 模型。该方法适合用于搜索引擎构建倒排索引的分词,粒度比较细 待分词的字符串可以是 unicode 或 UTF-8 字符串、GBK 字符串。注意:不建议直接输入 GBK 字符串,可能无法预料地错误解码成 UTF-8
•	jieba.cut 以及 jieba.cut_for_search 返回的结构都是一个可迭代的 generator,可以使用 for 循环来获得分词后得到的每一个词语(unicode),或者用 =jieba.lcut 以及 jieba.lcut_for_search 直接返回 list
jieba.analyse的使用:提取关键字
•	第一个参数:待提取关键词的文本
•	第二个参数 topK:返回关键词的数量,重要性从高到低排序
•	第三个参数 withWeight:是否同时返回每个关键词的权重
•	第四个参数allowPOS=():词性过滤,为空表示不过滤,若提供则仅返回符合词性要求的关键词 ,查看:jieba词性表.txt
# 必须引入的使用就引入jieba.analyse,才能使用.  不能导入jieba ,然后使用jieba.analyse
text = " 因此电影开头谜语人从用地毯铲杀市长开始就在为验证蝙蝠侠的身份布局了"
seg_list = jieba.cut(text, cut_all=True)
print("Full Mode: " + " ".join(seg_list))  # 全模式,Full Mode:因此 电影 开头 谜语 人 从 用地 地毯 铲 杀 市长 开始 就 在 为 验证 蝙蝠 蝙蝠侠 的 身份 布局 了
seg_list = jieba.cut(text, cut_all=False)
print("Default Mode: " + " ".join(seg_list))  # 精确模式,Default Mode:因此 电影 开头 谜语 人 从 用 地毯 铲 杀 市长 开始 就 在 为 验证 蝙蝠侠 的 身份 布局 了
# 提取关键字
seg_list = jieba.analyse.extract_tags(text)
print("analysea extract: " + " ".join(seg_list))  # 分析提取,analysea extract: 蝙蝠侠 谜语 地毯 开头 验证 电影 身份 布局 市长 因此 开始
# 提取5个
seg_list = jieba.analyse.extract_tags(text, topK=5)
print("analysea extract topK: " + "  ".join(seg_list))  # 分析提取,analysea extract topK: 蝙蝠侠  谜语  地毯  开头  验证
# 返回权重
seg_list = jieba.analyse.extract_tags(text, topK=5, withWeight=True)
print("analysea extract withWeight: " + str((seg_list)))  # 分析提取,analysea extract withWeight: [('蝙蝠侠', 1.2636979683636365), ('谜语', 0.9156396595909091), ('地毯', 0.73958968629), ('开头', 0.7244029513209091), ('验证', 0.7130812398863636)]
# 词性过滤 返回 n名词
seg_list = jieba.analyse.extract_tags(text, allowPOS=("n"))
print("analysea extract allowPOS: " + str((seg_list)))  # 分析提取,analysea extract allowPOS: ['蝙蝠侠', '谜语', '地毯', '电影', '身份', '布局', '市长']

七、理解Groupby并使用agg、transform、apply函数

import pandas as pd
import numpy as np
company=['A','B','C']
data=pd.DataFrame({'company':[company[x] for x in np.random.randint(0,len(company),10)],
                   'salary':np.random.randint(5,50,10),
                   "age":np.random.randint(15,20,10)})
print(data)
group=data.groupby("company")
print('--------------------------------')
print(group)
print(list(group))
print('=============================')
print(data.groupby("company").agg('mean'))
print(data.groupby("company").agg({'salary': 'median', 'age': 'mean'}))
print('-------------------------------')
# 添加列 拆分成字典
avg_salary_dict=data.groupby("company")['salary'].mean().to_dict()
print(avg_salary_dict)
# 键值对,以map映射
data['avg_salary']=data['company'].map(avg_salary_dict)
print(data)
# 事务 映射
data['avg_salary1']=data.groupby('company')['salary'].transform('sum')
print(data)
print("=====================-")
def get_old_staff(x):
    # 输入数据按照age字段进行排序
    df=x.sort_values(by='age',ascending=True)
    # 返回最后一行数据
    return df.iloc[-1,:]
oldest_staff=data.groupby('company',as_index=False).apply(get_old_staff)
print(oldest_staff)
  company  salary  age
0       A      35   18
1       B       8   16
2       B      49   16
3       C      36   16
4       C      22   15
5       B      13   16
6       C      44   18
7       B      21   15
8       A       5   15
9       C       5   15
--------------------------------
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001AE9B4CAF08>
[('A',   company  salary  age
0       A      35   18
8       A       5   15), ('B',   company  salary  age
1       B       8   16
2       B      49   16
5       B      13   16
7       B      21   15), ('C',   company  salary  age
3       C      36   16
4       C      22   15
6       C      44   18
9       C       5   15)]
=============================
         salary    age
company               
A         20.00  16.50
B         22.75  15.75
C         26.75  16.00
         salary    age
company               
A          20.0  16.50
B          17.0  15.75
C          29.0  16.00
-------------------------------
{'A': 20.0, 'B': 22.75, 'C': 26.75}
  company  salary  age  avg_salary
0       A      35   18       20.00
1       B       8   16       22.75
2       B      49   16       22.75
3       C      36   16       26.75
4       C      22   15       26.75
5       B      13   16       22.75
6       C      44   18       26.75
7       B      21   15       22.75
8       A       5   15       20.00
9       C       5   15       26.75
  company  salary  age  avg_salary  avg_salary1
0       A      35   18       20.00           40
1       B       8   16       22.75           91
2       B      49   16       22.75           91
3       C      36   16       26.75          107
4       C      22   15       26.75          107
5       B      13   16       22.75           91
6       C      44   18       26.75          107
7       B      21   15       22.75           91
8       A       5   15       20.00           40
9       C       5   15       26.75          107
=====================-
  company  salary  age  avg_salary  avg_salary1
0       A      35   18       20.00           40
1       B      13   16       22.75           91
2       C      44   18       26.75          107

Process finished with exit code 0

八、连接 merge()函数inner与right、left、outer

pd.merge( left, right, how: str = 'inner', on=None, left_on=None, right_on=None, left_index: bool = False, right_index: bool = False, sort: bool = False, suffixes=('_x', '_y'), copy: bool = True, indicator: bool = False, validate=None, )
•   left/right 两个不同的 DataFrame 对象。
•   how 要执行的合并类型,从 {'left', 'right', 'outer', 'inner'} 中取值,默认为“inner”内连接。
•   on 指定用于连接的键(即列标签的名字),该键必须同时存在于左右两个 DataFrame 中,如果没有指定,并且其他参数也未指定, 那么将会以两个 DataFrame 的列名交集做为连接键。
•   left_on 指定左侧 DataFrame 中作连接键的列名。该参数在左、右列标签名不相同,但表达的含义相同时非常有用。
•   right_on 指定左侧 DataFrame 中作连接键的列名。
•   left_index 布尔参数,默认为 False。如果为 True 则使用左侧 DataFrame 的行索引作为连接键
•   right_index 布尔参数,默认为 False。如果为 True 则使用左侧 DataFrame 的行索引作为连接键
•   sort 布尔值参数, False,则按照 how 给定的参数值进行排序。设置为True,它会将合并后的数据进行排序;
•   suffixes 字符串组成的元组。当左右 DataFrame 存在相同列名时,通过该参数可以在相同的列名后附加后缀名,默认为('_x','_y')。
•   copy 默认为 True,表示对数据进行复制。
注意:Pandas 库的 merge() 支持各种内外连接,与其相似的还有 join() 函数(默认为左连接)。
一、inner
merge的inner的类型称为内连接,它在拼接的过程中会取两张表的键(key)的交集进行拼接。什么意思呢?
下面以图解的方式来一步一步拆解。
首先我们有以下的数据,左侧和右侧的数据分别代表了用户的基础信息和消费信息,连接两张表的键是userid。 
df_1 = pd.DataFrame({
                     "userid":['a', 'b', 'c', 'd'], 
                     "age":[23, 46, 32, 19]
                    })
print(df_1) 
    userid  age
0   a   23
1   b   46
2   c   32
3   d   19
df_2 = pd.DataFrame({
        "userid":['a', 'c'],
        "payment":[2000, 3500]
    })
print(df_2)
    userid  payment
0   a   2000
1   c   3500
print(df_1.merge(df_2,on='userid'))
    userid  age payment
0   a   23  2000
1   c   32  3500
pd.merge(df_1, df_2, on='userid')
    userid  age payment
0   a   23  2000
1   c   32  3500
​
相信整个过程并不难理解,上面演示的是同一个键下,两个表对应只有一条数据的情况(一个用户对应一条消费记录),那么,如果一个用户对应了多条消费记录的话,那又是怎么拼接的呢?
假设现在的数据变成了下面这个样子,在df_2中,有两条和a对应的数据:
# 同样用inner的方式进行merge:
df_1 = pd.DataFrame({
                     "userid":['a', 'b', 'c', 'd'], 
                     "age":[23, 46, 32, 19]
                    })
​
df_2 = pd.DataFrame({
        "userid":['a', 'c','a', 'd'],
        "payment":[2000, 3500, 500, 1000]
    })
print(pd.merge(df_1, df_2, on="userid"))
    userid  age payment
0   a   23  2000
1   a   23  500
2   c   32  3500
3   d   19  1000
整个过程除了对应匹配阶段,其他和上面基本都是一致的。
二、left 和right
'left'和'right'的merge方式其实是类似的,分别被称为左连接和右连接。这两种方法是可以互相转换的,所以在这里放在一起介绍。
'left'
merge时,以左边表格的键为基准进行配对,如果左边表格中的键在右边不存在,则用缺失值NaN填充。
'right'
merge时,以右边表格的键为基准进行配对,如果右边表格中的键在左边不存在,则用缺失值NaN填充。
现在用'left'的方式进行merge
df_1 = pd.DataFrame({
                     "userid":['a', 'b', 'c', 'd'], 
                     "age":[23, 46, 32, 19]
                    })
​
df_2 = pd.DataFrame({
        "userid":['a', 'c','e'],
        "payment":[2000, 3500, 600]
    })
pd.merge(df_1, df_2,how='left', on="userid")
    userid  age payment
0   a   23  2000.0
1   b   46  NaN
2   c   32  3500.0
3   d   19  NaN
对于'right'类型的merge和'left'其实是差不多的,只要把两个表格的位置调换一下,两种方式返回的结果就是一样的(),如下:
pd.merge(df_1, df_2,how='right', on="userid")
    userid  age payment
0   a   23.0    2000
1   c   32.0    3500
2   e   NaN 600
三、outer
'outer'是外连接,在拼接的过程中它会取两张表的键(key)的并集进行拼接。看文字不够直观,还是上例子吧!
还是使用上方用过的演示数据 
pd.merge(df_1, df_2,how='outer',on='userid')
    userid  age payment
0   a   23.0    2000.0
1   b   46.0    NaN
2   c   32.0    3500.0
3   d   19.0    NaN
4   e   NaN 600.0
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值