pandas相关知识

pandas 数据结构

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

Series

Series 是一种类似于一维数组的对象,由下面两部分组成

  • vaules:一组数据(ndarray 类型)
  • index:相关数据索引标签

1、Series 的创建

两种创建方式

1.1 由列表或者 numpy 数组创建
  • 默认索引为 0 到 n - 1 的整数类型索引
list1 = [11, 22, 33, 44]
s = pd.Series(list1)
s

n = np.array(list1)
s = pd.Series(n)
s

"""
0    11
1    22
2    33
3    44
dtype: int32
"""

# 类型
type(s)
  • index 和 values
# 值
s.values
"""
array([11, 22, 33, 44])
"""

# 索引
s.index
list(s.index)

"""
[0, 1, 2, 3]
"""

# 修改索引 index
s.index = ['A', 'B', 'C', 'D']
s.index = list('BCDE')
s

"""
B    11
C    22
D    33
E    44
dtype: int32
"""

# 通过索引 index 获取值
s.B, s.C, s['D']

"""
(11, 22, 33)
"""

# 通过索引修改值, 数字索引要用 []
s['E'] = 100
s

"""
B     11
C     22
D     33
E    100
dtype: int32
"""
1.2 由字典创建
d = {
    'a': 11,
    'b': 22,
    'c': 33,
    'd': 44
}
s = pd.Series(d)
s

s.index = list('ABCD')
s

"""
A    11
B    22
C    33
D    44
dtype: int64
"""

d = {
    'a': np.random.randint(0, 10, size=(2, 3)),
    'b': np.random.randint(0, 10, size=(2, 3)),
    'c': np.random.randint(0, 10, size=(2, 3)),
    'd': np.random.randint(0, 10, size=(2, 3))
}
s = pd.Series(d)
s

"""
a    [[6, 1, 2], [7, 3, 7]]
b    [[0, 1, 6], [1, 1, 6]]
c    [[2, 3, 8], [7, 3, 6]]
d    [[5, 8, 5], [2, 7, 0]]
dtype: object
"""

s['a']

"""
array([[6, 1, 2],
       [7, 3, 7]])
"""

pd.Series([1, 2, 3], index=['鲁班', '李白', '杜甫'], name='历史人物')

"""
鲁班    1
李白    2
杜甫    3
Name: 历史人物, dtype: int64
"""

2、Series 的索引

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

2.1 显示索引
  • 使用index 中的元素作为索引值
  • 使用.loc[] (推荐)
s = pd.Series({"Python": 100, 'Java': 90, 'Golang': 98})
s

"""
Python    100
Java       90
Golang     98
dtype: int64
"""

# 显示索引:使用索引名
s['Python']

# 取多个元素,获取到的类型是:Series
s[['Python', 'Java']]

# 使用 loc[]
s.loc['Python']
s.loc[['Python', 'Java']]

"""
Python    100
Java       90
dtype: int64
"""
2.2 隐式索引
  • 使用整数作为索引值
  • 使用.iloc[] 推荐
s = pd.Series({"Python": 100, 'Java': 90, 'Golang': 98})
s

"""
Python    100
Java       90
Golang     98
dtype: int64
"""

# 隐式索引:使用数字下标
s[0]
s[[0, 2]]

# iloc
s.iloc[0]
s.iloc[[0, 2]]

"""
Python    100
Golang     98
dtype: int64
"""

3、Series 的切片

s = pd.Series({
    "语文": 100,
    "数学": 120,
    "英语": 120,
    "物理": 90,
    "化学": 89,
    "生物": 99
})
s

"""
语文    100
数学    120
英语    120
物理     90
化学     89
生物     99
dtype: int64
"""

# 切片
# Series 是一维数组

# 隐式切片
s[1: 4]
s.iloc[1: 4]

# 显示切片
s["数学": "化学"]
s.loc["数学": "化学"]

4、Series 的基本属性和方法

  • shape 形状
  • size 长度
  • index 索引
  • values 值
  • name 名字
  • head() 查看前几条数据,默认5条
  • tail() 查看后几条数据,默认5
# 形状
s.shape

# 元素个数
s.size

# 值
s.values

# 索引名字
s.name

# 查看前几条数据
s.head()
s.head(2)

# 查看后几条数据
s.tail()
s.tail(2)
  • 检测缺失数据
    • pd.isnull()
    • pd.notnull()
    • isnull()
    • notnull()
s = pd.Series(['张三', '李四', '王五', np.nan])
s

# Nan:空

"""
0     张三
1     李四
2     王五
3    NaN
dtype: object
"""

# isnull 判断是否为空
s.isnull()
# pd.isnull(s)

# notnull 判断是否不为空
s.notnull()
# pd.notnull(s)

"""
0     True
1     True
2     True
3    False
dtype: bool
"""
  • 使用 bool 值索引过滤数据
# 过滤掉空值、
cond1 = s.isnull()
cond1

"""
0    False
1    False
2    False
3     True
dtype: bool
"""
  
# ~ 取反
s[~cond1]

"""
0    张三
1    李四
2    王五
dtype: object
"""

# 过滤掉空值
cond2 = s.notnull()
cond2
s[cond2]

"""
0    张三
1    李四
2    王五
dtype: object
"""

5、Series 的运算

5.1 适用于 Numpy 的数组运算也适用于 Series
s = pd.Series(np.random.randint(10, 100, size=5))
s

"""
0    39
1    61
2    11
3    44
4    46
dtype: int32
"""

# 基本算术运算
s + 100
s - 100
s * 100
s / 100
s // 2
s % 3
5.2 Series 之间的运算
  • 在运算中自动对齐索引
  • 如果索引不对应,则补NaN
  • Series 没有广播机制
s1 = pd.Series(np.random.randint(10, 100, size=3))
s2 = pd.Series(np.random.randint(10, 100, size=3))
display(s1, s2)

s1 + s2
s1 - s2

s3 = pd.Series(np.random.randint(10, 100, size=3))
s4 = pd.Series(np.random.randint(10, 100, size=4))
display(s3, s4)

s3 + s4

"""
0    100.0
1     98.0
2    190.0
3      NaN
dtype: float64
"""
  • 注意:要想保留所有的 index,则需要使用 .add() 函数
display(s3, s4)
s3.add(s4, fill_value=0)

总结

  • Series:可以看作是一个有序的字典结构

DataFrame

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

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

1、DataFrame 的创建

DataFrame以字典的键作为每一【列】的名称,以字典的值(一个数组 )作为每一列。

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

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

1.1 最常用的方法是传递一个字典创建。
d = {
    "name": ["python", "java", "golang"],
    "age": [11, 30, 10]
}
df = pd.DataFrame(d)
df

"""
  name	 age
0	python	11
1	java	  30
2	golang	10
"""

DataFrame 的基本属性和方法:

  • values 值,二维 ndarray 数组
  • columns 列索引
  • index 行索引
  • shape 形状
  • head() 查看前几条数据,默认5条
  • tail() 查看后几条数据,默认5条
display(df)
df.values
df.columns
df.index
df.shape
df.tail(2)
df.head(2)

# 设置 index
df.index = list("ABC")
df

#设置列索引
df.columns = ["name1", "name2"]
df
1.2 其他创建DataFrame 方式
d = {
    "name": ["python", "java", "golang"],
    "age": [11, 30, 10]
}
df = pd.DataFrame(d, index=list("ABC"))
df

"""
  name	  age
A	python	11
B	java	  30
C	golang	10
"""

df = pd.DataFrame(
    data = np.random.randint(10, 100, size=(4, 6)),
    index = ["Jack", "Marry", "Tom", "Jone"],
    columns= ["语文", "数学", "物理", "英语", "美术", "生物"]
)
df

"""
			语文	数学	物理	英语	美术	生物
Jack		65	55		78		87		17	87
Marry		72	78		55		88		46	92
Tom			50	50		49		63		80	92
Jone		94	87		23		26		51	78
"""

2、DataFrame 的索引

2.1 对列进行索引
  • 通过类似字典的方式
  • 通过属性的方式

可以将 DataFrame 的列获取为一个 Series。返回的 Series 拥有原 DataFrame 相同的索引,且 name 属性也已经设置好了,就是相应的列名。

df.语文 # Series 类型
df["语文"]

# 使用两个 [[]] 获取的是 DataFrame 类型

df[["语文", "英语"]]
2.2 对行进行索引
  • 使用 .loc[] 加index 来进行索引
  • 使用.iloc[] 加整数来进行行索引

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

# DataFrame 默认是先取列索引

# 取行索引
df.loc["Jack"] # Series 类型
df.iloc[0]

# 使用两个中括号:DataFrame 类型
df.loc[["Jack", "Tom"]]
df.loc[["Jack"]]
df.iloc[[0, 3]]
df.iloc[[0, -1]]
2.3 对元素索引的方法
  • 使用列索引
  • 使用行索引(iloc[3, 1] 相当于两个参数;iloc[[3, 3]] 里面的[3, 3]看做一个参数)
  • 使用values属性(二维 NumPy数组)
# 先取列在取行
df["语文"]["Jack"]

# 先取行在取列
df.loc["Jack"]["语文"]
df.iloc[0][0]
df.iloc[0, 0]

3、DataFrame 的切片

注意

直接用中括号时:

  • 索引优先对列进行操作
  • 切片优先对行进行操作
# 行切片
df[1:3] # 左闭右开
df["Marry": "Jone"]  # 左闭右闭

df.iloc[1:3] # 左闭右开
df.loc["Marry": "Jone"]  # 左闭右闭


# 列切片
# 对列做切片,也必须先对行切片
df.iloc[:,1:4]

df.loc[:, "数学": "英语"]

# 同时对行和列做切片
df.iloc[1:3, 1:4]
df.loc["Marry": "Jone", "数学": "英语"]

总结

  • 要么取一行或一列:索引
  • 要么取连续的多行或多列:切片
  • 要么取不连续的多行或多列:中括号

4、DataFrame 的运算

4.1 DataFrame 之间的运算
  • 在运算中自动对齐不同索引的数据
  • 如果索引不对应,则补NaN
  • DataFrame 没有广播机制

创建DataFrame df1 不同人员的各科目成绩,月考一

df1 = pd.DataFrame(
    data = np.random.randint(10, 100, size=(3, 3)),
    index = ["Jack", "Marry", "Tom"],
    columns= ["语文", "数学", "物理"]
)
df1

创建DataFrame df1 不同人员的各科目成绩,月考二

df2 = pd.DataFrame(
    data = np.random.randint(10, 100, size=(3, 3)),
    index = ["Jack", "Marry", "Tom"],
    columns= ["语文", "数学", "物理"]
)
df2

DataFrame 与标量之间的预算

df1 + 100
df1 - 100
df1 * 10
df1 / 10

DataFrame 之间的运算

df1 + df2

使用 .add() 函数,填充数据

df3 = pd.DataFrame(
    data = np.random.randint(10, 100, size=(4, 4)),
    index = ["Jack", "Marry", "Tom", "Jone"],
    columns= ["语文", "数学", "物理", "英语"]
)
df3

df1 + df3

# 先填充 0 后相加
df1.add(df3, fill_value=0)

#除法
df1.divide(df3, fill_value=2)
4.2 Series 与 DataFrame 之间的运算
  • 使用Python操作符:以行为单位操作(参数必须是行),对所有行都有效。
    • 类似于 NumPy 中二维数组与一维数组的运算,但可能出现NaN
  • 使用pandas操作函数:
    • axis=0:以列为单位操作(参数必须是列),对所有列都有效
    • axis=1:以行为单位操作(参数必须是行),对所有的行都有效
s = pd.Series([100, 10, 1], index=df1.columns)
s

df1 + s
df1.add(s, axis=1)

s = pd.Series([100, 10, 1], index=df1.index)
s

df1.add(s, axis=0)

5、pandas 层次化索引

5.1 创建多层行索引
5.1.1 隐式构造

最常见的方法是给 DataFrame 构造函数的 index 参数传递两个或更多的数组

data = np.random.randint(0, 100, size=(6, 6))

index = [
    ['1班', '1班', '1班', '2班', '2班', '2班'],
    ['张三', '李四', '王五', '鲁班', '张三丰', '张无忌'],
]

columns = [
    ['期中', '期中', '期中', '期末', '期末', '期末'],
    ['语文', '数学', '英语', '语文', '数学', '英语']
]

df = pd.DataFrame(data=data, index=index, columns=columns)
df
  • Series 也可以创建多层索引
data = np.random.randint(0, 100, size=6)
index = [
    ['1班', '1班', '1班', '2班', '2班', '2班'],
    ['张三', '李四', '王五', '鲁班', '张三丰', '张无忌'],
]

s = pd.Series(data=data, index=index)
s
5.1.2 显示构造
  • 使用数组
data = np.random.randint(0, 100, size=(6, 6))

index = pd.MultiIndex.from_arrays([
    ['1班', '1班', '1班', '2班', '2班', '2班'],
    ['张三', '李四', '王五', '鲁班', '张三丰', '张无忌'],
])

columns = [
    ['期中', '期中', '期中', '期末', '期末', '期末'],
    ['语文', '数学', '英语', '语文', '数学', '英语']
]

df = pd.DataFrame(data=data, index=index, columns=columns)
df
  • 使用元组 tuple
data = np.random.randint(0, 100, size=(6, 6))

index = pd.MultiIndex.from_tuples(
    (
        ('1班', '张三'),('1班', '李四'), ('1班', '王五'),
        ('2班', '鲁班'), ('2班', '张三丰'), ('2班', '张无忌')
    )
)

columns = [
    ['期中', '期中', '期中', '期末', '期末', '期末'],
    ['语文', '数学', '英语', '语文', '数学', '英语']
]

df = pd.DataFrame(data=data, index=index, columns=columns)
df
  • 使用product
  • 笛卡尔积
data = np.random.randint(0, 100, size=(6, 6))

# 笛卡尔积:{a,b} {c, d} => {a,c} {a, d} {b,c} {b,d}
index = pd.MultiIndex.from_product([
    ['1班', '2班'],
    ['张三', '李四', '王五'],
])

columns = [
    ['期中', '期中', '期中', '期末', '期末', '期末'],
    ['语文', '数学', '英语', '语文', '数学', '英语']
]

df = pd.DataFrame(data=data, index=index, columns=columns)
df
5.2 多层索引对象的索引与切片操作
5.2.1 Series的操作
  • 对于Series 来说,直接中括号[] 与使用 .loc() 完全一样

    索引

# 显示索引
s['1班']
s.loc['1班']
s[['1班', '2班']]
s['1班']['张三']
s.loc['1班']['张三']
# 隐式索引
s[0]
s[1]
s.iloc[1]
s.iloc[[1, 2]]

# 切片
# 显示切片
s['1班': '2班']
s.loc['1班': '2班']
s.loc['1班'][:]

# 建议使用隐式索引
s[1:5]
s.iloc[1:5]
5.2.2 DataFrame 操作

索引

# 获取元素
df['期中']["数学"]['1班']['张三']

df.iloc[0,1]

df.loc[('1班', '张三'), ('期中', '数学')]

# 列索引
df['期中']
df['期中'][["数学"]]
df['期中']['数学']
df['期中', '数学']

df.iloc[:,2]
df.iloc[:, [0, 2, 1]]
df.loc[:, ('期中', '数学')]

# 行索引
df.loc['2班']
df.loc['2班'].loc['张三']
df.loc['2班', '张三']
df.loc[('2班', '张三')]

df.iloc[1]
df.iloc[[1]]
df.iloc[[1, 3, 4, 2]]

切片

# 行切片
df.iloc[1:5]

df.loc[('1班', '李四'): ('2班', '李四')]

df.loc['1班': '2班']

# 列切片
df.iloc[:, 1:5]
df.loc[:, '期中': '期末']
df.loc[('1班', '李四'): ('2班', '李四')]


# 建议切片使用隐式索引
5.3 索引堆叠
  • stack()
  • unstack() 【小技巧】使用 stack() 的时候, level等于 哪一个,哪一个就消失,出现在行里
data = np.random.randint(0, 100, size=(6, 6))

# 笛卡尔积:{a,b} {c, d} => {a,c} {a, d} {b,c} {b,d}
index = pd.MultiIndex.from_product([
    ['1班', '2班'],
    ['张三', '李四', '王五'],
])

columns = [
    ['期中', '期中', '期中', '期末', '期末', '期末'],
    ['语文', '数学', '英语', '语文', '数学', '英语']
]

df = pd.DataFrame(data=data, index=index, columns=columns)
df


# stack:将列索引变成行索引
df.stack()  # 默认是将最里层的列索引变成行索引
df.stack(level=-1)
df.stack(level=1)
df2 =df.stack(level=0)
df2

【小技巧】使用 unstack() 的时候,level等于哪一个,哪一个就消失,出现在列里

# unstack():将行索引变成列索引
df2.unstack()
df2.unstack(level=-1)
df2.unstack(level=2)
df.unstack(level=1)
df.unstack(level=0)
data = np.random.randint(0, 100, size=(6, 6))

index = pd.MultiIndex.from_tuples(
    (
        ('1班', '张三'),('1班', '李四'), ('1班', '王五'),
        ('2班', '鲁班'), ('2班', '张三丰'), ('2班', '张无忌')
    )
)

columns = [
    ['期中', '期中', '期中', '期末', '期末', '期末'],
    ['语文', '数学', '英语', '语文', '数学', '英语']
]

df = pd.DataFrame(data=data, index=index, columns=columns)
df
  • fill_value(填充)
df.unstack()
df.unstack(fill_value=0)
5.4 聚合操作
  • 求和
  • 平均值
  • 最大值
  • 最小值
df2 = df.loc['1班', '期中']
df2

df2.values.sum()

df2.sum()
df2.sum(axis=0) # 求每一列中多行的和
df2.sum(axis=1) # 求每一行中多列的和

df.sum() # 默认是求每一列中多行的和
df.sum(axis=0) 

df.sum(axis=1)  # 默认是求每一行中多列的和

6、pandas 重复值处理

6.1 删除重复行
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
  • 使用duplicated()函数检测重复的行
    • 返回元素为布尔类型的 Series 对象
    • 每个元素对应一行,如果该行不是第一次出现,则元素为True
df = make_df([1, 2, 3, 4], list('ABCD'))
df

# 让第一行和第二行重复
df.loc[1] = df.loc[2]
df

# 判断是否和前面的行重复了
df.duplicated()

df.duplicated(keep="first") # 保留第一行
df.duplicated(keep="last") # 保留最后一行
df.duplicated(keep=False) # 标记所有重复行,不保留任何一行

df.loc[1, 'D'] = 'DDD'
df

# subset:子集
df.duplicated(subset=['A', 'B', 'C'])
  • 使用drop_duplicates()函数删除重复的行
df.drop_duplicates()
df.drop_duplicates(subset=['A', 'B', 'C'], keep="last")
6.2 映射

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

包含三种操作:

  • replace() 函数:替换元素
  • map()函数:新建一列,最重要
  • raname() 函数:替换索引
6.2.1 replace() 函数:替换元素

使用replace()函数,对values 进行替换操作

index = ["张三", "张三丰", "李白", "杜甫"]
colunms = ["python", "java", "h5", "ui"]

data = np.random.randint(0, 100, size=(4, 4))

df = pd.DataFrame(data=data, index=index, columns=colunms)
df

# 替换元素
df.replace({4:50, 1:100})
6.2.2 map() 函数:适合处理某一单独的列

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

df2 = df.copy()
df2

# map 一般用在 Series 数据结构,不能用于 DataFrame

# df2["python"].map({25:250, 19:190, 63:630, 1:100})

# 将Python 的每个人的成绩乘以 10
df2["python"].map(lambda x:x*10)

# 新增一列
df2["pandas"] = df2["python"].map(lambda x:x*10)
df2

# 新增一列:判断 Java的成绩是否及格

df2["java是否及格"] = df2["java"].map(lambda n:'及格' if n >= 60 else '不及格')
df2

# 使用普通函数
# 新增一列:判断 UI 成绩
# <60  不及格
# 60 <= n <80 及格
# > 80 优秀

def fn(n):
    pass


df2["UI等级"] = df2["ui"].map(fn)
df2
6.3 异常值检查和过滤
  • describe():查看每一列的描述性统计量
data = np.random.randint(0, 10, size=(5, 3))

df = pd.DataFrame(data=data, index=list('ABCDE'), columns=['python', 'numpy', 'pandas'])
df

df.describe()
df.describe([0.01, 0.3, 0.4, 0.9, 0.99])
df.describe([0.01, 0.3, 0.4, 0.9, 0.99]).T
  • df.std():可以求得DataFrame对象每一列的标准差
df.std()
  • df.drop():删除特定索引
# df2.drop('A') # 删除行
# df2.drop("python", axis=1) # 删除列
# df2.drop(index='A') # 删除行
# df2.drop(columns='python') # 删除列

# # 删除多列
# df2.drop(columns=["python", 'numpy'])

# 删除多行
df2.drop(index=['C', 'D'], inplace=True)
df2
  • unique():唯一,去重
# DataFrame 没有 unique,Series 调用 unique
df['python'].unique()
  • df.query():按条件查询
df.query('python==9')  # 找到 Python列中等于 9的所有行
df.query('python < 8')

df.query('python > 6 and numpy == 2')

df.query('python == 3 or numpy == 2')
df.query('python == 3 | numpy == 2')

df.query('python in [3, 4, 5, 6]') # 成员运算符

# 使用变量
n = 4
df.query('python == @n') # @n 表示使用变量n 的值

m = [3, 4, 5, 6]
df.query('python in @m')  # 成员运算符
  • df.sort_values():根据值排序
  • df.sort_index():根据索引排序
# sort_values:默认按照列名排序,默认升序(常用)
df.sort_values("python") 

# ascending 是否升序,默认是 True
df.sort_values('python', ascending=False) # 降序

# 根据行索引排序 (不常用)
df.sort_values('B', axis=1)

# 按照索引名排序

# 默认是对行索引进行排序,默认是升序
df.sort_index(ascending=False)

# 对列索引进行排序,默认是升序
df.sort_index(ascending=False, axis=1)
  • df.info()
# info:常用
df.info()

练习: 新建一个形状为 10000 * 3 的标准正态分布的 DataFrame(np.random.randn),去除掉所有满足以下情况的行:其中任一元素绝对值大于3被标准差

df = pd.DataFrame(np.random.randn(10000, 3))
display(df.head())

# 过滤掉 大于3倍标准差的行

# 标准差 df.std
# 决定值 df.abs
# cond:找到每一个元素是否大于 3倍标准差
cond = df.abs() > df.std() * 3
cond

# 找到存在大于 3被标准差的行
cond2 = cond.any(axis=1)

cond2
# cond2.sum()

# bool 值索引,过滤异常值(大于3倍标准差)
df.loc[~cond2]
6.4 抽样
  • 使用.take() 函数排序
  • 可以借助 np.random.permutation() 函数随机排序

无放回抽样

data = np.random.randint(0, 10, size=(5, 3))

df = pd.DataFrame(data=data, index=list('ABCDE'), columns=['python', 'numpy', 'pandas'])
df

df.take([1,0, 2]) # 行排列

df.take([1, 0, 2], axis=1)  # 列排序

# 随机排序
np.random.permutation([0, 1, 2])

# 无放回抽样:依次随机取出,没有重复值
df.take(np.random.permutation([0, 1, 2]))

有放回抽样

# 有放回抽样:可能会出现重复值
np.random.randint(0, 5, size=5)

df.take(np.random.randint(0, 3, size=5))

7、pandas 数据合并

  • pd.concat
  • pd.append
  • pd.merge
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
7.1 使用 pd.concat() 级联

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

7.1.1 简单级联
df1 = make_df([1, 2], ['A', 'B'])
df2 = make_df([3, 4], ['A', 'B'])
display(df1, df2)

# 默认垂直合并
pd.concat([df1, df2])

# 左右合并,水平合并
pd.concat([df1, df2], axis=1)
  • 忽略索引 ignore_index
# 忽略行索引,重置索引
pd.concat([df1, df2], ignore_index=True)
  • 使用多层索引 keys
# 使用多层索引 keys
pd.concat([df1, df2], keys=['x', 'y'])

pd.concat([df1, df2], keys=['x', 'y'], axis=1)
7.2.2 不匹配级联

不匹配指的是级联的维度的索引不一致,例如纵向级联时列索引不一致,横向级联时行索引不一致

df3 = make_df([1, 2, 3, 4], list('ABCD'))
df4 = make_df([2, 3, 4, 5], list('BCDE'))
display(df3, df4)

# 对应索引没有值,对应填充 NaN
pd.concat([df3, df4])
  • 外连接:补 NaN (默认模式)
# 外连接:类似并集,显示所有数据
pd.concat([df3, df4])
pd.concat([df3, df4], join='outer')
  • 内连接:只连接匹配的项
# 内连接:类似交集,只显示共同的部分
pd.concat([df3, df4], join='inner')
7.2.3 使用 append() 函数添加

由于在后面级联的使用非常普遍,因此有一个函数 append 专门用于在后面添加

df3._append(df4)
7.2 使用 pd.merge() 合并
  • 类似 MySQL中表和表直接的合并
  • merge 与 concat 的区别在于, merge 需要依据某一共同的行或列进行合并
  • 使用 pd.merge() 合并时,会自动根据两者相同 column 名称的那一列,作为 key 来进行合并
  • 每一列元素的顺序不要求一致
7.2.1 一对一合并
df1 = pd.DataFrame({
    "name": ["张三", "李四", "王五"],
    "id": [1, 2, 3],
    "age": [22, 23, 24]
})

df2 = pd.DataFrame({
    "id": [2, 3, 4],
    "sex": ["男", "女", "男"],
    "job": ["Saler", "CEO", "Programer"]
})

display(df1, df2)

# 合并
pd.merge(df1, df2)
7.2.2 多对一合并
df3 = pd.DataFrame({
    "name": ["张三", "李四", "王五"],
    "id": [1, 2, 2],
    "age": [22, 23, 24]
})

df4 = pd.DataFrame({
    "id": [2, 3, 4],
    "sex": ["男", "女", "男"],
    "job": ["Saler", "CEO", "Programer"]
})

display(df3, df4)

df3.merge(df4)
7.2.3 多对多合并
df5 = pd.DataFrame({
    "name": ["张三", "李四", "王五"],
    "id": [1, 2, 2],
    "age": [22, 23, 24]
})

df6 = pd.DataFrame({
    "id": [2, 2, 4],
    "sex": ["男", "女", "男"],
    "job": ["Saler", "CEO", "Programer"]
})

display(df5, df6)

df5.merge(df6)
7.2.4 key 的规范化
  • 使用on=显示指定哪一列为 key,当两个 DataFrame 有多列相同时使用
df1 = pd.DataFrame({
    "id": [1, 2, 3],
    "name": ["张三", "李四", "王五"],
    "age": [22, 23, 24]
})

df2 = pd.DataFrame({
    "id": [2, 3, 4],
    "name": ["男", "女", "男"],
    "job": ["Saler", "CEO", "Programer"]
})

display(df1, df2)

# 如果有多列名称相同,需要指定一列作为连接的字段
df1.merge(df2, on="id")
  • 使用 left_on 和 right_on 指定左右两边的列作为 key,当左右两边的 key 都不想等时使用
df1 = pd.DataFrame({
    "id": [1, 2, 3],
    "name": ["张三", "李四", "王五"],
    "age": [22, 23, 24]
})

df2 = pd.DataFrame({
    "id2": [2, 3, 4],
    "name": ["男", "女", "男"],
    "job": ["Saler", "CEO", "Programer"]
})

display(df1, df2)

# 如果没有相同的列名,则需要使用 left_on,right_on 来分别指定两个表中的不同列作为连接的字段
df1.merge(df2, left_on="id", right_on="id2")
  • 当左边的列和右边的 index 相同的时候,使用 right_index=True
df1 = pd.DataFrame({
    "id": [1, 2, 3],
    "name": ["张三", "李四", "王五"],
    "age": [22, 23, 24]
})

df2 = pd.DataFrame({
    "id2": [2, 3, 4],
    "name": ["男", "女", "男"],
    "job": ["Saler", "CEO", "Programer"]
})

display(df1, df2)

# 可以使用行索引作为连接的字段
df1.merge(df2, left_index=True, right_index=True)
  • 内合并与外合并

    • 内合并:只保留两者都有的 key (默认模式)

      df1 = pd.DataFrame({
          "id": [1, 2, 3],
          "name": ["张三", "李四", "王五"],
          "age": [22, 23, 24]
      })
      
      df2 = pd.DataFrame({
          "id": [2, 3, 4],
          "sex": ["男", "女", "男"],
          "job": ["Saler", "CEO", "Programer"]
      })
      
      display(df1, df2)
      
      # 默认是内合并 (inner join)
      df1.merge(df2, how="inner")
      
    • 外合并 how=‘outer’:补 NaN

# 外合并:会显示两个表的所有数据
df1.merge(df2, how="outer")
  • 左合并、右合并:how=“left”, how=“right”
# 左连接:显示左边 df1 表的所有数据和 右边表 df2 的公共数据
df1.merge(df2, how="left")

# 右连接:显示右边 df2 表的所有数据和 左边表 df1 的公共数据
df1.merge(df2, how="right")
7.2.5 列冲突的解决

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

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

df1 = pd.DataFrame({
    "id": [1, 2, 3],
    "name": ["张三", "李四", "王五"],
    "age": [22, 23, 24]
})

df2 = pd.DataFrame({
    "id": [2, 3, 4],
    "name": ["男", "女", "男"],
    "job": ["Saler", "CEO", "Programer"]
})

df1.merge(df2, on="id", suffixes=['_df1', '_df2'])

merge 合并总结:

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

8、pandas 缺失值处理

有两种丢失数据(空值)

  • None
  • np.nan
8.1 None
  • None 是 Python自带的,是 Python中的空对象。None 不能参与到任何计算中
  • object 类型的运算要比 int 类型的运算慢的 多
%timeit np.arange(1e6, dtype=object).sum()

%timeit np.arange(1e6, dtype=np.int32).sum()
8.2 np.nan
  • np.nan 是浮点类型,能参与到计算中。但计算的结果总是 NaN
type(np.nan)
  • 但可以使用 np.nan() 函数来计算nan,此时会过滤掉 nan
n = np.array([1, 2, 3, np.nan, 5, 6])
n

"""
array([ 1.,  2.,  3., nan,  5.,  6.])
"""

np.sum(n) # nan
np.nansum(n) # 自动过滤 nan 不计算

np.nan + 10
8.3 pandas 中的 None 与 NaN
8.3.1 pandas 中的 None 与 np.nan 都视作 np.nan
  • 创建 DataFrame
data = np.random.randint(0, 100, size=(5, 5))
df = pd.DataFrame(data=data, columns=list("ABCDE"))
df
  • 使用 DataFrame 行索引与列索引修改 DataFrame 数据
df.loc[2, 'B'] = np.nan
df.loc[3, 'C'] = None
df
8.3.2 pandas 中 None 与 np.nan 的操作
  • isnull()
  • notnull()
  • all()
  • any()
  • dropna() 过滤丢失数据
  • fillna() 填充丢失数据

判断函数

  • isnull()
  • notnull()
df.isnull()

df.notnull()

# all()  必须全部为 True 才会是 True,类似 and
# any()  只要有一个为 True 就为 True,类似 or
# 找有空值的列
df.isnull().any() # 常用,尽可能找到有空的列
# df.isnull().all() # 必须全部都为空的行或列才会为True

# 找没有空值的列
df.notnull().all() # 常用,尽量找到没有空值的列或行
# df.notnull().any()

# 找有空的行
df.isnull().any(axis=1)

# 找没有空值的行
df.notnull().all(axis=1)
  • 使用 bool 值索引过滤数据
# 行过滤
cond = df.isnull().any(axis=1)
# display(~cond) # ~ 取反
df[~cond]

cond = df.notnull().all(axis=1)
df[cond]

# 过滤列
cond = df.isnull().any()
cond

df.loc[:, ~cond]

cond = df.notnull().all()
df.loc[:, cond]

过滤函数

  • dropna()

可以选择过滤的是行还是列(默认为行)

# 默认删除有空的行
df.dropna()
df.dropna(axis=1) # 删除有空的列

也可以选择过滤的方式 how=‘all’

df.dropna(how='any')

# 必须所有数据都为 nan才会删除
df.dropna(how='all')

inplace=True 修改原数组

df2 = df.copy()
df2

df2.dropna(inplace=True)
df2
8.3.3 填充数据 Series/DataFrame
  • fillna()
# 填充空值
df.fillna(value=100)

df2 = df.copy()
df2.loc[1, "B"] = np.nan
df2.loc[2, "C"] = np.nan
df2

# 限制填充的次数
df2.fillna(value=100, limit=1, inplace=True)
df2

df.fillna(method='ffill') # 向下填充

df.fillna(method='backfill') # 向上填充

# method : {'backfill', 'bfill', 'ffill', None}, default None
#     Method to use for filling holes in reindexed Series:

#     * ffill: propagate last valid observation forward to next valid.
#     * backfill / bfill: use next valid observation to fill gap.

df.fillna(method='ffill', axis=1) # 向左填充
df.fillna(method='backfill', axis=1) # 向右填充
8.4 异常值处理
  • descirbe():查看每一列的描述性统计量
df.describe()
df.describe([0.3, 0.4, 0.9, 0.99])
df.describe([0.3, 0.4, 0.9, 0.99]).T
  • df.std():可以求得DataFrame 对象每一列的标准差
df.std()
  • df.drop():删除特定索引
df2 = df.copy()
df2

df2.drop(0)

9、pandas 数据分组聚合

数据聚合是数据处理的最后一步,通常是要使每一个数组生成一个单一的数值。

数据分类处理:

  • 分组:先把数据分为几组
  • 用函数处理:为不同组的数据应用不同的函数以转换数据
  • 合并:把不同组得到的结果合并起来

数据分类处理的核心:groupby() 函数

df = pd.DataFrame(
    {
        'color': ['green', 'green', 'yellow', 'blue', 'blue', 'yellow', 'yellow'],
        'price': [4, 3, 2, 1, 5, 7, 6]
    }
)
df

# 按照 color 进行分组
df.groupby(by='color')

使用 .groups属性查看各行的分组情况

df.groupby(by='color').groups

# 分组 + 聚合
df.groupby('color').sum()

练习: 菜品:item

颜色:color

重量:weight

价格:price

1.要求以属性作为列索引,新建一个 ddd

2.对 ddd 进行聚合操作,求出颜色为白色的价格总和

3.对ddd进行聚合操作,分别求出萝卜的所有重量以及平均价格

4.使用merge合并总重量及平均价格

ddd = pd.DataFrame(
    {
        "item": ['萝卜', '白菜', '辣椒', '冬瓜', '萝卜', '白菜', '辣椒', '冬瓜'],
        "color": ['白', '青', '红', '白', '青', '红', '白', '青'],
        'weight': [10, 20, 10, 10, 30, 40, 50, 60],
        'price': [0.99, 1.99, 2.99, 3.99, 4, 5, 6, 7]
    }
)
ddd

# .对 ddd 进行聚合操作,求出颜色为白色的价格总和

ddd.groupby("color")['price'].sum() # 结果是 Series 类型

ddd.groupby("color")[['price']].sum().loc[['白']]

# 对ddd进行聚合操作,分别求出萝卜的所有重量以及平均价格
df1 = ddd.groupby('item')[['weight']].sum()

df2 = ddd.groupby('item')[['price']].mean()

display(df1, df2)

# 使用merge合并总重量及平均价格

df1.merge(df2, left_index=True, right_index=True)

10、pandas 数学函数

  • 聚合函数
df = pd.DataFrame(data=np.random.randint(0, 100, size=(5, 3)))
df

df.count() # 非空的数量
df.count(axis=1)

df.max() # 默认求在每一列中不同行之间的最大值
df.max(axis=1) # 默认求在每一行之间的最大值

df.min()
df.min(axis=1)

df.median()  # 中位数

df.sum() # 求和
df.sum(axis=1)

df.values.sum() # 求所有数字的和

df.mean() # 求平均值
df.mean(axis=1)
  • 方差:
    • 当数据分布比较分散(即数据在平均数附近波动较大)时,各个数据与平均数的差的平方和比较大,方差就较大;
    • 当数据分布比较集中时,各个数据与平均数的差的平方和比较小
    • 因此方差越大,数据的波动越大;方差越小数据的波动就越小
  • 标准差
    • 标准差 = 方差的算术平方根
df.var()  # 方差
df.std() # 标准差
  • 其他数学函数
df.value_counts() # 统计元素出现次数

df.cumsum() #累加

df.cumprod() # 累乘
  • 协方差
    • 两组数值中每对变量的偏差乘积的平均值
    • 协方差 > 0:表式两组变量正相关
      • 如果两个变量的变化趋势一致,也就是说如果其中一个大于自身的期望值时另外一个也大于自身的期望值,那么两个变量之间的协方差就是正值;
    • 协方差<0:表式两组变量负相关
      • 如果两个变量的变化趋势相反,即其中一个变量大于自身的期望值时另外一个却小于自身的期望值,那么两个变量之间的协方差就是负值
    • 协方差=0:表式两组变量不相关
df.cov() # 协方差
df[0].cov(df[1]) # 第0列和第一列的协方差
  • 相关系数
  • 相关系数 = X 与 Y 的协方差 / (X 的标准差 * Y 的标准差)
  • 相关系数值的范围在 -1 和 +1 之间
  • r > 0 为正相关, r < 0 为负相关。r = 0 表示不相关
  • r 的绝对值越大,相关程度越高
df.corr() # 所有特征的相关系数

df.corrwith(df[2]) # 单一特征相关系数

11、pandas 时间序列

11.1 时间戳
# 1. 创建时间戳
pd.Timestamp('2024-08-17') # 时刻数据
pd.Period('2024-08-17', freq='D') # 时期数据
# freq:Y:年, M:月, D:日

# 批量生成时刻数据
# periods=4 创建4个时间
# freq='D':按天周期
index = pd.date_range("2024-08-17", periods=4, freq='D') # 时刻数据
index = pd.period_range("2024-08-17", periods=4, freq='D') # 时期数据
index

# 时间戳索引
pd.Series(np.random.randint(0, 10, size=4), index=index)


# 2.转化方法
pd.to_datetime(['2024-08-17', '2024.8.18', '2024/08/18'], format='mixed')

# 时间戳 -> 时间
pd.to_datetime([1899678987], unit='s')

dt = pd.to_datetime([1899678987000], unit='ms')
display(dt)

# 时间差 DateOffset
dt + pd.DateOffset(hours=8) # 加8个小时
dt + pd.DateOffset(days=8) # 加8天
dt - pd.DateOffset(days=8) # 减8天
dt + pd.DateOffset(days=-8) # 减8天


# 3.时间戳的索引和切片
index = pd.date_range('2030-3-14', periods=100, freq='D')
index

ts = pd.Series(range(len(index)), index=index)
ts

# 索引
ts['2030-03-15'] # 索引
ts['2030-03'] # 3月份
ts['2030'] # 年

# 切片
ts['2030-03-15': '2030-03-22']

# 时间戳索引
pd.Timestamp('2030-3-22')

ts[pd.Timestamp('2030-3-22')]

# 切片
ts[pd.Timestamp('2030-3-15'):pd.Timestamp('2030-3-22')]

# date_range
ts[pd.date_range('2030-3-24', periods=10, freq='D')]


# 4.属性
ts.index

ts.index.year # 年
ts.index.month # 月
ts.index.day # 日
ts.index.dayofweek # 星期几
11.2 时间序列常用方法
  • 对时间做一些移动/滞后、频率转换、采样等相关操作
index = pd.date_range('2030-3-15', periods=365, freq='D')
ts = pd.Series(np.random.randint(0, 500, len(index)), index=index)
ts

# 1、移动
ts.shift() # 默认后移一位
ts.shift(periods=2) # 后移2位 
ts.shift(periods=-2) # 前移两位


# 2、频率转换 
ts.asfreq(pd.tseries.offsets.Week()) # 天 -> 星期
ts.asfreq(pd.tseries.offsets.MonthEnd())  # 天 -> 月

# 由少变多:fill_value 填充
ts.asfreq(pd.tseries.offsets.Hour(), fill_value=0) # 天 -> 小时
11.3 resample:根据日期维度进行数据聚合
  • 按照分钟(T)、小时(H)、日(D)、周(W)、月(M)、年(Y) 等来作为日期维度
# 3.重采样
ts.resample('D').sum() # 以1天为单位进行汇总,求和
ts.resample('2D').sum() # 以2天为单位进行汇总,求和
ts.resample('2W').sum() # 以2周为单位进行汇总,求和
ts.resample('3M').sum() # 以3个月为单位进行汇总,求和


# 4、DataFrame 重采样
d = {
    'price': [10, 11, 23, 15, 18, 19, 20, 21],
    'score': [20, 10, 90, 89, 99, 28, 87, 69],
    'week': pd.date_range('2030-3-1', periods=8, freq='W')
}
df = pd.DataFrame(d)
df

# 对 week 列进行按月汇总
df.resample('M', on='week').sum()

df.resample('M', on='week').apply(np.sum)

# 对 week 列进行按月汇总:price 求平均值,score 求和
df.resample('M', on='week').agg({'score':np.sum, 'price': np.mean})
11.4 时区
index = pd.date_range('2030-3-1 00:00', periods=3, freq='D')
ts = pd.Series(np.random.randn(len(index)), index=index)
ts

# tz:timezone 时区
import pytz

# 常用的时区
pytz.common_timezones

# 时区表示
ts = ts.tz_localize(tz='UTC')
ts

# 时区转换
ts.tz_convert(tz='Asia/Shanghai')

12、pandas 分箱操作

  • 分箱操作就是将连续型数据离散化
  • 分箱操作分为等距分箱和等频分箱
data = np.random.randint(0, 100, size=(5, 3))
df = pd.DataFrame(data=data, columns=["python", "pandas", "java"])
df
12.1 等宽分箱
df.python

s = pd.cut(df.python, bins=4)
s

s.value_counts()

s.value_counts().plot.bar()


pd.cut(
    df.python, # 分箱数据
    bins=[0, 30, 60, 80, 100], # 分箱断点
    right=False, # 左闭右开,默认是左开右闭
    labels=['D', 'C', 'B', 'A'] # 分箱后分类的标签
)
12.2 等频分箱
pd.qcut(
    df.python, # 分箱数据
    q = 4, # 4等份
)

13、pandas 数据加载

13.1 CSV 加载数据
data = np.random.randint(0, 50, size=(10, 5))
df = pd.DataFrame(data=data, columns=["python", "java", "golang", "vue", "c++"])
df
  • df.to_csv 数据保存到 csv
# sep:分隔符,默认是逗号
# header:是否保存列索引
# index:是否保留行索引
df.to_csv('data.csv', sep=',', header=True, index=True)
  • df.read_csv:加载csv 数据
# 不获取列:header=None
pd.read_csv('data.csv', sep=',', header=[0], index_col=0)
  • pd.read_table
pd.read_table('data.csv', sep=',', index_col=0)
  • df.to_excel:保存到 excel 文件
# sheet_name:工作表名称
# header:是否保存列索引
# index:是否保存行索引
df.to_excel('data.xlsx', sheet_name="Sheet1", header=True, index=False)
  • pd.read_excel:读取exce
pd.read_excel('data.xlsx', sheet_name="Sheet1", header=[0, 1])
pd.read_excel('data.xlsx', sheet_name="Sheet1", header=[0])

# name 替换掉列索引
pd.read_excel('data.xlsx', sheet_name="Sheet1", header=[0], names=list('ABCDE'))
13.2 MySQL 数据读取

需要安装pymysql

  • pip install pymysql -i https://pypi.tuna.tsinghua.edu.cn/simple

需要安装 sqlalchemy:

  • pip install sqlalchemy -i https://pypi.tuna.tsinghua.edu.cn/simple
from sqlalchemy import create_engine
import pymysq

# 创建数据
data = np.random.randint(0, 150, size=(150, 3))
df = pd.DataFrame(data=data, columns=['python', 'pandas', 'pytorch'])
df.head()
  • 连接数据库
conn = create_engine('mysql+pymysql://root:123456@localhost:3306/jdbc_mysql')

df.to_sql(
    name='score', #数据库中的表名字
    con=conn, # 数据库连接对象
    index=False, # 是否保存行索引
    if_exists='append' # 如果表存在则追加数据
)
  • pd.read_sql:从MySQL中加载数据
pd.read_sql(
    sql='select * from score', # sql 语句
    con=conn # 数据库连接对象
)

14、pandas 绘图

  • Series 和 DataFrame 都有一个用于生成各类图表的 plot 方法
  • Pandas 的绘图是基于 Matplotlib,可以快速实现基本图形的绘制,复杂的图形还是需要用 Matplotlib

常见可视化图形:

  • 折线图
  • 条形图/柱形图
  • 饼图
  • 散点图
  • 箱体图
  • 面积图
  • 直方图
14.1 折线图

Series图形

s = pd.Series([100, 250, 300, 200, 150, 100])
s
s.plot()

在这里插入图片描述

  • 正弦曲线
# sin 曲线
x = np.arange(0, 2* np.pi, 0.1)
x

y = np.sin(x)
y

s = pd.Series(data=y, index=x)
s.plot()

在这里插入图片描述

DataFrame 图表

  • 图形的位置可能会随着数据的不同而不同
data = np.random.randint(50, 100, size=(5, 6))
index = ['1st', '2nd', '3th', '4th', '5th']
columns = ['jeff', 'jack', 'rose', 'lucy', 'bob', 'marry']
df = pd.DataFrame(data=data, index=index, columns=columns)
df
# 每一列一根线
df.plot()

# 每一行一根线
df.T.plot()

在这里插入图片描述

在这里插入图片描述

14.2 条形图和柱状图

Series 柱状图示例,kind=‘bar/barh’

df = pd.DataFrame(np.random.rand(10, 4))
df.plot(kind='bar') # 第一种方式
df.plot.bar() # 第二种方式

df.plot.bar(stacked=True) # 堆叠

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

s = pd.Series(data=[100, 200, 300, 200], index=list('ABCE'))
# s.plot(kind='bar') # 柱状图
# kind : str
#     The kind of plot to produce:

#     - 'line' : line plot (default)
#     - 'bar' : vertical bar plot
#     - 'barh' : horizontal bar plot
#     - 'hist' : histogram
#     - 'box' : boxplot
#     - 'kde' : Kernel Density Estimation plot
#     - 'density' : same as 'kde'
#     - 'area' : area plot
#     - 'pie' : pie plot
#     - 'scatter' : scatter plot (DataFrame only)
#     - 'hexbin' : hexbin plot (DataFrame only)
s.plot(kind='barh') # 水平:条形图

在这里插入图片描述

DataFrame 柱状图示例

data = np.random.randint(0, 100, size=(4, 3))
index = list('ABCD')
columns = ["python", "java", "c"]

df = pd.DataFrame(data=data, index=index, columns=columns)
df

df.plot(kind='bar')

df.plot(kind='barh')

在这里插入图片描述

在这里插入图片描述

练习

tips = pd.DataFrame(
    data = {
        'day': ['Fri', 'Stat', 'Sun', 'Thur'],
        '1': [1, 2, 0, 1],
        '2': [16, 53, 39, 48],
        '3': [1, 18, 15, 4],
        '4': [1, 13, 18, 5],
        '5': [0, 1, 3, 1],
        '6': [0, 0, 1, 3]
    }
)
tips

# 把 day 作为行索引
tips2 = tips.set_index('day')
tips2

# 求每一天的聚会规模
day_sum = tips2.sum(axis=1)
day_sum

# 每天聚会规模的比例
tips3 = tips2.div(day_sum, axis=0)
tips3

tips3.plot(kind='bar')

在这里插入图片描述

14.3 直方图

random 生成随机数百分比直方图,调用 hist 方法

  • 柱高表示数据的频数,柱宽表示各组数据的组距
  • 参数 bins 可以设置直方图方柱的个数上限,越大柱宽越小,数据分组越细致
  • 设置 density 参数为 True,可以把频数转换为概率
s = pd.Series([1, 2, 2, 2, 2, 3, 3, 4 , 5, 5, 6, 6])

# 直方图
# bins=5 表示5个组
# density 频数转换为概数
s.plot(kind='hist', bins=5, density=True)

在这里插入图片描述

kde 图:核密度估计,用于弥补直方图由于参数 bins 设置的不合理导致的精度缺失问题

# kde 图:核密度估计

s.plot(kind='hist', bins=5, density=True)
s.plot(kind='kde') # 可以结合上面的直方图一起显示,效果更好

在这里插入图片描述

14.4 饼图
df = pd.DataFrame(data=np.random.rand(4, 2), index=list('ABCD'), columns=['python', 'java'])
df

# 画饼图
# df['python'].plot(kind='pie', autopct='%.1f%%')

# subplots:子图
df.plot.pie(subplots=True, figsize=(8, 8), autopct='%.1f%%')

# 复杂的图可以用 matplotlib

在这里插入图片描述

14.5 散点图
  • 散点图是观察两个一维数据数列之间的关系的有效方法,DataFrame 对象可以
data = np.random.normal(size=(1000, 2))
data

df = pd.DataFrame(data=data, columns=list('AB'))
df.head()
# df.plot(kind='scatter', x='A', y='B')

# x='A':使用 A列作为 X 轴
# y='B':使用B列作为y 轴
df.plot.scatter(x='A', y='B')

在这里插入图片描述

14.6 面积图
df = pd.DataFrame(data=np.random.rand(10, 4), columns=list('ABCD'))
df

df.plot.area(stacked=True) # 堆叠

在这里插入图片描述

14.7 箱型图
df = pd.DataFrame(data=np.random.rand(10, 4), columns=list('ABCD'))
df

df.plot.box()

# 最大值
# 75%
# 50%
# 25%
# 最小值

# 圆点:表示异常值,离群点

请添加图片描述

DataFrame 的一些数据格式转换

在 Pandas 中,你可以将 DataFrame 转换为字典(dict)类型。Pandas 提供了几种不同的方式来实现这一转换,具体取决于你希望得到的字典格式。以下是几种常见的转换方法:

  1. to_dict() 方法:这是最常用的方法之一,它可以将 DataFrame 转换为多种格式的字典。
  2. 按列转换:将每一列转换为字典的键值对,其中键是索引,值是该索引对应的列值。
  3. 按记录转换:将每行数据作为一个字典,整个 DataFrame 转换为字典列表。
  4. 按索引转换:将索引作为字典的键,整个 DataFrame 作为值。
import pandas as pd

# 创建一个示例 DataFrame
data = {
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Age': [25, 30, 35],
    'City': ['New York', 'Los Angeles', 'Chicago']
}

df = pd.DataFrame(data)

# 输出原始 DataFrame
print("Original DataFrame:")
print(df)

# 转换为字典
# 1. 按列转换
column_dict = df.to_dict('list')
print("\nConverted to dict (by columns):")
print(column_dict)

# 2. 按记录转换
record_dict = df.to_dict('records')
print("\nConverted to dict (by records):")
print(record_dict)

# 3. 按索引转换
index_dict = df.to_dict('index')
print("\nConverted to dict (by index):")
print(index_dict)

"""
Original DataFrame:
      Name  Age         City
0    Alice   25     New York
1      Bob   30  Los Angeles
2  Charlie   35      Chicago

Converted to dict (by columns):
{'Name': ['Alice', 'Bob', 'Charlie'], 'Age': [25, 30, 35], 'City': ['New York', 'Los Angeles', 'Chicago']}

Converted to dict (by records):
[
	{'Name': 'Alice', 'Age': 25, 'City': 'New York'}, 
	{'Name': 'Bob', 'Age': 30, 'City': 'Los Angeles'}, 
	{'Name': 'Charlie', 'Age': 35, 'City': 'Chicago'}
]

Converted to dict (by index):
{
	0: {'Name': 'Alice', 'Age': 25, 'City': 'New York'}, 
	1: {'Name': 'Bob', 'Age': 30, 'City': 'Los Angeles'}, 
	2: {'Name': 'Charlie', 'Age': 35, 'City': 'Chicago'}
}
"""

在 Pandas 中,.T 是一个属性,用于转置 DataFrame 或 Series。当应用于 DataFrame 时,它会交换 DataFrame 的行和列。这意味着原来的列名会变成索引,而原来的索引会变成新的列名。

使用 .T 转置 DataFrame 的示例

假设我们有一个 DataFrame df 如下所示:

import pandas as pd

data = {
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Age': [25, 30, 35],
    'City': ['New York', 'Los Angeles', 'Chicago']
}

df = pd.DataFrame(data)

print("Original DataFrame:")
print(df)
print(df.to_dict())

transposed_df = df.T
print("\nTransposed DataFrame:")
print(transposed_df)
print(transposed_df.to_dict())

"""
Original DataFrame:
      Name  Age         City
0    Alice   25     New York
1      Bob   30  Los Angeles
2  Charlie   35      Chicago
{
	'Name': {0: 'Alice', 1: 'Bob', 2: 'Charlie'}, 
	'Age': {0: 25, 1: 30, 2: 35}, 
	'City': {0: 'New York', 1: 'Los Angeles', 2: 'Chicago'}
}

Transposed DataFrame:
             0            1        2
Name     Alice          Bob  Charlie
Age         25           30       35
City  New York  Los Angeles  Chicago
{
	0: {'Name': 'Alice', 'Age': 25, 'City': 'New York'}, 
	1: {'Name': 'Bob', 'Age': 30, 'City': 'Los Angeles'}, 
	2: {'Name': 'Charlie', 'Age': 35, 'City': 'Chicago'}
}
"""
Pandas的重点知识点主要包括以下几个方面: 1. Pandas与NumPy的关系:Pandas是基于NumPy实现的,它们互为补充。Pandas的核心数据结构与NumPy的ndarray相似,但Pandas在数据处理方面更强大和智能,而NumPy更基础和强大。 2. 数据分析中的Data Frame操作:Data Frame是Pandas中最常用的数据结构,类似于Excel中的表格。对Data Frame进行各种操作是进行数据分析的基础操作,比如数据筛选、排序、切片等。 3. 分组聚合:利用Pandas进行数据分析时,经常需要根据某些特征将数据分组,并对每个分组进行聚合计算,如求和、计数、均值等。这种分组聚合操作可以帮助我们快速统计和分析数据。 4. Series:Series是Pandas中的一维数据结构,类似于Excel中的列。它由一组数据和与之关联的索引组成,可以对数据进行标签化的访问和操作。 总结来说,Pandas的重点知识点包括Pandas与NumPy的关系、Data Frame的操作、分组聚合以及Series的使用。掌握这些知识点可以帮助你更好地进行数据分析和处理。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Pandas知识点超全总结](https://blog.csdn.net/Itsme_MrJJ/article/details/126101002)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值