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 高级用法
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