see: pandas

1 初识pandas

处理二维表数据(即 DataFrame

列称为 Series

2 全局配置

pd.set_option("display.max_columns", None)                  # 显示所有列
pd.set_option("display.expand_frame_repr", False)           # 禁止换行显示
pd.set_option("display.width", 1000)                        # 设置终端显示宽度(避免自动换行)

3 基本用法

3.1 对象

ages = pd.Series([28, 18, 18], name="Age")                   # DataFrame信息   
df = pd.DataFrame(                                           # 创建 DataFrame
    {
        'Name': ['Tom', 'Jerry', 'Mary',],
        "Age": [28, 18, 18],
        "Sex": ["male", "male", "female"],
    }
)

df.info()                                                     # DataFrame信息
# output:
# <class 'pandas.core.frame.DataFrame'>
# RangeIndex: 3 entries, 0 to 2
# Data columns (total 3 columns):
#  #   Column  Non-Null Count  Dtype 
# ---  ------  --------------  ----- 
#  0   Name    3 non-null      object
#  1   Age     3 non-null      int64 
#  2   Sex     3 non-null      object
# dtypes: int64(1), object(2)
# memory usage: 204.0+ bytes
# None

df.dtypes                                                     # 每列数据的类型
# output:
# Name    object
# Age      int64
# Sex     object
# dtype: object

df.shape                                                      # 行数和列数统计
# output:
# (3, 3)

3.2 表头

df.rename(columns={'ole_column_name': 'new_column_name'}, inplace=True)           # 重命名Column。inplace=True-原df上进行修改;inplace=False-创建新的DataFrame(原df不变)
df = df.rename(columns=str.lower)                                                 # 重命名Column:改成小写

df.drop(columns={'Age', 'Sex'}, inplace=True)                                     # 删除Column
df['new_column'] = df['column_1'] * df['column_2']                                # 添加Column(添加到最后一列)

# 指定index=loc插入Column
df.insert(loc=1, column='new_column', value='')                                   # 插入Column
df.insert(loc=1, column='new_column', value=["C001", "C002", "C003"])             # 插入Column 

3.3 行

df.head(n)                                                    # 前n行
df.tail(n)                                                    # 最后n行

# 过滤
df[df['Age'] > 18]                                            # 过滤单个条件。 Age>18 的行
df[df['Age'].isin([18, 26])]                                  # 过滤单个条件。 Age=18或26 的行
df[(df['Age'] > 18) & ( df['Sex'] == 'male')]                 # 过滤多个条件。可以使用 & 和 |
df[df['Age'].notna()]                                         # 过滤 Age的值 有效的行

3.4 列

df['Name'].shape                                              # 行数和列数统计
df[['Name', 'Age']].shape                                     # 行数和列数统计
# output:
# (3,)
# (3, 2)

df.describe()                                                 # 显示数字类型列的信息(不会显示非数字类型的Column)
# output:
#              Age
# count   3.000000
# mean   21.333333
# std     5.773503
# min    18.000000
# 25%    18.000000
# 50%    18.000000
# 75%    23.000000
# max    28.000000

# 过滤
df['Age']                                                     # 过滤单列
df[["Name", "Age"]]                                           # 过滤多列

3.6 单元格

# 过滤
df.loc[df["Age"] > 20, "Name"]                                # 根据条件过滤
df.iloc[9:25, 2:5]                                            # 根据索引过滤(第10~25行,第3~5列的单元格)
                                                              # 左闭右开

4 高级用法

see: apply() / map() / applymap()区别

4.1 对象

4.2 表头

4.2.1 Column顺序

df = df[["Age", "Name", "Sex"]]                   # 方法一:直接指定列顺序
df = df.reindex(columns=["Age", "Name", "Sex"])   # 方法二:使用 reindex

# 方法三:通过 insert 和 drop 移动列
age_series = df.pop("Age")                        # 移除 Age列
df.insert(loc=0, column='Age', value=age_series)  # 插入到第 0 列位置

# 指定列按固定顺序,剩余列保留原有顺序,并在 指定列 的后面
# ['Age', 'Sex', 'also_can_be_not_exists_column'] 重排到最前面,其他列跟在后面
target_order = ['Age', 'Sex']
existing_target = [col for col in target_order if col in df.columns]      # 筛选出存在的目标列,并按目标顺序排列
remaining_cols = [col for col in df.columns if col not in target_order]   # 获取剩余列,并保持原有顺序
df = df[existing_target + remaining_cols]                                 # 重新排列列顺序

4.3 行

4.4 列

4.4.1 计算 & 聚合

# 值计算
df['Age'] = df['Age'] * 10
df['Age'] = df['Age'].apply(lambda x: x * 10)
df['Age'] = df['Age'].map(lambda x: x * 100)

# 计算 (以下方法均可以进行多列操作。如df[['Age', 'Weight']].min())
df['Age'].max()                                               # 最大
df['Age'].min()                                               # 最小
df['Age'].mean()                                              # 平均值
df['Age'].median()                                            # 中位数
df['Age'].sum()                                               # 求和

# 聚合 (对数据进行多种统计操作,如求和、平均、最大值、最小值等)
df.agg({
    "Age": ["min", "max", "median", "skew"],
    "column_2": ["min", "max", "median", "skew"],
})

df["Age"].value_counts()                                     # 统计列中每个类别的记录数
# output:
# Age
# 18    2
# 28    1
# Name: count, dtype: int64

4.4.2 分组

# 分组
df[["Sex", "Age"]].groupby("Sex").mean()                      # Sex进行分组,计算'Age'的值
# output:
#         Age
# Sex         
# female  18.0
# male    23.0

df.groupby("Sex").mean(numeric_only=True)                    # Sex进行分组,计算所有 数字类型Column 的值

df.groupby("Sex")["Age"].mean()                              
# output:
# Sex
# female    27.915709
# male      30.726645
# Name: Age, dtype: float64

df.groupby(["Sex", "Pclass"])["Fare"].mean()
# output:
# Sex     Pclass
# female  1         106.125798
#         2          21.970121
#         3          16.118810
# male    1          67.226127
#         2          19.741782
#         3          12.661633
# Name: Fare, dtype: float64

4.5单元格

4.6 时间处理

时间格式:

字符 说明
%Y 年份(4位数)
%m 月份(01-12)
%d 日期(01-31)
%H 小时(00-23)
%M 分钟(00-59)
%S 秒数(00-59)
%f 微秒(000000-999999)
%a 星期几的缩写(Mon,Tue等)
%A 星期几的全称(Monday,Tuesday等)
%b 月份的缩写(Jan,Feb等)
%B 月份的全称(January,February等)
%c 完整的日期和时间(Tue Aug 16 21:30:00 2016)
%p AM或PM
%z 时区偏移量(+0800表示东八区)
%% 百分号标记

数据格式:

datetime                    value
2025-01-01 00:00:00          10
2025-01-01 00:15:00           9
2025-01-01 00:30:00           8
2025-01-02 00:00:00           7
2025-01-02 00:15:00           6
2025-01-02 00:30:00           1
2025-02-01 00:00:00           2
2025-02-01 00:15:00           3
2025-02-01 00:30:00           4
2025-02-02 00:00:00           5
2025-02-02 00:15:00           12
2025-02-02 00:30:00           11

DataFrame:

df = pd.DataFrame(
    {
        'datetime': [
            '2025-01-01 00:00:00',
            '2025-01-01 00:15:00',
            '2025-01-01 00:30:00',
            '2025-01-02 00:00:00',
            '2025-01-02 00:15:00',
            '2025-01-02 00:30:00',
            '2025-02-01 00:00:00',
            '2025-02-01 00:15:00',
            '2025-02-01 00:30:00',
            '2025-02-02 00:00:00',
            '2025-02-02 00:15:00',
            '2025-02-02 00:30:00',
        ],
        'value': [10, 9, 8, 7, 6, 1, 2, 3, 4, 5, 12, 11]
    }
)

4.6.1 基本用法

df["datetime"] = pd.to_datetime(df["datetime"], format='%Y-%m-%d %H:%M:%S')                # 将 str 转换成 datetime类型
df = pd.read_csv(path, parse_dates=["datetime"], date_format='%Y-%m-%d %H:%M:%S')          # 读取文件时,直接指定字段为 datetime类型

4.6.2 resample

声明:

df.resample(
	rule,
	axis: Axis | lib.NoDefault = lib.no_default,
	closed: Literal["right", "left"] | None = None,
	label: Literal["right", "left"] | None = None,
	convention: Literal["start", "end", "s", "e"] | lib.NoDefault = lib.no_default,
	kind: Literal["timestamp", "period"] | None | lib.NoDefault = lib.no_default,
	on: Level | None = None,
	level: Level | None = None,
	origin: str | TimestampConvertibleTypes = "start_day",
	offset: TimedeltaConvertibleTypes | None = None,
	group_keys: bool_t = False,
)

说明:

参数 说明
rule 定义重采样的频率.可以使用 "4.6.2.1 rule参数说明" 字符串别名
axis 0(默认)-沿行(时间轴)重采样,
1-沿列重采样(很少使用)
closed 控制重采样区间的闭合方向:
- 'right':右闭合,即区间包含结束点
- 'left':左闭合,即区间包含起始点

默认值:
‘ME’, ‘YE’, ‘QE’, ‘BME’, ‘BA’, ‘BQE’, and ‘W’- default ‘right’
其他 - default 'left'
label 控制分组标签的闭合方向:
- 'right':右闭合,即区间包含结束点
- 'left':左闭合,即区间包含起始点

默认值:
‘ME’, ‘YE’, ‘QE’, ‘BME’, ‘BA’, ‘BQE’, and ‘W’- default ‘right’
其他 - default 'left'
convention Deprecated
kind Deprecated
on 当DataFrame没有时间索引时,指定用于重采样的时间列
level 对于多级索引,指定用于重采样的级别名称或数字
origin Timestamp或字符串,默认为'start_day'。调整分组的时间戳。原点的时区必须与索引的时区匹配。如果是字符串,必须是以下之一:

'epoch':原点是1970-01-01。
'start':原点是时间序列的第一个值。
'start_day':原点是时间序列的午夜的第一天。
'end':原点是时间序列的最后一个值。
'end_day':原点是最后一天午夜的天花板。
offset Timedelta或字符串,默认为None。添加到原点的偏移时间间隔
group_keys bool,默认为False。是否在对重采样对象使用.apply()时将组键包含在结果索引中

4.6.2.1 rule参数说明

频率参数 频率 说明
'S' 每秒采样
'T'或'min' 分钟 每分钟采样
'H' 小时 每小时采样
'D' 每天采样
'W' 每周采样
'M' 月末 每月最后一天采样
'Q' 季末 每季最后一天采样
'A'或'Y' 年末 每年最后一天采样

组合频率示例:

频率参数 频率 说明
'5T' 5分钟 每5分钟采样
'15T' 15分钟 每15分钟采样
'2H' 2小时 每2小时采样
'2H30T' 2小时30分钟 每2.5小时采样
'1D2H' 1天2小时 每26小时采样
'3D' 3在不在 每3天采样
'W-MON' 每周星期一 每周采样
'Q-JAN' 每年1月开始的季度末 每年1/4/7/10最后一天采样
'A-DEC' 每年12月为年末(默认) 每年12月31日采样
df["datetime"] = pd.to_datetime(df["datetime"], format='%Y-%m-%d %H:%M:%S')                # 将 str 转换成 datetime类型
df.set_index('datetime', inplace=True)                                                     # resample()需要 datetime类型为 index

monthly_max = df.resample("ME").max()                                                      # 统月分组,求最大值
# output:
#             value
# datetime         
# 2025-01-31     10
# 2025-02-28     12

4.7 str类型处理

df["Name"].str.lower()                                             # 全部小写
df["Name"].str.split(",").str.get(0)                               # 获取以,分隔后index=0的数据
df["Name"].str.contains("text")                                    # 值是否包含text
df["Sex"] = df["Sex"].replace({"male": "M", "female": "F"})        # 替换指定字符:列Sex,用'M'替代'male'、'F'替代'Female'

5 文件读取/写入

pandas支持csv, json, table, excel, hdf, feather, parquet, sql等文件读取和写入

读取:pd.read_*()

写入:pd.to_*()

df.to_csv(path, encoding="utf-8", index=False)                  # 写csv
df.to_excel(path, sheet_name="sheet1", index=False)             # 写excel

df = pd.read_csv(path, encoding="utf-8", dtype={"code": str})   # 读csv。dtype-指定字段类型
df = pd.read_excel(path, sheet_name="sheet1", index=False)      # 读excle