跳转至

Pandas

Pandas 是一个 Python 库,提供了高效的数据操作和分析功能。它主要用于数据处理和分析,包括数据读取、数据清洗、数据转换、数据聚合和可视化等功能。Pandas 基于 NumPy 库,并提供了类似 MATLAB 的接口,使得数据处理和分析变得更加方便。

Pandas 的核心是 Series 和 DataFrame 两种数据结构。Series 是一种一维数组,可以包含各种类型的数据(如整数、浮点数、字符串等),并具有标签(index)用于标记数据。DataFrame 是一个二维表格,可以看作是由多个 Series 组成的表格,其中每一列都可以看作是一个 Series。

Pandas 提供了一系列用于数据处理和分析的函数和方法,如:

数据读取和写入:read_csv、read_excel、read_json、to_csv、to_excel、to_json 等。
数据清洗:dropna、fillna、drop_duplicates 等。
数据转换:map、replace、applymap、apply 等。
数据聚合:groupby、agg、pivot_table 等。
数据可视化:plot、hist、bar、箱形图等。

1.Pandas 的数据结构

Pandas 的核心数据结构是 Series 和 DataFrame。

Series:是一种一维数组,包含一组数据(values,ndarray类型)以及一个标签(index)。它可以看作是 Python 中的一维 NumPy 数组的扩展,增加了标签和数据类型等额外信息。Series 可以包含各种类型的数据,如整数、浮点数、字符串等。Series: 可以看做是一个有序的字典结构。

DataFrame:是一个二维表格,包含多个 Series,每个 Series 可以看作是表格中的一列。DataFrame 提供了类似于表格的数据结构,可以方便地访问、处理和分析数据。

除了 Series 和 DataFrame,Pandas 还提供了其他数据结构,如 Index、MultiIndex、Panel、Panel4D、SparseSeries 和 SparseDataFrame 等。这些数据结构可以满足不同类型的数据分析和操作需求。

1.1 Series的创建

(1) 由列表或NumPy数组创建

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
s = pd.Series([11, 22, 33], index=list('ABC'))
s
A    11
B    22
C    33
dtype: int64
# index和values
s.index, s.values
(Index(['A', 'B', 'C'], dtype='object'), array([11, 22, 33], dtype=int64))

(2) 由字典创建

s = pd.Series({'name': "肖战","age": 27,'tel':"18012541968"})
s
name             肖战
age              27
tel     18012541968
dtype: object

1.2 Series的索引和切片

1.2.1 Series的索引

可以使用中括号取单个索引(此时返回的是元素类型),或者中括号里一个列表取多个索引(此时返回的仍然是一个Series类型)。分为显示索引和隐式索引:

(1) 显式索引:

使用index中的元素作为索引值

s = pd.Series({'name': "肖战","age": 27,'tel':"18012541968"})
s['name']
'肖战'

(2) 隐式索引:

使用整数作为索引值

s = pd.Series({'name': "肖战","age": 27,'tel':"18012541968"})
s[0]
'肖战'

1.2.2 Series的切片

s = pd.Series([11, 22, 33, 44, 55, 66, 77, 88, 99], index=list('ABCDEFGHI'), name='hello')
s
A    11
B    22
C    33
D    44
E    55
F    66
G    77
H    88
I    99
Name: hello, dtype: int64
s[1 : 4]  # 前闭后开
B    22
C    33
D    44
Name: hello, dtype: int64
s['B': 'D']  # 2边都包含
B    22
C    33
D    44
Name: hello, dtype: int64

1.2.3 Series的基本属性和方法¶

shape 形状

size 长度

index 索引

values 值

name 名字
s = pd.Series([11, 22, 33, 44, 55, 66, 77, 88, 99], index=list('ABCDEFGHI'), name='hello')
print(s.shape)
print(s.size)
print(s.index)
print(s.values)
print(s.name)
(9,)
9
Index(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'], dtype='object')
[11 22 33 44 55 66 77 88 99]
hello

1.3 DataFrame

DataFrame是一个【表格型】的数据结构,可以看做是【由Series组成的字典】(共用同一个索引)。DataFrame由按一定顺序排列的多列数据组成。设计初衷是将Series的使用场景从一维拓展到多维。DataFrame既有行索引,也有列索引。

行索引:index
列索引:columns
值:values(NumPy的二维数组)

1.3.1 DataFrame的创建

最常用的方法是传递一个字典来创建。DataFrame以字典的键作为每一【列】的名称,以字典的值(一个数组)作为每一列。

此外,DataFrame会自动加上每一行的索引(和Series一样)。

同Series一样,若传入的列与字典的键不匹配,则相应的值为NaN。

df = pd.DataFrame({'name': ['刘亦菲', '李冰冰', '林心如'], 'age': [33, 44, 55]})
df
name age
0 刘亦菲 33
1 李冰冰 44
2 林心如 55
df = pd.DataFrame({'name': ['刘亦菲', '李冰冰', '林心如'], 'age': [33, 44, 55]},index=list('ABC'))
df
name age
A 刘亦菲 33
B 李冰冰 44
C 林心如 55
data = {'Name': ['Alice', 'Bob', 'Charlie'], 'Age': [25, 30, 35]}  
index = pd.Index(['row0', 'row1', 'row2'], name='row')  
df = pd.DataFrame(data, index=index)
df
Name Age
row
row0 Alice 25
row1 Bob 30
row2 Charlie 35
print(df.values)
print(df.index)
print(df.columns)
print(df.shape)
[['Alice' 25]
 ['Bob' 30]
 ['Charlie' 35]]
Index(['row0', 'row1', 'row2'], dtype='object', name='row')
Index(['Name', 'Age'], dtype='object')
(3, 2)
df.head(2)  # 默认前5行
Name Age
row
row0 Alice 25
row1 Bob 30
df.tail(2)  # 默认后5行
Name Age
row
row1 Bob 30
row2 Charlie 35
df2 = pd.DataFrame(np.random.randint(60,100,size=(4, 5)), 
                  index=['李白', '杜甫', '白居易', '秦始皇'], 
                  columns=['Python', 'Java', 'C', 'R', 'JS'])
df2
Python Java C R JS
李白 66 67 75 66 95
杜甫 63 85 74 65 88
白居易 95 69 70 64 72
秦始皇 67 62 96 74 60
# 默认是对列取索引
df2['Python']
# df2['李白']  # 不可以直接取行索引
李白     66
杜甫     63
白居易    95
秦始皇    67
Name: Python, dtype: int32
df2.Python  #  Series
李白     66
杜甫     63
白居易    95
秦始皇    67
Name: Python, dtype: int32
df2[['Python']]  # DataFrame
Python
李白 66
杜甫 63
白居易 95
秦始皇 67
df2[['Python', 'Python', 'Java']]
Python Python Java
李白 66 66 67
杜甫 63 63 85
白居易 95 95 69
秦始皇 67 67 62

1.3.2 对行进行索引

使用.loc[]加index来进行行索引

使用.iloc[]加整数来进行行索引

同样返回一个Series,index为原来的columns。

df2
Python Java C R JS
李白 66 67 75 66 95
杜甫 63 85 74 65 88
白居易 95 69 70 64 72
秦始皇 67 62 96 74 60
df2.loc['李白']
Python    66
Java      67
C         75
R         66
JS        95
Name: 李白, dtype: int32
df2.iloc[0]
Python    66
Java      67
C         75
R         66
JS        95
Name: 李白, dtype: int32
df2.loc[['李白', '杜甫']]
Python Java C R JS
李白 66 67 75 66 95
杜甫 63 85 74 65 88
df2.iloc[[2, 1, 2, 2, 2, 2, 2]]
Python Java C R JS
白居易 95 69 70 64 72
杜甫 63 85 74 65 88
白居易 95 69 70 64 72
白居易 95 69 70 64 72
白居易 95 69 70 64 72
白居易 95 69 70 64 72
白居易 95 69 70 64 72

1.3.3 DataFrame的切片

【注意】 直接用中括号时:

索引优先对列进行操作
切片优先对行进行操作
# NumPy 索引和切片都是优先对行
df2 = pd.DataFrame(np.random.randint(60,100,size=(4, 5)), 
                  index=['李白', '杜甫', '白居易', '秦始皇'], 
                  columns=['Python', 'Java', 'C', 'R', 'JS'])
df2
Python Java C R JS
李白 89 86 98 93 60
杜甫 85 62 91 62 83
白居易 64 62 69 95 90
秦始皇 84 76 89 87 94
df2.values[:2]
array([[89, 86, 98, 93, 60],
       [85, 62, 91, 62, 83]])
# DataFrame: 
#   索引优先对列进行操作
#   切片优先对行进行操作

# 行切片
df2[1 : 3]
Python Java C R JS
杜甫 99 90 87 73 60
白居易 94 61 95 87 95
df2['杜甫' : '白居易']
Python Java C R JS
杜甫 99 90 87 73 60
白居易 94 61 95 87 95
# 列切片
df2.iloc[:, 1:3]
Java C
李白 78 79
杜甫 90 87
白居易 61 95
秦始皇 79 94
df2.loc[:, "Java": "R"]
Java C R
李白 78 79 96
杜甫 90 87 73
白居易 61 95 87
秦始皇 79 94 89

2. Pandas数据合并

Pandas 中的数据合并主要包括以下几种方式:

pd.concat() 函数实现。
pd.merge() 函数实现。
import numpy as np
import pandas as pd
## 定义一个生成DataFrame的函数
def make_df(indexs, columns):    
    data = [[str(j)+str(i) for j in columns] for i in indexs]
    df = pd.DataFrame(data=data, index=indexs, columns=columns)
    return df
make_df([1, 2, 3, 4], ['A','B','C'])
A B C
1 A1 B1 C1
2 A2 B2 C2
3 A3 B3 C3
4 A4 B4 C4

2.1 使用pd.concat()级联

pandas使用pd.concat函数,与np.concatenate函数类似。

pd.concat(objs, axis=0, join='inner', join_axes=None, ignore_index=False, copy=True, names=None)

参数说明:

objs:要合并的 Pandas 对象列表。可以是 DataFrame、Series 或其他 Pandas 对象。
axis:要合并的轴。0 表示按行合并(默认值),1 表示按列合并。
join:指定合并方式。可以是 'inner'(默认值,只保留重叠的元素)、'outer'(保留所有元素)或 'left'、'right'(分别保留左边界和右边界的元素)。
join_axes:指定合并时使用的轴。如果指定了该参数,则只合并指定的轴,而不是所有轴。
ignore_index:如果为 True,则不保留原始索引,重新创建一个新的索引。
copy:如果为 True,则将合并后的对象复制一份,否则直接在原地进行修改。
names:如果指定了该参数,则在合并后的对象中创建两个附加的列,分别包含左侧和右侧对象的名称。

简单级联

df1 = make_df([1, 2], ['A', 'B'])
df2 = make_df([3, 4], ['A', 'B'])
display(df1, df2)
df1 = make_df([1, 2], ['geneA', 'geneB', 'geneC'])
df2 = make_df([2, 3], ['geneA', 'geneB', 'geneD'])
display(df1, df2)
geneA geneB geneC
1 geneA1 geneB1 geneC1
2 geneA2 geneB2 geneC2
geneA geneB geneD
2 geneA2 geneB2 geneD2
3 geneA3 geneB3 geneD3
pd.concat( (df1, df2) )  # 上下合并,默认
geneA geneB geneC geneD
1 geneA1 geneB1 geneC1 NaN
2 geneA2 geneB2 geneC2 NaN
2 geneA2 geneB2 NaN geneD2
3 geneA3 geneB3 NaN geneD3
pd.concat((df1, df2), axis=1)  # 左右合并
geneA geneB geneC geneA geneB geneD
1 geneA1 geneB1 geneC1 NaN NaN NaN
2 geneA2 geneB2 geneC2 geneA2 geneB2 geneD2
3 NaN NaN NaN geneA3 geneB3 geneD3
import pandas as pd  

# 创建两个 DataFrame  
df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})  
df2 = pd.DataFrame({'A': [5, 6], 'B': [7, 8]})  

# 沿着行方向合并  
result = pd.concat([df1, df2])  
display(result)
# 沿着列方向合并  
result = pd.concat([df1, df2], axis=1)  
display(result)

# 沿着行方向合并,忽略索引  
result = pd.concat([df1, df2], ignore_index=True)  
display(result)
A B
0 1 3
1 2 4
0 5 7
1 6 8
A B A B
0 1 3 5 7
1 2 4 6 8
A B
0 1 3
1 2 4
2 5 7
3 6 8

2.2 使用pd.merge()合并

类似MySQL中表和表的合并

pd.merge()是pandas库中用于合并两个或更多数据框(DataFrame)的函数。它通过共享一个或多个键将数据框的行连接在一起。

merge与concat的区别在于,merge需要依据某一共同的行或列来进行合并。

使用pd.merge()合并时,会自动根据两者相同column名称的那一列,作为key来进行合并。

每一列元素的顺序不要求一致

pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=True, suffixes=('_x', '_y'), copy=True, indicator=False, validate=None)

参数说明:

left: 左侧的数据框。
right: 右侧的数据框。
how: 连接类型,可以是'inner'(内连接,默认),'left'(左连接),'right'(右连接),'outer'(外连接)。
on: 用于连接的键,可以是列名或索引名。如果how='inner',则此参数必须提供。
left_on: 左侧数据框中的键。
right_on: 右侧数据框中的键。
left_index: 是否使用左侧数据框的索引作为连接键(如果为True,则忽略left_on)。
right_index: 是否使用右侧数据框的索引作为连接键(如果为True,则忽略right_on)。
sort: 是否对合并后的结果进行排序(如果为True,则按照连接键进行排序)。
suffixes: 当有重复键时,用于区分列名的后缀。
copy: 是否创建新的数据框(如果为True,则创建新的数据框)。
indicator: 是否创建一个指示列,指示合并的类型(如果为True,则创建一个指示列)。
validate: 用于验证连接键的函数。

2.2.1 一对一合并

import pandas as pd  

# 创建左侧数据框  
df1 = pd.DataFrame({'key': ['A', 'B', 'C'], 'value': [1, 2, 3]})  
display(df1)  
# 创建右侧数据框  
df2 = pd.DataFrame({'key': ['B', 'C', 'D'], 'value2': ['x', 'y', 'z']})  
display(df2)  
# 使用pd.merge()合并两个数据框  
merged_df = pd.merge(df1, df2, on='key')  

# 输出合并后的数据框  
merged_df
key value
0 A 1
1 B 2
2 C 3
key value2
0 B x
1 C y
2 D z
key value value2
0 B 2 x
1 C 3 y
df1.merge(df2) # 默认 内连接
key value value2
0 B 2 x
1 C 3 y

2.2.2 多对一合并

df3 = pd.DataFrame({
    'id': [1, 2, 2],
    'name': ['李明', '王明', '陈明'],
    'age': [22, 33, 44]
})
df4 = pd.DataFrame({
    'id': [2, 3, 4],
    'sex': ['男', '女', '男'],
    'job': ['Saler', 'CEO', 'Programer']
})
display(df3, df4)
id name age
0 1 李明 22
1 2 王明 33
2 2 陈明 44
id sex job
0 2 Saler
1 3 CEO
2 4 Programer
pd.merge(df3, df4)
id name age sex job
0 2 王明 33 Saler
1 2 陈明 44 Saler

2.2.3 多对多的合并

df5 = pd.DataFrame({
    'id': [1, 2, 2],
    'name': ['李明', '王明', '陈明'],
    'age': [22, 33, 44]
})
df6 = pd.DataFrame({
    'id': [2, 2, 4],
    'sex': ['男', '女', '男'],
    'job': ['Saler', 'CEO', 'Programer']
})
display(df5, df6)
id name age
0 1 李明 22
1 2 王明 33
2 2 陈明 44
id sex job
0 2 Saler
1 2 CEO
2 4 Programer
pd.merge(df5, df6)
id name age sex job
0 2 王明 33 Saler
1 2 王明 33 CEO
2 2 陈明 44 Saler
3 2 陈明 44 CEO

2.2.4 key的规范化

使用on=显式指定哪一列为key,当2个DataFrame有多列相同时使用。

df1 = pd.DataFrame({
    'id': [1, 2, 3],
    'name': ['李明', '王明', '陈明'],
    'age': [22, 33, 44]
})
df2 = pd.DataFrame({
    'id': [2, 3, 4],
    'name': ['王明', '赵明', '江明'],
    'job': ['Saler', 'CEO', 'Programer']
})
display(df1, df2)
id name age
0 1 李明 22
1 2 王明 33
2 3 陈明 44
id name job
0 2 王明 Saler
1 3 赵明 CEO
2 4 江明 Programer
pd.merge(df1, df2, on='id')
id name_x age name_y job
0 2 王明 33 王明 Saler
1 3 陈明 44 赵明 CEO
pd.merge(df1, df2)
id name age job
0 2 李四 33 Saler

使用left_on和right_on指定左右两边的列作为key,当左右两边的key都不想等时使用

df1 = pd.DataFrame({
    'id': [1, 2, 3],
    'name': ['李明', '王明', '陈明'],
    'age': [22, 33, 44]
})
df2 = pd.DataFrame({
    'id2': [2, 3, 4],
    'sex': ['男', '女', '男'],
    'job': ['Saler', 'CEO', 'Programer']
})
display(df1, df2)
id name age
0 1 李明 22
1 2 王明 33
2 3 陈明 44
id2 sex job
0 2 Saler
1 3 CEO
2 4 Programer
pd.merge(df1, df2, left_on='id', right_on='id2')
id name age id2 sex job
0 2 王明 33 2 Saler
1 3 陈明 44 3 CEO

当左边的列和右边的index相同的时候,使用right_index=True

df1 = pd.DataFrame({
    'id': [1, 2, 3],
    'name': ['李明', '王明', '陈明'],
    'age': [22, 33, 44]
})
df2 = pd.DataFrame({
    'id2': [2, 3, 4],
    'sex': ['男', '女', '男'],
    'job': ['Saler', 'CEO', 'Programer']
})
display(df1, df2)
id name age
0 1 李明 22
1 2 王明 33
2 3 陈明 44
id2 sex job
0 2 Saler
1 3 CEO
2 4 Programer
pd.merge(df1, df2, left_index=True, right_on='id2')
id name age id2 sex job
0 3 陈明 44 2 Saler

2.2.5 内合并与外合并

# 内合并:只保留两者都有的key(默认模式)
df1 = pd.DataFrame({
    'id': [1, 2, 3],
    'name': ['李明', '王明', '陈明'],
    'age': [22, 33, 44]
})
df2 = pd.DataFrame({
    'id': [2, 3, 4],
    'sex': ['男', '女', '男'],
    'job': ['Saler', 'CEO', 'Programer']
})
display(df1, df2)
id name age
0 1 李明 22
1 2 王明 33
2 3 陈明 44
id sex job
0 2 Saler
1 3 CEO
2 4 Programer
# how : {'left', 'right', 'outer', 'inner', 'cross'}, default 'inner'
pd.merge(df1, df2)  # 默认是内连接
id name age sex job
0 2 王明 33 Saler
1 3 陈明 44 CEO
pd.merge(df1, df2, how='inner')  # 默认是内连接
id name age sex job
0 2 王明 33 Saler
1 3 陈明 44 CEO
pd.merge(df1, df2, how='left') 
id name age sex job
0 1 李明 22 NaN NaN
1 2 王明 33 Saler
2 3 陈明 44 CEO

外合并 how='outer':补NaN

pd.merge(df1, df2, how='outer')
id name age sex job
0 1 李明 22.0 NaN NaN
1 2 王明 33.0 Saler
2 3 陈明 44.0 CEO
3 4 NaN NaN Programer

当列冲突时,即有多个列名称相同时,需要使用on=来指定哪一个列作为key,配合sufixes指定冲突列名。

可以使用suffixes=自己指定后缀

import pandas as pd  

# 创建数据框 df1  
df1 = pd.DataFrame({'id':[1,2,3],
                    'name': ['Alice', 'Bob', 'Charlie'],  
                    'age': [25, 30, 35]})  

# 创建数据框 df2  
df2 = pd.DataFrame({'id':[2,3,4],
                    'name': ['David', 'Bob', 'Charlie'],  
                    'salary': [50000, 60000, 70000]})  

print("df1:")  
display(df1)
print("df2:")  
display(df2)

merged_df = pd.merge(df1, df2, on='id', suffixes=('_df1', '_df2') )  
merged_df
df1:
id name age
0 1 Alice 25
1 2 Bob 30
2 3 Charlie 35
df2:
id name salary
0 2 David 50000
1 3 Bob 60000
2 4 Charlie 70000
id name_df1 age name_df2 salary
0 2 Bob 30 David 50000
1 3 Charlie 35 Bob 60000
df1 = pd.DataFrame({'name':['陈明','王明','李明'],'id' :[1,2,3],'age': [22,33,44]})
df2 = pd.DataFrame({'id':[2,3,4],'name': ['王明', '李明','赵明'] ,'job': ['saler','CTO',' Programer']})
display(df1,df2)
df1. merge(df2,on='id',suffixes=['_表1','表2'] )
name id age
0 陈明 1 22
1 王明 2 33
2 李明 3 44
id name job
0 2 王明 saler
1 3 李明 CTO
2 4 赵明 Programer
name_表1 id age name表2 job
0 王明 2 33 王明 saler
1 李明 3 44 李明 CTO

总结:

合并有三种现象:一对一,多对一,多对多.
合并默认会找相同的列名进行合并,如果有多个列名相同,用on来指定.
如果没有列名相同,但是数据又相同,可以通过left _on, right_ _on来分别指定要合并的列.
如果想和index合并,使用left. index, right _index来指定.
如果多个列相同,合并之后可以通过suffixes来区分.
还可以通过how来控制合并的结果,默认是内合并,还有外合并outer,左合并Ieft,右合并right.

2.3 join()函数

使用join()函数将DataFrame与另一个DataFrame进行连接。

import pandas as pd  

# 创建两个DataFrame  
df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})  
df2 = pd.DataFrame({'C': [5, 6], 'D': [7, 8]})  
display(df1,df2)
# 
result = df1.join(df2)
result
A B
0 1 3
1 2 4
C D
0 5 7
1 6 8
A B C D
0 1 3 5 7
1 2 4 6 8

3. Pandas缺失值处理

3.1 None与np.nan

print(None == None)  # 输出:True  
print(np.nan == np.nan)  # 输出:False  
print(None == np.nan)  # 输出:False
True
False
False

在NumPy中,np.nan 代表 "Not a Number",它是一种特殊的浮点数值,用于表示无法表示的或者未定义的数值。由于其特殊性质,np.nan 与其他任何值(包括它自己)进行比较都会返回 False,包括与自身的比较。

这是因为在数学和计算的上下文中,"不是一个数字" 不能被看作与任何其他值相等,即使是它自己。因此,np.nan 与任何值进行比较都会返回 False,即使两个 np.nan 也不例外。这是一种在处理缺失数据和非数值时保持一致性的方式。

如果你想检查一个值是否为 np.nan,应该使用 np.isnan() 函数而不是直接使用等号。

import numpy as np    
print(np.isnan(np.nan))  # 输出:True
True

在 Pandas 中,None 和 np.nan(NumPy 中的 "Not a Number")在大多数情况下都被视为缺失值,即都被当作 NaN(Not a Number)来处理。这种处理是为了在处理数据时保持一致性和方便性。

在 Pandas 中,None 和 np.nan 都被视为缺失值的情况包括:

在 Series 或 DataFrame 中,它们都被当作缺失值处理,并且可以通过一些方法(如 isnull() 和 fillna())来处理这些缺失值。

在数值计算中,它们都会被当作特殊的缺失值处理,比如在进行算术运算时,它们与其他值相加、相乘等都会得到 NaN。

在逻辑运算中,它们都会被当作缺失的逻辑值处理,即与逻辑操作相关的运算会产生 NaN 结果。

需要注意的是,虽然在大多数情况下 None 和 np.nan 都被当作缺失值处理,但它们之间并不等价。None 是 Python 中的特殊对象,而 np.nan 是一个浮点数值。在某些特定情况下,它们可能会有不同的行为,尤其是在数据类型推断和某些操作中。

总之,Pandas 设计了这种处理方式,以便在数据处理中能够更方便地处理缺失值,而不必关心是使用 None 还是 np.nan。

3.2 检查缺失值:

使用 isnull() 或 isna() 方法可以检查一个 Series 或 DataFrame 中的缺失值,返回一个布尔类型的结果。

import pandas as pd
import numpy as np

data = pd.Series([1, 2, None, 4, np.nan, 6])
missing_values = data.isnull()
print(missing_values)
print("----------")
print(data.isna())
0    False
1    False
2     True
3    False
4     True
5    False
dtype: bool
----------
0    False
1    False
2     True
3    False
4     True
5    False
dtype: bool
data = np.random.randint(0, 100, size=(5, 5))
df = pd.DataFrame(data=data, columns=list('ABCDE'))
df['B'][1] = np.nan
df['C'][2] = np.nan
df
C:\Users\chens\AppData\Local\Temp\ipykernel_21680\690573573.py:4: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  df['C'][2] = np.nan
A B C D E
0 37 17.0 51.0 72 35
1 40 NaN 53.0 65 20
2 56 87.0 NaN 53 15
3 52 33.0 33.0 48 63
4 25 97.0 94.0 79 79
df.isnull()
A B C D E
0 False False False False False
1 False True False False False
2 False False True False False
3 False False False False False
4 False False False False False
df.isnull().all()  # 必须所有的全为空才能找到
A    False
B    False
C    False
D    False
E    False
dtype: bool
df.isnull().any()  # 只要有1个为空就会找到 (常用)  有空的列
A    False
B     True
C     True
D    False
E    False
dtype: bool
df.isnull().any(axis=1)  # 有空的行
0    False
1     True
2     True
3    False
4    False
dtype: bool
# 取出非空的行
cond1 = df.isnull().any(axis=1)
cond1
df[ ~cond1 ]
A B C D E
0 37 17.0 51.0 72 35
3 52 33.0 33.0 48 63
4 25 97.0 94.0 79 79
cond1 = df.notnull().all(axis=1)
cond1
df[ cond1 ]
A B C D E
0 37 17.0 51.0 72 35
3 52 33.0 33.0 48 63
4 25 97.0 94.0 79 79
df3 = pd.DataFrame(np.random.randint(40, 100, size=(4, 5)))
df3.index = list('ABCD')
df3.columns = ['C', 'R', 'Python', 'Java', 'C++']
df3
C R Python Java C++
A 86 71 72 50 77
B 62 51 58 40 91
C 72 96 80 82 97
D 66 50 92 91 83
# 找出Python成绩小于60的数,并删除

cond = df3.Python < 60
~cond

# bool值索引
df3[~cond]

# drop
# df3.drop(index='B')
C R Python Java C++
A 86 71 72 50 77
C 72 96 80 82 97
D 66 50 92 91 83

3.3 过滤函数

DataFrame.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)

参数说明:

 axis:指定要删除的轴,0表示删除行,1表示删除列。
how:指定删除的方式,'any'表示删除包含NaN值的行或列,'all'表示删除所有值都为NaN的行或列。
thresh:如果要删除的行或列的数量不是唯一的,可以指定要删除的行或列的数量。
subset:指定要删除NaN值的子集。
inplace:如果为True,则直接在原始DataFrame上修改,否则返回一个新的DataFrame。

用于从DataFrame中删除包含NaN值的行或列。可以选择过滤的是行还是列(默认为行)

import pandas as pd  

# 创建一个包含NaN值的DataFrame  
df = pd.DataFrame({'A': [1, 2, np.nan], 'B': [4, np.nan, np.nan], 'C': [7, 8, 9]})  
display(df)

# 删除包含NaN值的行  
df_dropna = df.dropna()  
display(df_dropna)  

# 删除包含NaN值的列  
df_dropna = df.dropna(axis=1)  
display(df_dropna)
A B C
0 1.0 4.0 7
1 2.0 NaN 8
2 NaN NaN 9
A B C
0 1.0 4.0 7
C
0 7
1 8
2 9

3.4 填充缺失值

使用 fillna() 方法可以将缺失值填充为指定的值。你可以传递一个特定的值、一个字典或者使用不同的填充方法。

DataFrame.fillna(value=None, method=None, axis=0, inplace=False, limit=None, downcast=None)

参数说明:

value:用于填充缺失值的值或一个字典,其中键是列名,值是要填充的值。
method:指定填充方法,例如'ffill'(向前填充)、'bfill'(向后填充)或'mean'(使用列的平均值填充)。
axis:指定要填充的轴,0表示行,1表示列。
inplace:如果为True,则直接在原始DataFrame上修改,否则返回一个新的DataFrame。
limit:向前或向后填充时,限制填充的次数。
downcast:可选参数,用于指定输出数据的精度。
import pandas as pd  
import numpy as np  

# 创建一个包含NaN值的DataFrame  
df = pd.DataFrame({'A': [1, 2, np.nan], 'B': [4, np.nan, np.nan], 'C': [7, 8, 9]})  
display(df)  

# 使用0填充NaN值  
df_filled = df.fillna(value=0)  
display(df_filled)  
A B C
0 1.0 4.0 7
1 2.0 NaN 8
2 NaN NaN 9
A B C
0 1.0 4.0 7
1 2.0 0.0 8
2 0.0 0.0 9
df = pd.DataFrame(data=data, columns=list(['age', 'salary', 'height', 'score', 'weight']))

df['age'][1] = np.nan
df['height'][2] = np.nan
df
C:\Users\chens\AppData\Local\Temp\ipykernel_21680\3502519571.py:4: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  df['height'][2] = np.nan
age salary height score weight
0 37.0 17 51.0 72 35
1 NaN 41 53.0 65 20
2 56.0 87 NaN 53 15
3 52.0 33 33.0 48 63
4 25.0 97 94.0 79 79
# 填充: 平均值,中位数,众数,0

# height: 身高
df['height'].fillna(value=df['height'].mean(), inplace=True)
df
age salary height score weight
0 37.0 17 51.00 72 35
1 NaN 41 53.00 65 20
2 56.0 87 57.75 53 15
3 52.0 33 33.00 48 63
4 25.0 97 94.00 79 79
df['age'].fillna(value=df['age'].median(),inplace=True)
df     
age salary height score weight
0 37.0 17 51.00 72 35
1 44.5 41 53.00 65 20
2 56.0 87 57.75 53 15
3 52.0 33 33.00 48 63
4 25.0 97 94.00 79 79

4. Pandas处理重复值和异常值

4.1 删除重复值

使用drop_duplicates()函数可以删除DataFrame中的重复行。默认情况下,该函数将删除所有重复行,但也可以指定要删除哪些列的重复行。

DataFrame.drop_duplicates(subset=None, keep='first', inplace=False)

参数说明:

subset:一个列的子集,用于确定哪些列应被视为唯一标识符。如果提供此参数,keep参数将无效。
keep:控制哪些行应被视为重复。可能的值是'first','last'或False。
inplace:如果为True,则直接在原始DataFrame上修改,否则返回一个新的DataFrame。
import pandas as pd  

df = pd.DataFrame({'A': [1, 2, 2, 3], 'B': [4, 5, 5, 6], 'C': [7, 8, 8, 9]})  
display(df)
df = df.drop_duplicates()  
df
A B C
0 1 4 7
1 2 5 8
2 2 5 8
3 3 6 9
A B C
0 1 4 7
1 2 5 8
3 3 6 9
df = pd.DataFrame({'A': [1, 1, 2, 3], 'B': [4, 4, 5, 6], 'C': [7, 7, 8, 9]})  
display(df)
A B C
0 1 4 7
1 1 4 7
2 2 5 8
3 3 6 9

使用duplicated()函数检测重复的行,返回元素为布尔类型的Series对象,每个元素对应一行,如果该行不是第一次出现,则元素为True

# 检测是否重复
df.duplicated(keep='first')
0    False
1     True
2    False
3    False
dtype: bool
df['C'][1] = 666
df
A B C
0 1 4 7
1 1 4 666
2 2 5 8
3 3 6 9
df.duplicated(subset=['A', 'B'])
0    False
1     True
2    False
3    False
dtype: bool

使用drop_duplicates()函数删除重复的行

df.drop_duplicates(subset=['A', 'B'],inplace=True)
df
A B C
0 1 4 7
2 2 5 8
3 3 6 9

4.2 映射

映射的含义:创建一个映射关系列表,把values元素和一个特定的标签或者字符串绑定。

map()函数:适合处理某一单独的列

map()函数中可以使用lambda函数

df = pd.DataFrame(data=np.random.randint(0, 100, size=(3, 4)), columns=list('ABCD'))
df
A B C D
0 40 6 76 24
1 23 18 10 14
2 0 86 9 38
df['B'] = df['B'].map(lambda x: x*10)
df
A B C D
0 40 60 76 24
1 23 180 10 14
2 0 860 9 38

4.3 异常值检测和过滤

4.3.1 有关异常值检测的相关函数和操作

describe()是pandas库中DataFrame对象的一个方法,用于计算数据框中每列的描述性统计量。这些统计量包括:计数(count)、平均值(mean)、标准差(std)、最小值(min)、四分位数(25%,50%,75%)和最大值(max)。

import pandas as pd  

# 创建一个简单的数据框  
data = {  
    'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],  
    'age': [25, 32, 18, 47, 22],  
    'salary': [50000, 70000, 30000, 90000, 60000]  
}  

df = pd.DataFrame(data)  

display(df)
# 查看数据框的描述性统计量  
df.describe()
name age salary
0 Alice 25 50000
1 Bob 32 70000
2 Charlie 18 30000
3 David 47 90000
4 Eve 22 60000
age salary
count 5.000000 5.000000
mean 28.800000 60000.000000
std 11.388591 22360.679775
min 18.000000 30000.000000
25% 22.000000 50000.000000
50% 25.000000 60000.000000
75% 32.000000 70000.000000
max 47.000000 90000.000000

df.drop(): 删除特定索引

df.drop(index=[1, 2])
name age salary
0 Alice 25 50000
3 David 47 90000
4 Eve 22 60000
df.drop(columns=['age'])
name salary
0 Alice 50000
1 Bob 70000
2 Charlie 30000
3 David 90000
4 Eve 60000

unique() : 唯一,去重

df2 = pd.DataFrame(data=np.random.randint(5, 10, size=(3, 4)), columns=list('ABCD'))
df2
A B C D
0 7 5 9 8
1 5 6 6 7
2 6 6 5 9
df2['B'].unique()
array([5, 6])

df.sort_values(): 根据值排序

df
name age salary
0 Alice 25 50000
1 Bob 32 70000
2 Charlie 18 30000
3 David 47 90000
4 Eve 22 60000
df.sort_values(by='age')  # 升序
name age salary
2 Charlie 18 30000
4 Eve 22 60000
0 Alice 25 50000
1 Bob 32 70000
3 David 47 90000
df.sort_values(by='salary', ascending=False)  # 降序
name age salary
3 David 47 90000
1 Bob 32 70000
4 Eve 22 60000
0 Alice 25 50000
2 Charlie 18 30000
df ##排序后不改变原来数据框的结构
name age salary
0 Alice 25 50000
1 Bob 32 70000
2 Charlie 18 30000
3 David 47 90000
4 Eve 22 60000

df.info(): 查看数据信息

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  5 non-null      int64 
dtypes: int64(2), object(1)
memory usage: 248.0+ bytes

4.3.2 异常值过滤

# 创建一个简单的数据框  
data = {  
    'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],  
    'age': [25, 32, 18, 47, 22],  
    'salary': [50000, 70000, 30000, 90000, 60000]  
}  

df = pd.DataFrame(data)  
df
name age salary
0 Alice 25 50000
1 Bob 32 70000
2 Charlie 18 30000
3 David 47 90000
4 Eve 22 60000
# bool值索引过滤异常值
cond = df['age'] > 30
cond
0    False
1     True
2    False
3     True
4    False
Name: age, dtype: bool
df[~cond]
name age salary
0 Alice 25 50000
2 Charlie 18 30000
4 Eve 22 60000