Pandas 数据分析

视频来源B站:Python数据分析教程,零基础学会numpy+pandas+matplotlib数据分析,数据可视化

基本介绍

Pandas 是什么

Pandas 是 Python 数据分析工具链中最核心的库,充当数据读取、清洗、分析、统计、输出的高效工具。
Pandas 是一个开源的数据分析和数据处理库,它是基于 Python 编程语言的。
Pandas 提供了易于使用的数据结构和数据分析工具,特别适用于处理结构化数据,如表格型数据(类似于Excel表格)。
Pandas 是数据科学和分析领域中常用的工具之一,它使得用户能够轻松地从各种数据源中导入数据,并对数据进行高效的操作和分析。
Pandas是基于NumPy构建的专门为处理表格和混杂数据设计的Python库,其核心设计理念包括:

  • 标签化数据结构:提供带标签的轴(行索引和列名)
  • 灵活处理缺失数据:内置NaN处理机制
  • 智能数据对齐:自动按标签对齐数据
  • 强大IO工具:支持从CSV、Excel、SQL等20+数据源读写
  • 时间序列处理:原生支持日期时间处理和频率转换

名称来源

pandas这个名字源于panel data(面板数据,这是多维结构化数据集在计量经济学中的术语)以及Python data analysis(Python 数据分析)。
pandas兼具numpy高性能的数组计算功能以及电子表格和关系型数据库(如SQL)灵活的数据处理功能。它提供了复杂精细的索引功能,能更加便捷地完成重塑、切片和切块、聚合以及选取数据子集等操作。

功能

有标签轴的数据结构。在数据结构中,每个轴都被赋予了特定的标签,这些标签用于标识和引用轴上的数据元素,使得数据的组织、访问和操作更加直观和方便

应用

工具 功能特色 适用场景
Excel 图形界面,简单上手 人工分析、小规模数据
SQL 高效读写,最终数据源 数据库查询和联表
Python + Pandas 算法和分析部署核心 数据清洗,统计分析,可视化等
与excel对比
  • 优势:
    • 处理百万级数据不卡顿(Excel约100万行限制)
    • 可复用的分析流程(脚本 vs 手工操作)
    • 支持复杂数据转换(如:分组聚合、时间重采样)
  • 局限:
    • 可视化交互性较弱
    • 学习曲线较陡峭
与数据库对比
  • 优势:
    • 无需SQL知识即可分析
    • 适合探索性分析(即时反馈)
    • 丰富的数据清洗函数
  • 局限:
    • 数据量受内存限制
    • 不适合高并发访问

处理流程图

在这里插入图片描述

核心数据结构

Series

一维带有标签的数组
在这里插入图片描述

什么是 Series

类似于 NumPy 一维数组,但增加了 “标签”,可以理解为「一维标签化数组」。
Series 是 Pandas 中的一个核心数据结构,类似于一个一维的数组,具有数据和索引。
Series 可以存储任何数据类型(整数、浮点数、字符串等),并通过标签(索引)来访问元素。Series 的数据结构是非常有用的,因为它可以处理各种数据类型,同时保持了高效的数据操作能力,比如可以通过标签来快速访问和操作数据。
在这里插入图片描述
Series 特点:

  • 一维数组:Series 中的每个元素都有一个对应的索引值。
  • 索引: 每个数据元素都可以通过标签(索引)来访问,默认情况下索引是从 0 开始的整数,但你也可以自定义索引。
  • 数据类型: Series 可以容纳不同数据类型的元素,包括整数、浮点数、字符串、Python 对象等。
  • 大小不变性:Series 的大小在创建后是不变的,但可以通过某些操作(如 append 或 delete)来改变。
  • 操作:Series 支持各种操作,如数学运算、统计分析、字符串处理等。
  • 缺失数据:Series 可以包含缺失数据,Pandas 使用NaN(Not a Number)来表示缺失或无值。
  • 自动对齐:当对多个 Series 进行运算时,Pandas 会自动根据索引对齐数据,这使得数据处理更加高效。
    我们可以使用 Pandas 库来创建一个 Series 对象,并且可以为其指定索引(Index)、名称(Name)以及值(Values):
import numpy as np
# series 的创建
import pandas as pd
s = pd.Series([1,2,3,4,5])
print(s)

# 结果
0    1
1    2
2    3
3    4
4    5
dtype: int64
创建 Series

直接通过列表创建Series

import numpy as np
# series 的创建
import pandas as pd
s = pd.Series([1,2,3,4,5])
print(s)

# 结果
0    1
1    2
2    3
3    4
4    5
dtype: int64

Series的字符串表现形式为:索引在左边,值在右边。由于我们没有为数据指定索引,于是会自动创建一个 0 到 N-1(N为数据的长度)的整数型索引。

创建方式:

  1. 通过列表创建 Series 时指定索引
# 自定义索引
s = pd.Series([1,2,3,4,5], index=['a','b','c','d','e'])
print(s)

#结果
a    1
b    2
c    3
d    4
e    5
dtype: int64
  1. 通过列表创建 Series 时指定索引和名称
# 定义name
s = pd.Series([1,2,3,4,5], index=['a','b','c','d', 'e'], name='shuzi')
print(s)

# 结果
a    1
b    2
c    3
d    4
e    5
Name: shuzi, dtype: int64
  1. 通过字段方式创建
#通过字段方式创建
s = pd.Series({'a':1,'b':2,'c':3,'d':4,'e':5})
print(s)
print('--------------------')
s = pd.Series(s, index=['a','c'])
print(s)

#结果
a    1
b    2
c    3
d    4
e    5
dtype: int64
--------------------
a    1
c    3
dtype: int64
名称的作用,与变量名的区别

在 Pandas 的 Series 中,name 参数用于给整个 Series 对象赋予一个名称。这个名称有以下几个用途:

  1. 标识作用:name 可以作为 Series 的标识,类似于给数据列取一个名字。当你打印 Series 时,name 会显示在输出的最下方。
  2. DataFrame 列名:如果你将一个 Series 转换成 DataFrame 或与其他 DataFrame 合并,name 会自动成为列名。
  • 例如:
import pandas as pd
s = pd.Series([4, 7, -5, 3], index=["a", "b", "c", "d"],name="hello_python")

df = s.to_frame()  # 转换为 DataFrame,列名就是 "hello_python"
print(df)
#     hello_python
# a             4
# b             7
# c            -5
# d             3
  1. 对齐操作:在 Pandas 运算(如 concat、merge 等)时,name 可以帮助对齐数据。
  2. 导出数据:将 Series 导出为 CSV 或其他格式时,name 会成为列名。

name 的主要作用是 给 Series 一个标识,方便后续数据处理、合并或导出。如果只是单独使用 Series,name 可能看起来作用不大,但在更复杂的数据操作中(如 DataFrame 整合),它会很有用。

访问数据

以下是 Pandas 中访问 Series 数据的主要方法汇总表格:

方法分类 语法示例 描述 返回值 是否支持切片/布尔索引
位置索引 s.iloc[0] 通过整数位置访问(从0开始) 标量值
s.iloc[1:3] 位置切片(左闭右开) Series
标签索引 s.loc[‘a’] 通过索引标签访问 标量值
s.loc[[‘a’,‘b’]] 通过标签列表访问 Series
直接索引 s[0] 类似iloc(当索引非整数时可能混淆) 标量值/Series
s[‘a’] 类似loc(优先标签索引)
布尔索引 s[s > 3] 通过布尔条件筛选 Series
s[~(s > 3)] 取反条件
函数访问 s.at[‘a’] 快速访问单个标签(类似loc但效率更高) 标量值
s.iat[0] 快速访问单个位置(类似iloc但效率更高)
头部/尾部 s.head(3) 访问前N行(默认5) Series
s.tail(2) 访问后N行(默认5)
取唯一值 s.unique() 返回唯一值数组 ndarray
值计数 s.value_counts() 统计各值出现次数 Series
  1. 优先使用loc/iloc:直接索引[]的行为可能因索引类型不同而变化,明确场景时建议显式使用loc(标签)或iloc(位置)。
  2. 切片差异:
    • loc切片为闭区间(包含两端)
    • iloc切片为左闭右开(与Python列表一致)
  3. 布尔索引:常用于条件过滤,如s[s > 3 & s < 10]。
import pandas as pd

s = pd.Series([10, 20, 30, 40], index=['a', 'b', 'c', 'd'])
# 位置索引
print(s.iloc[0])  # 10
# 标签访问
print(s["a"])  
# 标签索引
print(s.loc['b'])  # 20
# 布尔索引
print(s[s > 25])  # c:30, d:40
# 花式索引
print(s[['a', 'c']])  # a:10, c:30

#使用布尔索引从Series中筛选满足某些条件的值
print("mean:" + str(s.mean())) # 25.0
bools = s > s.mean()  
# 将大于平均值的元素标记为 True
print(bools)
# a    False
# b    False
# c     True
# d     True
# dtype: bool
print(s[bools])# b    3.5
# c    6.8
# dtype: float64# 使用where过滤
print(s.where(s > 20, -1))  # 小于等于20的值替换为-1
常用属性
属性 说明
index Series的索引对象
values Series的值
dtype或dtypes Series的元素类型
shape Series的形状
ndim Series的维度
size Series的元素个数
name Series的名称
loc[] 显式索引,按标签索引或切片
iloc[] 隐式索引,按位置索引或切片
at[] 使用标签访问单个元素
iat[] 使用位置访问单个元素
# series 的属性
"""
index
values
shape
ndim
size
name
loc[] 支持切片
iloc[]
at[]  不支持切片
iat[]
"""
s = pd.Series({'a':1,'b':2,'c':3,'d':4,'e':5})
print(s)
print(s.index)
print(s.values)
print(s.shape)
print(s.ndim)
print(s.dtype)
print(s.size)
print('--------------------')
print(s.loc['a'])
print(s.iloc[1])
print('-----------------')
print(s.loc['a':'c'])
print(s.iloc[1:3])
print('-------------------')
print(s.at['a'])
print(s.iat[3])
运算
import pandas as pd

s1 = pd.Series([1, 2, 3, 4])
s2 = pd.Series([10, 20, 30, 40])
# 基本运算
print(s1 + s2)  # 对应位置相加
print(s1 * 2)   # 标量乘法
常用方法与统计
用途分类 方法 说明 示例代码
数据预览 head() 查看前 n 行数据,默认 5 行 s.head(3)
数据预览 tail() 查看后 n 行数据,默认 5 行 s.tail(2)
条件判断 isin() 判断元素是否包含在参数集合中 s.isin([1, 2])
缺失值处理 isna() 判断是否为缺失值(如 NaN 或 None) s.isna()
聚合统计 sum() 求和,自动忽略缺失值 s.sum()
聚合统计 mean() 平均值 s.mean()
聚合统计 min() 最小值 s.min()
聚合统计 max() 最大值 s.max()
聚合统计 var() 方差 s.var()
聚合统计 std() 标准差 s.std()
聚合统计 median() 中位数 s.median()
聚合统计 mode() 众数(可返回多个) s.mode()
聚合统计 quantile(q) 分位数,q 取 0~1 之间 s.quantile(0.25)
聚合统计 describe() 常见统计信息(count、mean、std、min、25%、50%、75%、max) s.describe()
频率统计 value_counts() 每个唯一值的出现次数 s.value_counts()
频率统计 count() 非缺失值数量 s.count()
频率统计 nunique() 唯一值个数(去重) s.nunique()
唯一处理 unique() 获取去重后的值数组 s.unique()
唯一处理 drop_duplicates() 去除重复项 s.drop_duplicates()
抽样分析 sample() 随机抽样 s.sample(2)
排序操作 sort_index() 按索引排序 s.sort_index()
排序操作 sort_values() 按值排序 s.sort_values()
替换值 replace() 替换值 s.replace({1: 100})
转换结构 to_frame() 将 Series 转为 DataFrame s.to_frame()
比较判断 equals() 判断两个 Series 是否完全相等 s1.equals(s2)
信息提取 keys() 返回 Series 的索引对象 s.keys()
统计关系 corr() 计算相关系数(默认皮尔逊) s1.corr(s2)
统计关系 cov() 协方差 s1.cov(s2)
可视化 hist() 绘制直方图(需安装 matplotlib) s.hist()
遍历操作 items() 返回索引和值的迭代器 for i, v in s.items(): print(i, v)
import pandas as pd
import numpy as np
arrs = pd.Series([11,22,np.nan,None,44,22],index=['a','b','c','d','e','f'])
# head()    查看前n行数据,默认5行
print(arrs.head())
# tail()    查看后n行数据,默认5行
print(arrs.tail(3))
# describe()    常见统计信息
print(arrs.describe())
# count()   非缺失值元素的个数
print(arrs.count())
# keys()    返回Series的索引对象
print(arrs.index)
print(arrs.keys())
# isin()    判断数组中的每一个元素是否包含在参数集合中
print(arrs.isin([11]))
# isna()    元素是否为缺失值
print(arrs.isna())

#统计# sum() 求和,会忽略 Series 中的缺失值
print(arrs.sum())
# mean()    平均值
print(arrs.mean())
# min() 最小值
print(arrs.min())
# max() 最大值
print(arrs.max())
# var() 方差 每个元素与平均值的差 的平方 的和
print(arrs.var())
# std() 标准差 方差的平方根
print(arrs.std())
# print(arrs.var())
# median()  中位数
# 若数据集的元素个数为奇数,中位数就是排序后位于中间位置的数值。
# 若数据集的元素个数为偶数,中位数则是排序后中间两个数的平均值。
# 去除缺失值之后,arrs 就变成了 [11, 22, 44, 22]。
# 对 [11, 22, 44, 22] 进行排序,得到 [11, 22, 22, 44]
print(arrs.median())
# mode()    众数
print(arrs.mode())
# quantile()    指定位置的分位数,如quantile(0.5)
# 分位数:分位数是把一组数据按照从小到大的顺序排列后,分割成若干等份的数值点。
# 0.25 分位数就是将数据从小到大排序后,位于 25% 位置处的数值。
# 插值方法:当计算分位数时,若位置不是整数,就需要借助插值方法来确定分位数值。# "midpoint" 插值方法是指当分位数位置处于两个数据点之间时,取这两个数据点的
# 平均值作为分位数值。
# 对于有 n个数据点的有序数据集,q分位数的位置 i可以通过公式 i=(n−1)q来计
# 算。这里 n=4,q=0.25,则 i=(4−1)×0.25=0.75。这意味着 0.25 分位数处于第一个# 数据点(值为 11)和第二个数据点(值为 22)之间。使用 "midpoint" 插值方法,
# 分位数值就是这两个数据点的平均值,即 (11+22)÷2=16.5
print(arrs.quantile(0.25, interpolation="midpoint"))

print(len(arrs))
# drop_duplicates() 去重  这里可以看出,底层None也作为NaN处理
print(arrs.drop_duplicates())
# unique()  去重后的数组
print(arrs.unique())
# nunique() 去重后非缺失值元素元素个数
print(arrs.nunique())
# sample()  随机采样
print(arrs.sample())
# value_counts()    每个元素的个数
print(arrs.value_counts())
# sort_index()  按索引排序
print(arrs.sort_index())
# sort_values() 按值排序
print(arrs.sort_values())
# replace() 用指定值代替原有值
print(arrs.replace(22,"haha"))
# to_frame()    将Series转换为DataFrame
print(arrs.to_frame())
# equals()  判断两个Series是否相同
arr1 = pd.Series([1,2,3])
arr2 = pd.Series([1,2,3])
print(arr1.equals(arr2))
# corr()    计算与另一个Series的相关系数
# arr1.corr(arr2):由于 arr1 和 arr2 的值完全相同,它们之间是完全正相关的,
#因此相关系数为 1。
# arr1.corr(arr3):arr1 的值是递增的,而 arr3 的值是递减的,它们之间是完全
# 负相关的,所以相关系数为 -1。
# arr1.corr(arr4):arr1 和 arr4 的值都是递增的,且变化趋势一致,它们之间是
# 完全正相关的,相关系数为 1。
# arr5.corr(arr6):arr5 和 arr6 的值之间没有明显的线性关系,它们的相关系数
# 为 0。
arr3 = pd.Series([3,2,1])
arr4 = pd.Series([6,7,8])
arr5 = pd.Series([1, -1, 1, -1])
arr6 = pd.Series([1, 1, -1, -1])
print(arr1.corr(arr2))
print(arr1.corr(arr3))
print(arr1.corr(arr4))
print(arr5.corr(arr6))
# cov() 计算与另一个Series的协方差
# 协方差用于衡量两个变量的总体误差,其值的正负表示两个变量的变化方向关系:
# 正值表示同向变化,负值表示反向变化。
print(arr1.cov(arr3))
DataFrame

二维表格结构,可看作多个 Series 的组合
在这里插入图片描述

创建

DataFrame 是 Pandas 中的核心数据结构之一,多行多列表格数据,类似于 Excel 表格 或 SQL 查询结果。
它是一个 二维表格结构,具有行索引(index)和列标签(columns)。

df = pd.DataFrame({
    "name": ["Alice", "Bob"],
    "score": [90, 80]
})

在这里插入图片描述
DataFrame中的数据是以一个或多个二维块存放的(而不是列表、字典或别的一维数据结构)。它可以被看做由Series组成的字典(共同用一个索引)。提供了各种功能来进行数据访问、筛选、分割、合并、重塑、聚合以及转换等操作,广泛用于数据分析、清洗、转换、可视化等任务。

  1. 通过series来创建
# dataframe学习
import pandas as pd
import numpy as np

#通过Series创建
s1 = pd.Series([1,2,3,4,5])
s2 = pd.Series([6,7,8,9,10])
df = pd.DataFrame({"第一列": s1, "第二列": s2})
df
type(df)
type(df["第一列"])
  1. 直接通过字典创建DataFrame:
#通过字典创建
df = pd.DataFrame({
    "name": ["A","B","C","D","E"],
    "age": [12,23,34,45,56]
}, index=[1,2,3,4,5], columns=["age","name"])
df
  1. 通过字典创建时指定列的顺序和行索引
df = pd.DataFrame(
    data={"age": [20, 30, 40], 
    "name": ["张三", "李四", "王五"]}, 
    columns=["name", "age"], index=[101, 102, 103]
)
print(df)
#     name  age
# 101   张三   20
# 102   李四   30
# 103   王五   40
访问方式
方法分类 语法示例 描述 返回值类型 是否支持切片/条件索引
列选择 df[‘col’] 选择单列(返回Series) Series
df[[‘col1’, ‘col2’]] 选择多列(返回DataFrame) DataFrame
行选择 df.loc[row_label] 通过行标签选择单行(返回Series) Series ✅(标签切片)
df.loc[start:end] 通过标签切片选择多行(闭区间) DataFrame
df.iloc[row_index] 通过行位置选择单行(从0开始) Series ✅(位置切片)
df.iloc[start:end] 通过位置切片选择多行(左闭右开) DataFrame
行列组合选择 df.loc[row_labels, col_labels] 通过标签选择行和列(如df.loc[‘a’:‘b’, [‘col1’,‘col2’]]) Series/DataFrame
df.iloc[row_idx, col_idx] 通过位置选择行和列(如df.iloc[0:2, [1,3]]) Series/DataFrame
条件筛选 df[df[‘col’] > 3] 通过布尔条件筛选行 DataFrame
df.query(“col1 > 3 & col2 < 10”) 使用表达式筛选(需字符串表达式) DataFrame
快速访问 df.at[row_label, ‘col’] 快速访问单个值(标签索引,高效) 标量值
df.iat[row_idx, col_idx] 快速访问单个值(位置索引,高效) 标量值
头部/尾部 df.head(n) 返回前n行(默认5) DataFrame
df.tail(n) 返回后n行(默认5) DataFrame
样本抽样 df.sample(n=3) 随机抽取n行 DataFrame
索引重置 df.reset_index() 重置索引(原索引变为列) DataFrame
设置索引 df.set_index(‘col’) 指定某列作为新索引 DataFrame
  1. loc vs iloc
    • loc:基于标签(index/column names),切片为闭区间(如df.loc[‘a’:‘c’]包含’c’)。
    • iloc:基于整数位置(从0开始),切片为左闭右开(如df.iloc[0:2]不包含索引2)。
  2. 布尔条件筛选
    • 支持组合条件(需用&、|,并用括号分隔条件):
df[(df['col1'] > 3) & (df['col2'] == 'A')]
  1. at/iat vs loc/iloc
    • at/iat:仅用于访问单个值,速度更快。
    • loc/iloc:支持多行/列选择,功能更灵活

代码演示:

  1. 获取一列数据
# 访问数据
print(df['name'])  #访问某列数据
print(df.score)
 # df["col"] / df.col
df["name"]       # 返回 Series
df.name      
df[["name"]]     # 返回 DataFrame
  1. 获取多列数据
df[["date", "temp_max", "temp_min"]]  # 获取多列数据print(df[['name','score']]) # 访问多列数据
  1. 获取行数据
  • loc:通过行标签获取数据
df.loc[1]  # 获取行标签为1的数据
df.loc[[1, 10, 100]]  # 获取行标签分别为1、10、100的数据
  • iloc:通过行位置获取数据
df.iloc[0]  # 获取行位置为0的数据
df.iloc[-1]  # 获取行位置为最后一位的数据
  1. 获取指定单元格
df.loc[101, "name"]    # 标签访问
df.iloc[0, 1]          # 位置访问df.loc[1, "precipitation"]  # 获取行标签为1,列标签为precipitation的数据
df.loc[:, "precipitation"]  # 获取所有行,列标签为precipitation的数据
df.iloc[:, [3, 5, -1]]  # 获取所有行,列位置为3,5,最后一位的数据
df.iloc[:10, 2:6]  # 获取前10行,列位置为2、3、4、5的数据
df.loc[:10, ["date", "precipitation", "temp_max", "temp_min"]]  # 通过行列标签获取数据
  1. 查看部分数据
print(df.head())print(df.tail(10))
  1. 使用布尔索引筛选数据
# 条件筛选
df['score']>70
print(df[df.score>70])
print(df[(df['score']>70) & (df['age']<20)])# 随机抽样
df.sample(2)
常用属性
属性 说明
index DataFrame的行索引
columns DataFrame的列标签
values DataFrame的值
ndim DataFrame的维度
shape DataFrame的形状
size DataFrame的元素个数
dtypes DataFrame的元素类型
T 行列转置
loc[] 显式索引,按行列标签索引或切片
iloc[] 隐式索引,按行列位置索引或切片
at[] 使用行列标签访问单个元素
iat[] 使用行列位置访问单个元素

代码演示:

import pandas as pd
df = pd.DataFrame(data={"id": [101, 102, 103], "name": ["张三", "李四", "王五"], "age": [20, 30, 40]},index=["aa", "bb", "cc"])# index DataFrame的行索引
print(df.index)
# columns   DataFrame的列标签
print(df.columns
     )# values    DataFrame的值
print(df.values)
# ndim  DataFrame的维度
print(df.ndim)
# shape DataFrame的形状
print(df.shape)
# size  DataFrame的元素个数
print(df.size)
# dtypes    DataFrame的元素类型
print(df.dtypes)
# T 行列转置
print(df.T)
# loc[] 显式索引,按行列标签索引或切片 逗号前是行切片规则,后是列切片规则
print(df.loc["aa":"cc"])
print(df.loc[:,["id","name"]])
# iloc[]    隐式索引,按行列位置索引或切片
print(df.iloc[0:1])
print(df.iloc[0:3,2])
print("----------")
# at[]  使用行列标签访问单个元素
print(df.at["aa","name"])
# iat[] 使用行列位置访问单个元素
print(df.iat[0,1])
常用方法与统计
方法 说明
head() 查看前n行数据,默认5行
tail() 查看后n行数据,默认5行
isin() 元素是否包含在参数集合中
isna() 元素是否为缺失值
sum() 求和
mean() 平均值
min() 最小值
max() 最大值
var() 方差
std() 标准差
median() 中位数
mode() 众数
quantile() 指定位置的分位数,如quantile(0.5)
describe() 常见统计信息
info() 基本信息
value_counts() 每个元素的个数
count() 非空元素的个数
drop_duplicates() 去重
sample() 随机采样
replace() 用指定值代替原有值
equals() 判断两个DataFrame是否相同
cummax() 累计最大值
cummin() 累计最小值
cumsum() 累计和
cumprod() 累计积
diff() 一阶差分,对序列中的元素进行差分运算,也就是用当前元素减去前一个元素得到差值,默认情况下,它会计算一阶差分,即相邻元素之间的差值。参数:periods:整数,默认为 1。表示要向前或向后移动的周期数,用于计算差值。正数表示向前移动,负数表示向后移动。axis:指定计算的轴方向。0 或 ‘index’ 表示按列计算,1 或 ‘columns’ 表示按行计算,默认值为 0。
sort_index() 按行索引排序
sort_values() 按某列的值排序,可传入列表来按多列排序,并通过ascending参数设置升序或降序
nlargest() 返回某列最大的n条数据
nsmallest() 返回某列最小的n条数据
import pandas as pd
from typing import Any, Optional

def create_dataframe() -> pd.DataFrame:
    """
    创建一个包含 id、name 和 age 列的 DataFrame。
    
    Returns:
        pd.DataFrame: 包含示例数据的 DataFrame。
    """
    data = {
        "id": [101, 102, 103, 104, 105, 106, 101],
        "name": ["张三", "李四", "王五", "赵六", "冯七", "周八", "张三"],
        "age": [10, 20, 30, 40, None, 60, 10]
    }
    index = ["aa", "bb", "cc", "dd", "ee", "ff", "aa"]
    return pd.DataFrame(data, index=index)

def print_statistics(df: pd.DataFrame) -> None:
    """
    打印 DataFrame 的基本统计信息。
    
    Args:
        df (pd.DataFrame): 输入的 DataFrame。
    """
    print("=== 前几行数据 ===")
    print(df.head())
    
    print("\n=== 后几行数据 ===")
    print(df.tail())
    
    print("\n=== 检查元素是否存在于指定集合中 ===")
    print(df.isin([103, 106]))
    
    print("\n=== 检查缺失值 ===")
    print(df.isna())
    
    print("\n=== 年龄列的总和 ===")
    print(df["age"].sum())
    
    print("\n=== 年龄列的平均值 ===")
    print(df["age"].mean())
    
    print("\n=== 年龄列的最小值 ===")
    print(df["age"].min())
    
    print("\n=== 年龄列的最大值 ===")
    print(df["age"].max())
    
    print("\n=== 年龄列的方差 ===")
    print(df["age"].var())
    
    print("\n=== 年龄列的标准差 ===")
    print(df["age"].std())
    
    print("\n=== 年龄列的中位数 ===")
    print(df["age"].median())
    
    print("\n=== 年龄列的众数 ===")
    print(df["age"].mode())
    
    print("\n=== 年龄列的中位数(分位数 0.5) ===")
    print(df["age"].quantile(0.5))
    
    print("\n=== 数据的基本统计信息 ===")
    print(df.describe())
    
    print("\n=== 数据基本信息 ===")
    print(df.info())
    
    print("\n=== 每个元素的出现次数 ===")
    print(df.value_counts())
    
    print("\n=== 非空元素的个数 ===")
    print(df.count())
    
    print("\n=== 是否有重复行(按 age 列)===\n")
    print(df.duplicated(subset="age"))
    
    print("\n=== 随机采样一行 ===")
    print(df.sample())
    
    print("\n=== 替换特定值 ===")
    print(df.replace(20, "haha"))
    
    print("\n=== 累计最大值(按行)===\n")
    df3 = pd.DataFrame({'A': [2, 5, 3, 7, 4], 'B': [1, 6, 2, 8, 3]})
    print(df3.cummax(axis="columns"))
    
    print("\n=== 累计最小值 ===")
    print(df3.cummin())
    
    print("\n=== 累计和 ===")
    print(df3.cumsum())
    
    print("\n=== 累计积 ===")
    print(df3.cumprod())
    
    print("\n=== 一阶差分 ===")
    print(df3.diff())
    
    print("\n=== 按行索引排序 ===")
    print(df.sort_index())
    
    print("\n=== 按年龄列排序 ===")
    print(df.sort_values(by="age"))
    
    print("\n=== 年龄最大的两行 ===")
    print(df.nlargest(n=2, columns="age"))
    
    print("\n=== 年龄最小的一行 ===")
    print(df.nsmallest(n=1, columns="age"))

if __name__ == "__main__":
    dataframe = create_dataframe()
    print_statistics(dataframe)

在Pandas的 DataFrame 方法里,axis 是一个非常重要的参数,它用于指定操作的方向。
axis 参数可以取两个主要的值,即 0 或 ‘index’,以及 1 或 ‘columns’ ,其含义如下:

  • axis=0 或 axis=‘index’:表示操作沿着行的方向进行,也就是对每一列的数据进行处理。例如,当计算每列的均值时,就是对每列中的所有行数据进行计算。
  • axis=1 或 axis=‘columns’:表示操作沿着列的方向进行,也就是对每行的数据进行处理。例如,当计算每行的总和时,就是对每行中的所有列数据进行计算。
标量运算

标量与每个元素进行计算。

import pandas as pd

df = pd.DataFrame(data={"age": [20, 30, 40, 10], "name": ["张三", "李四", "王五", "赵六"]},
    columns=["name", "age"],
    index=[101, 104, 103, 102],
)
print(df * 2)
#      name     age
# 101  张三张三   40
# 104  李四李四   60
# 103  王五王五   80
# 102  赵六赵六   20
df1 = pd.DataFrame(
    data={"age": [10, 20, 30, 40], "name": ["张三", "李四", "王五", "赵六"]},
    columns=["name", "age"],
    index=[101, 102, 103, 104],
)
df2 = pd.DataFrame(
    data={"age": [10, 20, 30, 40], "name": ["张三", "李四", "王五", "田七"]},
    columns=["name", "age"],
    index=[102, 103, 104, 105],
)
print(df1 + df2)#      name   age
# 101   NaN   NaN
# 102  李四张三  30.0
# 103  王五李四  50.0
# 104  赵六王五  70.0
# 105   NaN   NaN
数据的导入与导出
导出数据
方法 说明
to_csv() 将数据保存为csv格式文件,数据之间以逗号分隔,可通过sep参数设置使用其他分隔符,可通过index参数设置是否保存行标签,可通过header参数设置是否保存列标签。
to_pickle() 如要保存的对象是计算的中间结果,或者保存的对象以后会在Python中复用,可把对象保存为.pickle文件。如果保存成pickle文件,只能在python中使用。文件的扩展名可以是.p、.pkl、.pickle。
to_excel() 保存为Excel文件,需安装openpyxl包。
to_clipboard() 保存到剪切板。
to_dict() 保存为字典。
to_hdf() 保存为HDF格式,需安装tables包。
to_html() 保存为HTML格式,需安装lxml、html5lib、beautifulsoup4包。
to_json() 保存为JSON格式。
to_feather() feather是一种文件格式,用于存储二进制对象。feather对象也可以加载到R语言中使用。feather格式的主要优点是在Python和R语言之间的读写速度要比csv文件快。feather数据格式通常只用中间数据格式,用于Python和R之间传递数据,一般不用做保存最终数据。需安装pyarrow包。
to_sql() 保存到数据库。
import os
import pandas as pd
os.makedirs("data", exist_ok=True)
df = pd.DataFrame({"age": [20, 30, 40, 10], "name": ["张三", "李四", "王五", "赵六"], "id": [101, 102, 103, 104]})
df.set_index("id", inplace=True)
df.to_csv("data/df.csv")
df.to_csv("data/df.tsv", sep="\t")  # 设置分隔符为 \t
df.to_csv("data/df_noindex.csv", index=False)  # index=False 不保存行索引
df.to_pickle("data/df.pkl")
df.to_excel("data/df.xlsx")
df.to_clipboard()
df_dict = df.to_dict()
df.to_hdf("data/df.h5", key="df")
df.to_html("data/df.html")
df.to_json("data/df.json")
df.to_feather("data/df.feather")
导入数据
方法 说明
read_csv() 加载csv格式的数据。可通过sep参数指定分隔符,可通过index_col参数指定行索引。
read_pickle() 加载pickle格式的数据。
read_excel() 加载Excel格式的数据。
read_clipboard() 加载剪切板中的数据。
read_hdf() 加载HDF格式的数据。
read_html() 加载HTML格式的数据。
read_json() 加载JSON格式的数据。
read_feather() 加载feather格式的数据。
read_sql() 加载数据库中的数据。
import os
import pandas as pd
df_csv = pd.read_csv("data/df.csv", index_col="id")  # 指定行索引
df_tsv = pd.read_csv("data/df.tsv", sep="\t")  # 指定分隔符
df_pkl = pd.read_pickle("data/df.pkl")
df_excel = pd.read_excel("data/df.xlsx", index_col="id")
df_clipboard = pd.read_clipboard(index_col="id")
df_from_dict = pd.DataFrame(df_dict)
df_hdf = pd.read_hdf("data/df.h5", key="df")
df_html = pd.read_html("data/df.html", index_col=0)[0]
df_json = pd.read_json("data/df.json")
df_feather = pd.read_feather("data/df.feather")
print(df_csv)
print(df_tsv)
print(df_pkl)
print(df_excel)
print(df_clipboard)
print(df_from_dict)
print(df_hdf)
print(df_html)
print(df_json)
print(df_feather)
数据清洗与预处理
缺失值处理
方法/操作 语法示例 描述
检测缺失值 df.isna() 或 df.isnull() 返回布尔矩阵,标记缺失值(NaN或None)
统计缺失值 df.isna().sum() 每列缺失值数量统计
删除缺失值 df.dropna() 删除包含缺失值的行(默认)
df.dropna(axis=1) 删除包含缺失值的列
df.dropna(subset=[‘col1’]) 仅删除指定列的缺失值行
填充缺失值 df.fillna(value) 用固定值填充(如df.fillna(0)
df.fillna(method=‘ffill’) 用前一个非缺失值填充(向前填充)
df.fillna(method=‘bfill’) 用后一个非缺失值填充(向后填充)
df.fillna(df.mean()) 用列均值填充

pandas使用浮点值NaN(Not a Number)表示缺失数据,使用 NA(Not Available)表示缺失值。可以通过isnull()、isna()或notnull()、notna()方法判断某个值是否为缺失值。
Nan 通常表示一个无效的或未定义的数字值,是浮点数的一种特殊取值,用于表示那些不能表示为正常数字的情况,如 0/0、∞-∞ 等数学运算的结果。nan 与任何值(包括它自身)进行比较的结果都为False。例如在 Python 中,nan == nan返回 False。
NA 一般用于表示数据不可用或缺失的情况,它的含义更侧重于数据在某种上下文中是缺失或不存在的,不一定特指数字类型的缺失。
na 和 nan 都用于表示缺失值,但 nan 更强调是数值计算中的特殊值,而na更强调数据的可用性或存在性。

s = pd.Series([np.nan, None, pd.NA])
print(s)
# 0     NaN
# 1    None
# 2    <NA>
# dtype: object
print(s.isnull())
# 0    True
# 1    True
# 2    True
# dtype: bool

加载数据中包含缺失值。

df = pd.read_csv("data/weather_withna.csv")print(df.tail(5))
#             date  precipitation  temp_max  temp_min  wind weather
# 1456  2015-12-27            NaN       NaN       NaN   NaN     NaN
# 1457  2015-12-28            NaN       NaN       NaN   NaN     NaN
# 1458  2015-12-29            NaN       NaN       NaN   NaN     NaN
# 1459  2015-12-30            NaN       NaN       NaN   NaN     NaN
# 1460  2015-12-31           20.6      12.2       5.0   3.8    rain

可以通过keep_default_na参数设置是否将空白值设置为缺失值。

df = pd.read_csv("data/weather_withna.csv", keep_default_na=False)print(df.tail(5))
#             date precipitation temp_max temp_min wind weather
# 1456  2015-12-27
# 1457  2015-12-28
# 1458  2015-12-29
# 1459  2015-12-30
# 1460  2015-12-31          20.6     12.2      5.0  3.8    rain

可通过na_values参数将指定值设置为缺失值。

df = pd.read_csv("data/weather_withna.csv", na_values=["2015-12-31"])print(df.tail(5))
#             date  precipitation  temp_max  temp_min  wind weather
# 1456  2015-12-27            NaN       NaN       NaN   NaN     NaN
# 1457  2015-12-28            NaN       NaN       NaN   NaN     NaN
# 1458  2015-12-29            NaN       NaN       NaN   NaN     NaN
# 1459  2015-12-30            NaN       NaN       NaN   NaN     NaN
# 1460         NaN           20.6      12.2       5.0   3.8    rain

查看缺失值:通过isnull()查看缺失值数量

df = pd.read_csv("data/weather_withna.csv")
print(df.isnull().sum())
# date               0
# precipitation    303
# temp_max         303
# temp_min         303
# wind             303
# weather          303
# dtype: int64

剔除缺失值:通过dropna()方法来剔除缺失值。

  1. Series 剔除缺失值:
s = pd.Series([1, pd.NA, None])
print(s)
# 0       1
# 1    <NA>
# 2    None
# dtype: object
print(s.dropna())
# 0    1
# dtype: object
  1. DataFrame 剔除缺失值:
df = pd.DataFrame([[1, pd.NA, 2], [2, 3, 5], [pd.NA, 4, 6]])
print(df)
#       0     1  2
# 0     1  <NA>  2
# 1     2     3  5
# 2  <NA>     4  6
print(df.dropna())
#    0  1  2
# 1  2  3  5

无法从DataFrame中单独剔除一个值,只能剔除缺失值所在的整行或整列。默认情况下,dropna()会剔除任何包含缺失值的整行数据。
可以设置按不同的坐标轴剔除缺失值,比如axis=1(或 axis=‘columns’)会剔除任何包含缺失值的整列数据

df = pd.DataFrame([[1, pd.NA, 2], [2, 3, 5], [pd.NA, 4, 6]])
print(df)
#       0     1  2
# 0     1  <NA>  2
# 1     2     3  5
# 2  <NA>     4  6
print(df.dropna(axis=1))
#    2
# 0  2
# 1  5
# 2  6

有时只需要剔除全部是缺失值的行或列,或者绝大多数是缺失值的行或列。这些需求可以通过设置how或thresh参数来满足,它们可以设置剔除行或列缺失值的数量阈值

df = pd.DataFrame([[1, pd.NA, 2], [pd.NA, pd.NA, 5], [pd.NA, pd.NA, pd.NA]])
print(df)
#       0     1     2
# 0     1  <NA>     2
# 1  <NA>  <NA>     5
# 2  <NA>  <NA>  <NA>
print(df.dropna(how="all"))  # 如果所有值都是缺失值,则删除这一行
#       0     1  2
# 0     1  <NA>  2
# 1  <NA>  <NA>  5
print(df.dropna(thresh=2))  # 如果至少有2个值不是缺失值,则保留这一行
#    0     1  2
# 0  1  <NA>  2

可以通过设置subset参数来设置某一列有缺失值则进行剔除。

df = pd.DataFrame([[1, pd.NA, 2], [pd.NA, pd.NA, 5], [pd.NA, pd.NA, pd.NA]])
print(df)
#       0     1     2
# 0     1  <NA>     2
# 1  <NA>  <NA>     5
# 2  <NA>  <NA>  <NA>
print(df.dropna(subset=[0]))  # 如果0列有缺失值,则删除这一行
#    0     1  2
# 0  1  <NA>  2
填充缺失值
  1. 使用固定值填充:通过fillna()方法,传入值或字典进行填充
df = pd.read_csv("data/weather_withna.csv")
print(df.fillna(0).tail())  # 使用固定值填充
#   
print(df.fillna({"temp_max": 60, "temp_min": -60}).tail())  # 使用字典来填充
#             date  precipitation  temp_max  temp_min  wind weather
# 1456  2015-12-27            NaN      60.0     -60.0   NaN     NaN
# 1457  2015-12-28            NaN      60.0     -60.0   NaN     NaN
# 1458  2015-12-29            NaN      60.0     -60.0   NaN     NaN
# 1459  2015-12-30            NaN      60.0     -60.0   NaN     NaN
# 1460  2015-12-31           20.6      12.2       5.0   3.8    rain
  1. 使用统计值填充:通过fillna()方法,传入统计后的值进行填充
print(df.fillna(df[["precipitation", "temp_max", "temp_min", "wind"]].mean()).tail())  # 使用平均值填充
#             date  precipitation   temp_max  temp_min      wind weather
# 1456  2015-12-27       3.052332  15.851468  7.877202  3.242055     NaN
# 1457  2015-12-28       3.052332  15.851468  7.877202  3.242055     NaN
# 1458  2015-12-29       3.052332  15.851468  7.877202  3.242055     NaN
# 1459  2015-12-30       3.052332  15.851468  7.877202  3.242055     NaN
# 1460  2015-12-31      20.600000  12.200000  5.000000  3.800000    rain
  1. 使用前后的有效值填充:通过ffill()或bfill()方法使用前面或后面的有效值填充
print(df.ffill().tail())  # 使用前面的有效值填充
#             date  precipitation  temp_max  temp_min  wind weather
# 1456  2015-12-27            0.0      11.1       4.4   4.8     sun
# 1457  2015-12-28            0.0      11.1       4.4   4.8     sun
# 1458  2015-12-29            0.0      11.1       4.4   4.8     sun
# 1459  2015-12-30            0.0      11.1       4.4   4.8     sun
# 1460  2015-12-31           20.6      12.2       5.0   3.8    rain
print(df.bfill().tail())  # 使用后面的有效值填充
#             date  precipitation  temp_max  temp_min  wind weather
# 1456  2015-12-27           20.6      12.2       5.0   3.8    rain
# 1457  2015-12-28           20.6      12.2       5.0   3.8    rain
# 1458  2015-12-29           20.6      12.2       5.0   3.8    rain
# 1459  2015-12-30           20.6      12.2       5.0   3.8    rain
# 1460  2015-12-31           20.6      12.2       5.0   3.8    rain
  1. 通过线性插值填充:通过interpolate()方法进行线性插值填充。线性插值操作,就是用于在已知数据点之间估算未知数据点的值。interpolate 方法支持多种插值方法,可通过 method 参数指定,常见的方法有:
import pandas as pd
import numpy as np
# 创建包含缺失值的 Series
s = pd.Series([1, np.nan, 3, 4, np.nan, 6])
# 使用默认的线性插值方法填充缺失值
s_interpolated = s.interpolate()
print(s_interpolated)
# 0    1.0
# 1    2.0
# 2    3.0
# 3    4.0
# 4    5.0
# 5    6.0
# dtype: float64
  • ‘linear’:线性插值,基于两点之间的直线来估算缺失值,适用于数据呈线性变化的情况。
  • ‘time’:适用于时间序列数据,会考虑时间间隔进行插值。
  • ‘polynomial’:多项式插值,通过拟合多项式曲线来估算缺失值,可通过 order 参数指定多项式的阶数
# 缺失值
import numpy as np
import pandas as pd
# 缺失值的类型 nan na
s = pd.Series([np.nan, None, pd.NA,2,4])
df = pd.DataFrame([[1, pd.NA, 2], [2, 3, 5], [pd.NA, 4, 6]])
print(s)
print(s.isnull())  #查看是否是缺失值
print(s.isna()) #查看是否是缺失值
print(s.isna().sum()) # 缺失值的个数
# 剔除缺失值
print(s.dropna())  #series剔除缺失值
print(df.dropna()) #只要有缺失值,就剔除一整条记录
print(df.dropna(how="all")) # 如果所有值都是缺失值,则删除这一行
print(df.dropna(thresh=2)) # 如果至少有2个值不是缺失值,则保留这一行
print(df.dropna(axis=1))  #剔除一列中含缺失值的列
#可以通过设置subset参数来设置某一列有缺失值则进行剔除。
print(df.dropna(subset=[0]))# 如果0列有缺失值,则删除这一行
#填充缺失值
print('********')
df = pd.read_csv("data/weather_withna.csv")
# df = df.fillna({"temp_max": 60, "temp_min": -60}) # 使用字典来填充
print(df['temp_max'].mean())
df.fillna(df[["precipitation", "temp_max", "temp_min", "wind"]].mean()).tail() # 使用平均值填充
print(df.ffill().tail()) # 使用前面的有效值填充
print(df.bfill().tail()) # 使用后面的有效值填充

df1 = pd.read_csv("data/weather_withna.csv")
df2 = pd.read_csv("data/weather_withna.csv", keep_default_na=False)
print(df1.temp_max.count())
print(df1.isnull().sum())
print(df2.temp_max.count())
print(df2.isnull().sum())
重复数据处理
方法/操作 语法示例 描述
检测重复行 df.duplicated() 返回布尔序列标记重复行(首次出现的行标记为False)
删除重复行 df.drop_duplicates() 保留首次出现的行(默认检查所有列)
df.drop_duplicates(subset=[‘col1’]) 仅根据指定列去重
df.drop_duplicates(keep=‘last’) 保留最后一次出现的行
检测重复行
import pandas as pd

# 创建包含重复数据的DataFrame
data = {
    'Name': ['Alice', 'Bob', 'Alice', 'Charlie', 'Bob'],
    'Age': [25, 30, 25, 35, 30],
    'City': ['NY', 'LA', 'NY', 'SF', 'LA']
}
df = pd.DataFrame(data)

# 检测重复行(默认检查所有列)
print("重复行标记(False表示首次出现,True表示重复):")
print(df.duplicated())
# 0    False
# 1    False
# 2     True
# 3    False
# 4     True
# dtype: bool
删除重复行
import pandas as pd

# 创建包含重复数据的DataFrame
data = {
    'Name': ['Alice', 'Bob', 'Alice', 'Charlie', 'Bob'],
    'Age': [25, 30, 25, 35, 30],
    'City': ['NY', 'LA', 'NY', 'SF', 'LA']
}
df = pd.DataFrame(data)
# 默认保留首次出现的行
df_unique = df.drop_duplicates()
print("去重后的DataFrame:")
print(df_unique)
按指定列去重
import pandas as pd

# 创建包含重复数据的DataFrame
data = {
    'Name': ['Alice', 'Bob', 'Alice', 'Charlie', 'Bob'],
    'Age': [25, 30, 25, 35, 30],
    'City': ['NY', 'LA', 'NY', 'SF', 'LA']
}
df = pd.DataFrame(data)
# 仅根据'Name'列去重(保留首次出现)
df_name_unique = df.drop_duplicates(subset=['Name'])
print("按Name列去重:")
print(df_name_unique)
#       Name  Age City
# 0    Alice   25   NY
# 1      Bob   30   LA
# 3  Charlie   35   SF
保留最后一次出现的重复行
import pandas as pd

# 创建包含重复数据的DataFrame
data = {
    'Name': ['Alice', 'Bob', 'Alice', 'Charlie', 'Bob'],
    'Age': [25, 30, 25, 35, 30],
    'City': ['NY', 'LA', 'NY', 'SF', 'LA']
}
# 保留最后一次出现的行
df_last = df.drop_duplicates(keep='last')
print("保留最后一次出现的行:")
print(df_last)
#       Name  Age City
# 2    Alice   25   NY
# 4      Bob   30   LA
# 3  Charlie   35   SF
数据类型转换
方法/操作 语法示例 描述
查看数据类型 df.dtypes 显示每列的数据类型
强制类型转换 df[‘col’].astype(‘int’) 将列转换为指定类型(如int, float, str, datetime)
转换为日期时间 pd.to_datetime(df[‘col’]) 将字符串列转为datetime类型
转换为分类数据 df[‘col’].astype(‘category’) 将列转为分类类型(节省内存,提高性能)
数值格式化 df[‘col’].round(2) 保留2位小数
核心方法
操作 方法/函数 描述
查看数据类型 df.dtypes 显示每列的数据类型(如int64、float64、object等)。
强制类型转换 df[‘col’].astype(‘type’) 将列转换为指定类型(如int、float、str、bool等)。
转换为日期时间 pd.to_datetime(df[‘col’]) 将字符串或数值列转为datetime类型(支持自定义格式)。
转换为分类数据 df[‘col’].astype(‘category’) 将列转为分类类型(节省内存,提高性能,适用于有限取值的列如性别、省份)。
数值格式化 df[‘col’].round(2) 保留指定小数位数(如2位)。
  1. 查看数据类型
import pandas as pd

# 加载数据(以sleep.csv为例)
df = pd.read_csv("sleep.csv")
print(df.dtypes)
# person_id                     int64
# gender                       object
# age                           int64
# occupation                   object
# sleep_duration              float64
# sleep_quality               float64
# ...                          ...

说明:object通常为字符串或混合类型,需检查是否需要转换

  1. 强制类型转换:将数值列转换为整数或字符串
# 将sleep_duration从float转为int(丢失小数部分)
df['sleep_duration_int'] = df['sleep_duration'].astype('int32')

# 将gender转为字符串
df['gender_str'] = df['gender'].astype('str')

print(df[['sleep_duration', 'sleep_duration_int', 'gender_str']].head())
#    sleep_duration  sleep_duration_int gender_str
# 0             7.4                  7       Male
# 1             4.2                  4     Female
# 2             6.1                  6       Male
  1. 转换为日期时间:处理时间数据(假设employees.csv有日期列):
# 示例:创建临时日期列(实际数据可能为hire_date)
df_employees = pd.read_csv("employees.csv")
df_employees['fake_date'] = '2023-01-' + df_employees['employee_id'].astype(str).str[:2]

# 转换为datetime
df_employees['fake_date'] = pd.to_datetime(df_employees['fake_date'])
print(df_employees[['employee_id', 'fake_date']].head())
#    employee_id  fake_date
# 0          100 2023-01-10
# 1          101 2023-01-10
# 2          102 2023-01-10

注意:若原始格式非标准,需指定格式参数,如:pd.to_datetime(df[‘date’], format=‘%Y/%m/%d’)

  1. 转换为分类数据:优化内存和性能(适用于低基数列)
# 将gender列转为分类类型
df['gender'] = df['gender'].astype('category')
print(df['gender'].dtypes)
# category
  • 优势:
    • 减少内存占用(尤其对重复值多的列)。
    • 加速groupby、sort等操作
  1. 数值格式化:控制小数位数:
# 保留sleep_quality的2位小数
df['sleep_quality_rounded'] = df['sleep_quality'].round(2)
print(df[['sleep_quality', 'sleep_quality_rounded']].head())
#    sleep_quality  sleep_quality_rounded
# 0            7.0                   7.00
# 1            4.9                   4.90
# 2            6.0                   6.00
常见问题与技巧
  1. 处理转换错误:使用errors='coerce’将无效值转为NaN,避免报错
df['age'] = pd.to_numeric(df['age'], errors='coerce')
  1. 内存优化:将数值列从int64转为int32或float32:
df['age'] = df['age'].astype('int32')
  1. 布尔类型转换:将字符串(如"Yes"/“No”)转为布尔值:
df['is_active'] = df['active_flag'].map({'Yes': True, 'No': False})
  1. 自定义格式化:使用apply实现复杂转换(如百分比):
df['score_percent'] = df['score'].apply(lambda x: f"{x*100:.1f}%")
数据重塑与变形
方法/操作 语法示例 描述
行列转置 df.T 转置DataFrame(行变列,列变行)
宽表转长表 pd.melt(df, id_vars=[‘id’]) 将多列合并为键值对形式(variable和value列)
长表转宽表 df.pivot(index=‘id’, columns=‘var’, values=‘val’) 将长表转换为宽表(类似Excel数据透视)
分列操作 df[‘col’].str.split(‘,’, expand=True) 按分隔符拆分字符串为多列

注意事项

  1. pivot 与 pivot_table 的区别:
    • pivot 要求索引和列的组合唯一,否则报错。
    • pivot_table 支持聚合(如均值、求和),适合非唯一组合。
  2. 分列操作:
    • 使用 expand=True 将拆分结果转为多列。
    • 若分隔符数量不一致,需预处理数据(如填充缺失值)。
  3. 内存管理:
    • 宽表转长表可能增加行数,需注意内存占用
#数据变形
import pandas as pd
data = {
    'ID': [1, 2],
    'name':['alice','bob'],
    'Math': [90, 85],
    'English': [88, 92],
    'Science': [95, 89]
}
df = pd.DataFrame(data)
df
df.T
#宽表转长表
df2= pd.melt(df, id_vars=['ID','name'], var_name='科目', value_name='分数')
df2.sort_values(by=['name','科目'])
#长表转宽表
df3=pd.pivot(df2,index=['ID','name'],columns=['科目'],values='分数')
#分列
data = {
    'ID': [1, 2],
    'name':['alice smith','bob jack'],
    'Math': [90, 85],
    'English': [88, 92],
    'Science': [95, 89]
}
df = pd.DataFrame(data)
df[['first name','last name']] = df['name'].str.split(' ',expand=True)
# 加载数据
df = pd.read_csv("data/sleep.csv")

df=df[['person_id','blood_pressure']]
df[['high','low']]=df['blood_pressure'].str.split('/',expand=True)
df
文本数据处理
方法/操作 语法示例 描述
字符串大小写转换 df[‘col’].str.lower() 转为小写
去除空格 df[‘col’].str.strip() 去除两端空格
字符串替换 df[‘col’].str.replace(‘old’, ‘new’) 替换文本
正则表达式提取 df[‘col’].str.extract(r’(\d+)') 提取匹配正则的文本(如数字)
字符串包含检测 df[‘col’].str.contains(‘abc’) 返回布尔序列,判断是否包含子串
时间数据处理

Timestamp 是 pandas 对 datetime64 数据类型的一个封装。datetime64 是 NumPy 中的一种数据类型,用于表示日期和时间,而 pandas 基于 datetime64 构建了 Timestamp 类,以便更方便地在 pandas 的数据结构(如 DataFrame 和 Series)中处理日期时间数据。
当 pd.to_datetime 接收单个日期时间值时,会返回 Timestamp 对象。

时间戳 timestamp

to_period()获取统计周期

import pandas as pd
d = pd.Timestamp( "2015-05-01 09:08:07.123456" )
# 属性
print('年:',d.year)
print('月:',d.month)
print('日:',d.day)
print('小时:',d.hour)
print('分钟:',d.minute)
print('秒:',d.second)
print('微秒:',d.microsecond)
print('季度:',d.quarter)
print('是否是月底:',d.is_month_end)
print('是否是月初:',d.is_month_start)
print('是否是年底:',d.is_year_end)
print('是否是年初:',d.is_year_start)
# 方法
print('星期几:',d.day_name())
print('转换为年度:',d.to_period("Y"))
print('转换为季度:',d.to_period("Q"))
print('转换为月度:',d.to_period("M"))
print('转换为季度:',d.to_period("Q"))
print('转换为周维度:',d.to_period("W"))

在这里插入图片描述

freq:这是 to_period() 方法最重要的参数,用于指定要转换的时间周期频率。
常见的取值如下:

  • “D”:按天周期,例如 2024-01-01 会转换为 2024-01-01 这个天的周期。
  • “W”:按周周期,通常以周日作为一周的结束,比如日期落在某一周内,就会转换为该周的周期表示。
  • “M”:按月周期,像 2024-05-15 会转换为 2024-05。
  • “Q”:按季度周期,一年分为四个季度,日期会转换到对应的季度周期,例如 2024Q2 。
  • “A” 或 “Y”:按年周期,如 2024-07-20 会转换为 2024 。
日期数据转换
import pandas as pd

# 字符串字段转换为日期类型
a = pd.to_datetime('2025-07-01')
a = pd.to_datetime('20250409')
a = pd.to_datetime('2025/04/13')
a = pd.to_datetime('2025-07')
print(a)
print(type(a))
# dateFrame中的日期转换
df = pd.DataFrame({
    'sales':[100,50,40],
    'date':['2025-01-01','2023-03-02','2025-03-09']
})
df['datetime'] = pd.to_datetime(df['date'])
print(type(df['datetime'].dt))
df['datetime'].dt.day_name()

将日期数据作为索引
将datetime64类型的数据设置为索引,得到的就是DatetimeIndex。

df = pd.read_csv("data/weather.csv")df["date"] = pd.to_datetime(df["date"])  # 将date列转换为datetime64类型
df.set_index("date", inplace=True)  # 将date列设置为索引,inplace=true直接修改原对象
df.info()# <class 'pandas.core.frame.DataFrame'>
# DatetimeIndex: 1461 entries, 2012-01-01 to 2015-12-31

将时间作为索引后可以直接使用时间进行切片取值。

print(df.loc["2013-01":"2013-06"])  # 获取2013年1~6月的数据
#             precipitation  temp_max  temp_min  wind weather
# date
# 2013-01-01            0.0       5.0      -2.8   2.7     sun
# 2013-01-02            0.0       6.1      -1.1   3.2     sun
# ...                   ...       ...       ...   ...     ...
# 2013-06-29            0.0      30.0      18.3   1.7     sun
# 2013-06-30            0.0      33.9      17.2   2.5     sun
print  (  df  .  loc  [  "2015"  ])    # 获取2015年所有数据
#             precipitation  temp_max  temp_min  wind weather
# date
# 2015-01-01            0.0       5.6      -3.2   1.2     sun
# 2015-01-02            1.5       5.6       0.0   2.3    rain
# ...                   ...       ...       ...   ...     ...
# 2015-12-30            0.0       5.6      -1.0   3.4     sun
# 2015-12-31            0.0       5.6      -2.1   3.5     sun

也可以通过between_time()和at_time()获取某些时刻的数据。

df.between_time("9:00", "11:00")  # 获取9:00到11:00之间的数据
df.at_time("3:33")  # 获取3:33的数据
时间间隔 timedelta

当用一个日期减去另一个日期,返回的结果是timedelta64类型

d1 = pd.Timestamp( "2015-05-01 09:08:07.123456" )
d2 = pd.Timestamp( "2015-05-31 09:23:07.123456" )
print(d2-d1)
print(type(d1))
print(type(d2-d1))

将timedelta64类型的数据设置为索引,得到的就是TimedeltaIndex。

df = pd.read_csv("data/weather.csv", parse_dates=[0])
df_date   =   pd  .  to_datetime  (  df  [  "date"  ])
df  [  "timedelta"  ] =   df_date     -     df_date  [  0  ]    # 得到timedelta64类型的数据
df  .  set_index  (  "timedelta"  ,   inplace  =  True  )    # 将timedelta列设置为索引
df  .  info  ()# <class 'pandas.core.frame.DataFrame'>
# TimedeltaIndex: 1461 entries, 0 days to 1460 days

将时间作为索引后可以直接使用时间进行切片取值

print(df.loc["0 days":"5 days"])
#                 date  precipitation  temp_max  temp_min  wind  weather
# timedelta
# 0 days    2012-01-01            0.0      12.8       5.0   4.7  drizzle
# 1 days    2012-01-02           10.9      10.6       2.8   4.5     rain
# 2 days    2012-01-03            0.8      11.7       7.2   2.3     rain
# 3 days    2012-01-04           20.3      12.2       5.6   4.7     rain
# 4 days    2012-01-05            1.3       8.9       2.8   6.1     rain
# 5 days    2012-01-06            2.5       4.4       2.2   2.2     rain
时间序列
  1. 生成时间序列
    为了能更简便地创建有规律的时间序列,pandas提供了date_range()方法。
    date_range()通过开始日期、结束日期和频率代码(可选)创建一个有规律的日期序列,默认的频率是天。
print(pd.date_range("2015-07-03", "2015-07-10"))
# DatetimeIndex(['2015-07-03', '2015-07-04', '2015-07-05', '2015-07-06',
#                '2015-07-07', '2015-07-08', '2015-07-09', '2015-07-10'],
#               dtype='datetime64[ns]', freq='D')

此外,日期范围不一定非是开始时间与结束时间,也可以是开始时间与周期数periods。

print(pd.date_range("2015-07-03", periods=5))  
# DatetimeIndex(['2015-07-03', '2015-07-04', '2015-07-05', '2015-07-06',
#                '2015-07-07'],
#               dtype='datetime64[ns]', freq='D')

可以通过freq参数设置时间频率,默认值是D。此处改为h,按小时变化的时间戳。

print(pd.date_range("2015-07-03", periods=5, freq="h"))
  # DatetimeIndex(['2015-07-03 00:00:00', '2015-07-03 01:00:00',
  #                '2015-07-03 02:00:00', '2015-07-03 03:00:00',
  #                '2015-07-03 04:00:00'],
  #               dtype='datetime64[ns]', freq='h')

下表为常见时间频率代码与说明:

代码 说明
D 天(calendar day,按日历算,含双休日)
B 天(business day,仅含工作日)
W 周(weekly)
ME / M 月末(month end)
BME 月末(business month end,仅含工作日)
MS 月初(month start)
BMS 月初(business month start,仅含工作日)
QE / Q 季末(quarter end)
BQE 季末(business quarter end,仅含工作日)
QS 季初(quarter start)
BQS 季初(business quarter start,仅含工作日)
YE / Y 年末(year end)
BYE 年末(business year end,仅含工作日)
YS 年初(year start)
BYS 年初(business year start,仅含工作日)
h 小时(hours)
bh 小时(business hours,工作时间)
min 分钟(minutes)
s 秒(seconds)
ms 毫秒(milliseonds)
us 微秒(microseconds)
ns 纳秒(nanoseconds)
  1. 偏移量
    可以在频率代码后面加三位月份缩写字母来改变季、年频率的开始时间。
    比如 QE-JAN、BQE-FEB、QS-MAR、BQS-APR等,YE-JAN、BYE-FEB、YS-MAR、BYS-APR 等。
print  (  pd  .  date_range  (  "2015-07-03"  ,   periods  =  10  ,   freq  =  "QE-JAN"  ))
  # 设置1月为季度末
  # DatetimeIndex(['2015-07-31', '2015-10-31', '2016-01-31', '2016-04-30',
  #                '2016-07-31', '2016-10-31', '2017-01-31', '2017-04-30',
  #                '2017-07-31', '2017-10-31'],
  #               dtype='datetime64[ns]', freq='QE-JAN')

同理,也可以在后面加三位星期缩写字母来改变一周的开始时间。
比如 W-SUN、W-MON、W-TUE、W-WED等。

print  (  pd  .  date_range  (  "2015-07-03"  ,   periods  =  10  ,   freq  =  "W-WED"  ))
  # 设置周三为一周的第一天
  # DatetimeIndex(['2015-07-08', '2015-07-15', '2015-07-22', '2015-07-29',
  #                '2015-08-05', '2015-08-12', '2015-08-19', '2015-08-26',
  #                '2015-09-02', '2015-09-09'],
  #               dtype='datetime64[ns]', freq='W-WED')

在这些代码的基础上,还可以将频率组合起来创建的新的周期。例如,可以用小时(h)和分钟(min)的组合来实现2小时30分钟。

print  (  pd  .  date_range  (  "2015-07-03"  ,   periods  =  10  ,   freq  =  "2h30min"  )) 
  # DatetimeIndex(['2015-07-03 00:00:00', '2015-07-03 02:30:00',
  #                '2015-07-03 05:00:00', '2015-07-03 07:30:00',
  #                '2015-07-03 10:00:00', '2015-07-03 12:30:00',
  #                '2015-07-03 15:00:00', '2015-07-03 17:30:00',
  #                '2015-07-03 20:00:00', '2015-07-03 22:30:00'],
  #               dtype='datetime64[ns]', freq='150min')
数据分析与统计
分类 依赖关系 协同应用场景 示例
描述性统计 所有分析的基础 初步了解数据分布,指导后续分组策略 df.describe() 发现某列标准差大 → 触发分组过滤
分组聚合 基于描述性统计或分组过滤结果 按维度拆分后计算指标(如各品类销售额总和) df.groupby(‘category’)[‘sales’].sum()
分组转换 依赖分组聚合结构 在保留原始行数的前提下,添加组内计算列(如标准化、排名) df.groupby(‘group’)[‘value’].transform(lambda x: x/x.max())
分组过滤 依赖描述性统计或分组聚合结果 根据组级条件筛选数据(如剔除样本量不足的组) df.groupby(‘group’).filter(lambda x: len(x) > 5)
相关性分析 可结合分组聚合结果 分析不同分组下变量的关联性(如各地区的价格-销量相关性) df.groupby(‘region’)[[‘price’,‘sales’]].corr()

关键交互逻辑

  1. 从宏观到微观
  • 描述性统计(宏观) → 分组聚合(细分维度) → 分组转换/过滤(微观调整)
  1. 数据流闭环
# 示例:分析高波动品类(闭环流程)
grouped = df.groupby('category') 
# 1. 描述性统计 → 2. 分组过滤 → 3. 分组转换
result = (grouped.filter(lambda x: x['price'].std() > 2)
          .groupby('category')['price']
          .transform(lambda x: (x - x.mean())/x.std()))
  1. 功能互补性
  • 聚合 vs 转换:聚合减少行数,转换保持行数。
  • 过滤 vs 转*:过滤删除整组,转换修改组内值。

可视化应用场景
在这里插入图片描述

通过以上关系图和表格,可清晰理解如何组合这些方法解决实际问题,例如:

  1. 数据清洗:描述统计 → 发现异常 → 分组过滤
  2. 特征工程:分组聚合 → 分组转换(如生成占比特征)
  3. 业务分析:分组聚合 → 相关性分析(如用户分群行为关联)
聚合函数
方法 说明
sum() 求和
mean() 平均值
min() 最小值
max() 最大值
var() 方差
std() 标准差
median() 中位数
quantile() 指定位置的分位数,如quantile(0.5)
describe() 常见统计信息
size() 所有元素的个数
count() 非空元素的个数
first 第一行
last 最后一行
nth 第n行
分组聚合

聚合语法:

  • df.groupby(“分组字段”)[“要聚合的字段”].聚合函数()
  • df.groupby([“分组字段”, “分组字段2”, …])[[“要聚合的字段”, “要聚合的字段2”, …]].聚合函数()

DataFrameGroupBy 对象

对 DataFrame 对象调用groupby()方法后,会返回DataFrameGroupBy对象。如:<pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000024FCBAFD700>
这个对象可以看成是一种特殊形式的 DataFrame,里面隐藏着若干组数据,但是在没有应用累计函数之前不会计算。GroupBy对象是一种非常灵活的抽象类型。在大多数场景中,可以将它看成是DataFrame的集合。

查看分组:通过groups属性查看分组结果,返回一个字典,字典的键是分组的标签,值是属于该组的所有索引的列表。

print(df.groupby("department_id").groups)  # 查看分组结果
# {10.0: [100], 20.0: [101, 102], 30.0: [14, 15, 16, 17, 18, 19]...

通过get_group()方法获取分组:

print(df.groupby("department_id").get_group(50))  
# 获取分组为50的数据
#     employee_id first_name    last_name     email...
# 20          120    Matthew        Weiss    MWEISS...
# 21          121       Adam        Fripp    AFRIPP...
# 22          122      Payam     Kaufling  PKAUFLIN...

按列取值:

print(df.groupby("department_id")["salary"])  
# 按department_id分组,取salary列
# <pandas.core.groupby.generic.SeriesGroupBy object at 0x0000022456D6F2F0>

这里从原来的DataFrame中取某个列名作为一个Series组。与GroupBy对象一样,直到运行累计函数,才会开始计算。

print(df.groupby("department_id")["salary"].mean())  
# 计算每个部门平均薪资
# department_id
# 10.0      4400.000000
# 20.0      9500.000000
# 30.0      4150.000000

按组迭代:GroupBy对象支持直接按组进行迭代,返回的每一组都是Series或DataFrame。

for dept_id,group in df.groupby("department_id"):
    print(f"当前组为{dept_id},组里的数据情况{group.shape}:")
    print(group.iloc[:,0:3])
    print("-------------------")
# 当前组为10.0,组里的数据情况(1, 10):
#      employee_id first_name last_name
# 100          200   Jennifer    Whalen
# -------------------
# 当前组为20.0,组里的数据情况(2, 10):
#      employee_id first_name  last_name
# 101          201    Michael  Hartstein
# 102          202        Pat        Fay

按多字段分组:

salary_mean = df.groupby(["department_id", "job_id"])[
   ["salary", "commission_pct"]
].mean()  # 按department_id和job_id分组
print(salary_mean.index)  # 查看分组后的索引
# MultiIndex([( 10.0,    'AD_ASST'),
#             ( 20.0,     'MK_MAN'),
#             ( 20.0,     'MK_REP'),
#             ( 30.0,   'PU_CLERK'),
#             ( 30.0,     'PU_MAN'),
#             ...
print(salary_mean.columns)  # 查看分组后的列
# Index(['salary', 'commission_pct'], dtype='object')

按多个字段分组后得到的索引为复合索引。

可通过reset_index()方法重置索引。

print(salary_mean.reset_index())
#     department_id      job_id        salary  commission_pct
# 0            10.0     AD_ASST   4400.000000             NaN
# 1            20.0      MK_MAN  13000.000000             NaN
# 2            20.0      MK_REP   6000.000000             NaN
# 3            30.0    PU_CLERK   2780.000000             NaN
# 4            30.0      PU_MAN  11000.000000             NaN

也可以在分组的时候通过as_index = False参数(默认是True)重置索引。

salary_mean = df.groupby(["department_id", "job_id"], as_index=False)[
    ["salary", "commission_pct"]
].mean()  # 按department_id和job_id分组
print(salary_mean)#     department_id      job_id        salary  commission_pct
# 0            10.0     AD_ASST   4400.000000             NaN
# 1            20.0      MK_MAN  13000.000000             NaN
# 2            20.0      MK_REP   6000.000000             NaN
# 3            30.0    PU_CLERK   2780.000000             NaN
# 4            30.0      PU_MAN  11000.000000             NaN

分组频数计算:统计每个月不同天气状况的数量

df.groupby("month")["weather"].nunique()
# date
# 2012-01    4
# 2012-02    4
# 2012-03    4
# 2012-04    4
# 2012-05    3
一次计算多个统计值

可以通过agg()或aggregate()进行更复杂的操作,如一次计算多个统计值

df = pd.read_csv("data/employees.csv")  # 读取员工数据
# 按department_id分组,计算salary的最小值,中位数,最大值
print(df.groupby("department_id")["salary"].agg(["min", "median", "max"]))#                    min   median      max
# department_id
# 10.0            4400.0   4400.0   4400.0
# 20.0            6000.0   9500.0  13000.0
# 30.0            2500.0   2850.0  11000.0
# 40.0            6500.0   6500.0   6500.0
# 50.0            2100.0   3100.0   8200.0

多个列计算不同的统计值:可以在agg()中传入字典,对多个列计算不同的统计值。

df = pd.read_csv("data/employees.csv")  # 读取员工数据
# 按department_id分组,统计job_id的种类数,commission_pct的平均值
print(df.groupby("department_id").agg({"job_id": "nunique", "commission_pct": "mean"}))
#                job_id  commission_pct
# 10.0                1             NaN
# 20.0                2             NaN
# 30.0                2             NaN
# 40.0                1             NaN
# 50.0                3             NaN

重命名统计值:可以在agg()后通过rename()对统计后的列重命名

df = pd.read_csv("data/employees.csv")  # 读取员工数据
# 按department_id分组,统计job_id的种类数,commission_pct的平均值
print(
    df.groupby("department_id")
    .agg(
        {"job_id": "nunique", "commission_pct": "mean"},
    )
    .rename(
        columns={"job_id": "工种数", "commission_pct": "佣金比例平均值"},
    )
)
#                工种数  佣金比例平均值
# department_id
# 10.0             1      NaN
# 20.0             2      NaN
# 30.0             2      NaN
# 40.0             1      NaN
# 50.0             3      NaN

自定义函数:可以向agg()中传入自定义函数进行计算。

df = pd.read_csv("data/employees.csv")  # 读取员工数据
def f(x):
    """统计每个部门员工last_name的首字母"""    result = set()
    for i in x:
        result.add(i[0])
    return result
print(df.groupby("department_id")["last_name"].agg(f))
# department_id
# 10.0                                                   {W}
# 20.0                                                {F, H}
# 30.0                                    {B, T, R, C, K, H}
# 40.0                                                   {M}
# 50.0     {O, E, K, S, W, L, P, D, C, V, B, T, M, J, F, ...
分组转换

聚合操作返回的是对组内全量数据缩减过的结果,而转换操作会返回一个新的全量数据。数据经过转换之后,其形状与原来的输入数据是一样的。
通过transform()将每一组的样本数据减去各组的均值,实现数据标准化

df = pd.read_csv("data/employees.csv")  # 读取员工数据
print(df.groupby("department_id")["salary"].transform(lambda x: x - x.mean()))

通过transform()按分组使用平均值填充缺失值

df = pd.read_csv("data/employees.csv")  # 读取员工数据
na_index = pd.Series(df.index.tolist()).sample(30)  # 随机挑选30条数据
df.loc[na_index, "salary"] = pd.NA  # 将这30条数据的salary设置为缺失值
print(df.groupby("department_id")["salary"].agg(["size", "count"]))  # 查看每组数据总数与非空数据数
def fill_missing(x):
    # 使用平均值填充,如果平均值也为NaN,用0填充    
    if np.isnan(x.mean()):
        return 0    
    return x.fillna(x.mean())
df["salary"] = df.groupby("department_id")["salary"].transform(fill_missing)
print(df.groupby("department_id")["salary"].agg(["size", "count"]))  # 查看每组数据总数与非空数据数
分组过滤

过滤操作可以让我们按照分组的属性丢弃若干数据。
例如,我们可能只需要保留commission_pct不包含空值的分组的数据。

commission_pct_filter = df.groupby("department_id").filter(lambda x: x["commission_pct"].notnull().all()
)  # 按department_id分组,过滤掉commission_pct包含空值的分组
print(commission_pct_filter)

用得最多的pandas对象是 Series,一个一维的标签化数组对象,另一个是 DataFrame,它是一个面向列的二维表结构。

特性 Series DataFrame
维度 一维 二维
索引 单索引 行索引+列名
数据存储 同质化数据类型 各列可不同数据类型
类比 Excel单列 整张Excel工作表
创建方式 pd.Series([1,2,3]) pd.DataFrame({‘col’:[1,2,3]})

Pandas 与 Numpy 的关系与区别:就像学习数学要先掌握算术才能学代数一样,NumPy就是数据分析的"算术基础"。虽然可以直接用计算器(Pandas),但理解底层原理才能走得更远。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐