import numpy as np # 导入 NumPy 库,用于数值计算
import pandas as pd # 导入 Pandas 库,用于数据分析
float_data = pd.Series([1.2, -3.5, np.nan, 0]) # 创建一个包含浮点数和 NaN 的 Series
float_data # 显示 Series
0 1.2
1 -3.5
2 NaN
3 0.0
dtype: float64
数据分析和建模需要大量的数据准备工作。
加载、清洗、转换和重新排列数据会占用分析师的大量时间 (通常占 80% 甚至更多!😮)。
数据并不总是以正确的格式存在。现实世界的数据是混乱的!
Pandas 结合 Python 的内置功能,为数据操作提供了强大的工具。
Pandas 提供了用于数据处理的高级、灵活且快速的工具。
它的设计目标是有效地处理现实世界中的数据挑战。
本章涵盖以下工具:
缺失数据在数据分析中很常见。
Pandas 的目标是使处理缺失数据尽可能容易。
默认情况下,pandas 中的描述性统计会排除缺失数据。
Pandas 使用 NaN
(Not a Number,非数字),一个浮点值,来表示缺失的数据,尤其是在处理float64
数据类型时。
NaN
标记import numpy as np # 导入 NumPy 库,用于数值计算
import pandas as pd # 导入 Pandas 库,用于数据分析
float_data = pd.Series([1.2, -3.5, np.nan, 0]) # 创建一个包含浮点数和 NaN 的 Series
float_data # 显示 Series
0 1.2
1 -3.5
2 NaN
3 0.0
dtype: float64
np.nan
是一个特殊的浮点值,表示缺失数据。
它是一个标记值 – 它的存在表示一个缺失值或空值。
.isna()
检测.isna()
方法返回一个布尔类型的 Series。
True
表示缺失值 (NaN),False
表示非缺失值。
Pandas 采用 R 语言的约定:缺失数据被称为 NA (not available,不可用)。
NA 可能意味着:
分析缺失数据本身可以揭示数据收集问题或潜在的偏差。🤔
None
也是 NAstring_data = pd.Series(["aardvark", np.nan, None, "avocado"]) # 创建一个包含字符串、NaN 和 None 的 Series
string_data # 显示 Series
0 aardvark
1 NaN
2 None
3 avocado
dtype: object
Python 内置的 None
值在 pandas 中也被视为 NA。
字符串和数值类型的 Series 都可以将 None
和 NaN
作为 NA。
float_data = pd.Series([1, 2, None], dtype='float64') #即便序列中给定的是None,在指定类型为float64后,会被转换为NaN
float_data
0 1.0
1 2.0
2 NaN
dtype: float64
float_data
使用NaN
来表示缺失值。方法 | 描述 |
---|---|
dropna |
根据缺失值筛选轴标签 (行/列),并提供阈值选项。 |
fillna |
使用指定值或插值方法 (例如 “ffill”、“bfill”) 填充缺失数据。 |
isna |
返回一个布尔数组/Series,指示哪些值是缺失的/NA。 |
notna |
isna 的反操作:对于非 NA 值返回 True ,对于 NA 值返回 False 。 |
这些方法为在 pandas 中处理缺失数据提供了基础。
dropna
data = pd.Series([1, np.nan, 3.5, np.nan, 7]) # 创建一个包含数值和 NaN 的 Series
data.dropna() # 使用 .dropna() 方法删除包含 NaN 的元素
0 1.0
2 3.5
4 7.0
dtype: float64
Series 上的 dropna()
返回一个仅包含非空数据和索引标签的新 Series。
等同于布尔索引:data[data.notna()]
。
dropna
(第 1 部分)dropna
(第 2 部分)默认情况下,dropna()
会删除包含任何 NA 值的行。
这种方式可能非常严格。
how='all'
的 dropna
0 | 1 | 2 | |
---|---|---|---|
0 | 1.0 | 6.5 | 3.0 |
1 | 1.0 | NaN | NaN |
3 | NaN | 6.5 | 3.0 |
how="all"
仅删除所有值都为 NA 的行。
比默认行为更宽松。
0 | 1 | 2 | |
---|---|---|---|
0 | 1.0 | 6.5 | 3.0 |
1 | 1.0 | NaN | NaN |
2 | NaN | NaN | NaN |
3 | NaN | 6.5 | 3.0 |
要删除列,请使用 axis="columns"
(或 axis=1
)。
how="all"
与 axis="columns"
一起使用会删除所有值都为 NA 的列。
thresh
参数的 dropna
(第 1 部分)df = pd.DataFrame(np.random.standard_normal((7, 3))) # 创建一个包含随机数的 DataFrame
df.iloc[:4, 1] = np.nan # 将第 1 列的前 4 个值设置为 NaN
df.iloc[:2, 2] = np.nan # 将第 2 列的前 2 个值设置为 NaN
df # 显示 DataFrame
0 | 1 | 2 | |
---|---|---|---|
0 | -0.508112 | NaN | NaN |
1 | -0.167480 | NaN | NaN |
2 | -2.513986 | NaN | 2.715578 |
3 | 0.741943 | NaN | -1.950539 |
4 | 1.417023 | 0.714643 | -0.046613 |
5 | 0.161423 | 0.150239 | -1.075142 |
6 | 1.822603 | -0.586554 | -1.483757 |
thresh
参数的 dropna
(第 2 部分)0 | 1 | 2 | |
---|---|---|---|
4 | 1.417023 | 0.714643 | -0.046613 |
5 | 0.161423 | 0.150239 | -1.075142 |
6 | 1.822603 | -0.586554 | -1.483757 |
0 | 1 | 2 | |
---|---|---|---|
2 | -2.513986 | NaN | 2.715578 |
3 | 0.741943 | NaN | -1.950539 |
4 | 1.417023 | 0.714643 | -0.046613 |
5 | 0.161423 | 0.150239 | -1.075142 |
6 | 1.822603 | -0.586554 | -1.483757 |
thresh
参数保留至少具有 thresh
个非 NA 值的行。
可以更精细地控制要保留哪些行。
fillna
填充0 | 1 | 2 | |
---|---|---|---|
0 | -0.508112 | 0.000000 | 0.000000 |
1 | -0.167480 | 0.000000 | 0.000000 |
2 | -2.513986 | 0.000000 | 2.715578 |
3 | 0.741943 | 0.000000 | -1.950539 |
4 | 1.417023 | 0.714643 | -0.046613 |
5 | 0.161423 | 0.150239 | -1.075142 |
6 | 1.822603 | -0.586554 | -1.483757 |
fillna(value)
将所有 NA 值替换为指定的 value
。
一个常见的选择是 0,但这取决于具体情况。
fillna
0 | 1 | 2 | |
---|---|---|---|
0 | -0.508112 | 0.500000 | 0.000000 |
1 | -0.167480 | 0.500000 | 0.000000 |
2 | -2.513986 | 0.500000 | 2.715578 |
3 | 0.741943 | 0.500000 | -1.950539 |
4 | 1.417023 | 0.714643 | -0.046613 |
5 | 0.161423 | 0.150239 | -1.075142 |
6 | 1.822603 | -0.586554 | -1.483757 |
使用字典为每列指定不同的填充值。
字典的键是列标签;值是填充值。
fillna
进行插值 (第 1 部分)df = pd.DataFrame(np.random.standard_normal((6, 3))) # 创建一个包含随机数的 DataFrame
df.iloc[2:, 1] = np.nan # 将第 1 列的第 2 行之后的值设置为 NaN
df.iloc[4:, 2] = np.nan # 将第 2 列的第 4 行之后的值设置为 NaN
df # 显示 DataFrame
0 | 1 | 2 | |
---|---|---|---|
0 | -2.592998 | 0.252305 | 0.329177 |
1 | -0.445629 | -0.315648 | 0.445700 |
2 | -0.193578 | NaN | -0.436106 |
3 | 1.041361 | NaN | -1.718190 |
4 | 0.789268 | NaN | NaN |
5 | 0.141477 | NaN | NaN |
fillna
进行插值 (第 2 部分)0 | 1 | 2 | |
---|---|---|---|
0 | -2.592998 | 0.252305 | 0.329177 |
1 | -0.445629 | -0.315648 | 0.445700 |
2 | -0.193578 | -0.315648 | -0.436106 |
3 | 1.041361 | -0.315648 | -1.718190 |
4 | 0.789268 | -0.315648 | -1.718190 |
5 | 0.141477 | -0.315648 | -1.718190 |
method="ffill"
(前向填充) 将上一个有效观测值向前传播。-method="bfill"
(后向填充)使用下一个有效观测值来填充空缺。 - 适用于时间序列或有序数据。
limit
参数的 fillna
0 | 1 | 2 | |
---|---|---|---|
0 | -2.592998 | 0.252305 | 0.329177 |
1 | -0.445629 | -0.315648 | 0.445700 |
2 | -0.193578 | -0.315648 | -0.436106 |
3 | 1.041361 | -0.315648 | -1.718190 |
4 | 0.789268 | NaN | -1.718190 |
5 | 0.141477 | NaN | -1.718190 |
limit
参数限制 ffill
或 bfill
填充的连续 NA 值的数量。fillna
进行插补data = pd.Series([1., np.nan, 3.5, np.nan, 7]) # 创建一个包含数值和 NaN 的 Series
data.fillna(data.mean()) # 使用 .fillna(data.mean()) 将 NaN 值替换为 Series 的平均值
0 1.000000
1 3.833333
2 3.500000
3 3.833333
4 7.000000
dtype: float64
用平均值、中位数或其他统计量替换缺失值。
这是一种简单的插补形式。
筛选和清洗是必不可少的,但数据通常需要进一步转换。
本节涵盖:
data = pd.DataFrame({"k1": ["one", "two"] * 3 + ["two"],
"k2": [1, 1, 2, 3, 3, 4, 4]}) # 创建一个包含重复行的 DataFrame
data # 显示 DataFrame
k1 | k2 | |
---|---|---|
0 | one | 1 |
1 | two | 1 |
2 | one | 2 |
3 | two | 3 |
4 | one | 3 |
5 | two | 4 |
6 | two | 4 |
duplicated()
识别重复项0 False
1 False
2 False
3 False
4 False
5 False
6 True
dtype: bool
duplicated()
返回一个布尔 Series,指示每行是否为重复项 (是否在之前出现过)。drop_duplicates()
删除重复项k1 | k2 | |
---|---|---|
0 | one | 1 |
1 | two | 1 |
2 | one | 2 |
3 | two | 3 |
4 | one | 3 |
5 | two | 4 |
drop_duplicates()
返回一个删除了重复行的新 DataFrame。
保留每个唯一行的第一个出现。
drop_duplicates()
(第 1 部分)drop_duplicates()
(第 2 部分)k1 | k2 | v1 | |
---|---|---|---|
0 | one | 1 | 0 |
1 | two | 1 | 1 |
使用 subset
参数指定要检查重复项的列的子集。
这里,只考虑 "k1"
列。
keep='last'
的 drop_duplicates()
k1 | k2 | v1 | |
---|---|---|---|
0 | one | 1 | 0 |
1 | two | 1 | 1 |
2 | one | 2 | 2 |
3 | two | 3 | 3 |
4 | one | 3 | 4 |
6 | two | 4 | 6 |
keep="last"
保留每个唯一行 (或列组合) 的最后一个出现。
默认为 keep="first"
。
data = pd.DataFrame({"food": ["bacon", "pulled pork", "bacon",
"pastrami", "corned beef", "bacon",
"pastrami", "honey ham", "nova lox"],
"ounces": [4, 3, 12, 6, 7.5, 8, 3, 5, 6]}) # 创建一个包含食品和重量信息的 DataFrame
data # 显示 DataFrame
food | ounces | |
---|---|---|
0 | bacon | 4.0 |
1 | pulled pork | 3.0 |
2 | bacon | 12.0 |
3 | pastrami | 6.0 |
4 | corned beef | 7.5 |
5 | bacon | 8.0 |
6 | pastrami | 3.0 |
7 | honey ham | 5.0 |
8 | nova lox | 6.0 |
.map()
data["animal"] = data["food"].map(meat_to_animal) # 使用 .map() 方法和映射字典将 "food" 列映射到 "animal" 列
data # 显示 DataFrame
food | ounces | animal | |
---|---|---|---|
0 | bacon | 4.0 | pig |
1 | pulled pork | 3.0 | pig |
2 | bacon | 12.0 | pig |
3 | pastrami | 6.0 | cow |
4 | corned beef | 7.5 | cow |
5 | bacon | 8.0 | pig |
6 | pastrami | 3.0 | cow |
7 | honey ham | 5.0 | pig |
8 | nova lox | 6.0 | salmon |
Series 的 .map()
方法接受一个函数或一个类似字典的对象 (如我们的映射)。
它将映射应用于 Series 的每个元素。
.map()
一起使用def get_animal(x): # 定义一个函数,根据食物名称返回对应的动物
return meat_to_animal[x]
data["food"].map(get_animal) # 使用 .map() 方法和自定义函数将 "food" 列映射到动物类型
0 pig
1 pig
2 pig
3 cow
4 cow
5 pig
6 cow
7 pig
8 salmon
Name: food, dtype: object
我们也可以将函数与 .map()
一起使用。
该函数将 Series 中的单个元素作为输入,并返回转换后的值。
data = pd.Series([1., -999., 2., -999., -1000., 3.]) # 创建一个包含数值和一些表示缺失值的特殊值的 Series
data # 显示 Series
0 1.0
1 -999.0
2 2.0
3 -999.0
4 -1000.0
5 3.0
dtype: float64
replace()
替换单个值0 1.0
1 NaN
2 2.0
3 NaN
4 -1000.0
5 3.0
dtype: float64
replace(old_value, new_value)
将 old_value
的所有出现替换为 new_value
。replace()
替换多个值0 1.0
1 NaN
2 2.0
3 NaN
4 NaN
5 3.0
dtype: float64
data.replace([-999, -1000], [np.nan, 0]) # 使用 .replace() 方法为不同的旧值指定不同的替换值,将 -999 替换为 NaN,将 -1000 替换为 0
0 1.0
1 NaN
2 2.0
3 NaN
4 0.0
5 3.0
dtype: float64
replace()
一起使用0 1.0
1 NaN
2 2.0
3 NaN
4 0.0
5 3.0
dtype: float64
字典也可以与 replace()
一起使用。
键是旧值;值是新值。
data = pd.DataFrame(np.arange(12).reshape((3, 4)),
index=["Ohio", "Colorado", "New York"],
columns=["one", "two", "three", "four"]) # 创建一个 DataFrame,并指定行索引和列索引
data # 显示 DataFrame
one | two | three | four | |
---|---|---|---|---|
Ohio | 0 | 1 | 2 | 3 |
Colorado | 4 | 5 | 6 | 7 |
New York | 8 | 9 | 10 | 11 |
.map()
修改索引 (第 1 部分).map()
修改索引 (第 2 部分)one | two | three | four | |
---|---|---|---|---|
OHIO | 0 | 1 | 2 | 3 |
COLO | 4 | 5 | 6 | 7 |
NEW | 8 | 9 | 10 | 11 |
与 Series 类似,轴索引也有一个 .map()
方法。
我们应用一个函数来转换每个索引标签。
赋值给 data.index
会就地修改 DataFrame。
rename()
创建转换后的副本data.rename(index=str.title, columns=str.upper) # 使用 .rename() 方法创建转换后的副本,而不修改原始 DataFrame,将行索引首字母大写,列索引全部大写
ONE | TWO | THREE | FOUR | |
---|---|---|---|---|
Ohio | 0 | 1 | 2 | 3 |
Colo | 4 | 5 | 6 | 7 |
New | 8 | 9 | 10 | 11 |
rename()
创建一个转换后的副本,而不修改原始 DataFrame。
index
和 columns
参数可以接受函数、字典或 Series。
rename()
data.rename(index={"OHIO": "INDIANA"},
columns={"three": "peekaboo"}) # 使用字典对部分轴标签进行重命名,将行索引 "OHIO" 重命名为 "INDIANA",将列索引 "three" 重命名为 "peekaboo"
one | two | peekaboo | four | |
---|---|---|---|---|
INDIANA | 0 | 1 | 2 | 3 |
COLO | 4 | 5 | 6 | 7 |
NEW | 8 | 9 | 10 | 11 |
rename()
一起使用可以修改轴标签的子集。连续数据通常会被离散化或分箱以进行分析。
示例:将年龄分组到年龄范围。
ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32] # 创建一个年龄列表
bins = [18, 25, 35, 60, 100] # 定义分箱边界
age_categories = pd.cut(ages, bins) # 使用 pd.cut() 函数将年龄数据分箱
age_categories # 显示分箱结果
[(18, 25], (18, 25], (18, 25], (25, 35], (18, 25], ..., (25, 35], (60, 100], (35, 60], (35, 60], (25, 35]]
Length: 12
Categories (4, interval[int64, right]): [(18, 25] < (25, 35] < (35, 60] < (60, 100]]
pd.cut(data, bins)
根据指定的 bins
边界将数据划分为多个箱。
返回一个特殊的 Categorical
对象。
Categorical
对象 (第 1 部分)Categorical
对象 (第 2 部分)codes
: 一个整数数组,表示每个值所属的箱 (从 0 开始)。categories
: 一个 IntervalIndex
对象,包含箱的区间。Categorical
上的 value_counts()
(18, 25] 5
(25, 35] 3
(35, 60] 3
(60, 100] 1
Name: count, dtype: int64
pd.value_counts(categorical)
提供 pd.cut()
结果的箱计数。圆括号 ()
表示该侧是开的 (不包含)。
方括号 []
表示该侧是闭的 (包含)。
(18, 25]
表示 “大于 18,小于等于 25”。
[[18, 25), [18, 25), [25, 35), [25, 35), [18, 25), ..., [25, 35), [60, 100), [35, 60), [35, 60), [25, 35)]
Length: 12
Categories (4, interval[int64, left]): [[18, 25) < [25, 35) < [35, 60) < [60, 100)]
right=False
更改区间的闭合侧。group_names = ["Youth", "YoungAdult", "MiddleAged", "Senior"] # 定义箱的标签
pd.cut(ages, bins, labels=group_names) # 使用 labels 参数为箱指定自定义名称
['Youth', 'Youth', 'Youth', 'YoungAdult', 'Youth', ..., 'YoungAdult', 'Senior', 'MiddleAged', 'MiddleAged', 'YoungAdult']
Length: 12
Categories (4, object): ['Youth' < 'YoungAdult' < 'MiddleAged' < 'Senior']
labels
参数为箱分配自定义名称。
比默认的区间标签更具信息量。
pd.cut()
data = np.random.uniform(size=20) # 生成 20 个均匀分布的随机数
pd.cut(data, 4, precision=2) # 将数据分成 4 个等长的箱,并设置精度为 2
[(0.024, 0.25], (0.25, 0.48], (0.024, 0.25], (0.48, 0.7], (0.024, 0.25], ..., (0.7, 0.93], (0.48, 0.7], (0.024, 0.25], (0.48, 0.7], (0.024, 0.25]]
Length: 20
Categories (4, interval[float64, right]): [(0.024, 0.25] < (0.25, 0.48] < (0.48, 0.7] < (0.7, 0.93]]
将整数个箱传递给 pd.cut()
以根据最小值/最大值计算等长的箱。
precision
限制箱标签的小数精度。
pd.qcut()
data = np.random.standard_normal(1000) # 生成 1000 个标准正态分布的随机数
quartiles = pd.qcut(data, 4, precision=2) # 将数据分成四分位数,并设置精度为 2
quartiles # 显示分箱结果
[(-2.5399999999999996, -0.67], (-0.67, -0.025], (-2.5399999999999996, -0.67], (0.68, 2.99], (0.68, 2.99], ..., (0.68, 2.99], (0.68, 2.99], (-0.67, -0.025], (0.68, 2.99], (-0.025, 0.68]]
Length: 1000
Categories (4, interval[float64, right]): [(-2.5399999999999996, -0.67] < (-0.67, -0.025] < (-0.025, 0.68] < (0.68, 2.99]]
pd.qcut()
根据样本分位数对数据进行分箱。
旨在实现 (大致) 等大小的箱。
对于将数据划分为百分位数很有用。
pd.qcut()
(-2.533, -1.256] 100
(-1.256, -0.0252] 400
(-0.0252, 1.348] 400
(1.348, 2.99] 100
Name: count, dtype: int64
将自定义分位数 (0 到 1 之间的值) 传递给 pd.qcut()
。
示例:划分为十分位数 (0.1, 0.2, …, 0.9)。
data = pd.DataFrame(np.random.standard_normal((1000, 4))) # 创建一个包含 1000 行 4 列标准正态分布随机数的 DataFrame
data.describe() # 查看 DataFrame 的描述性统计信息
0 | 1 | 2 | 3 | |
---|---|---|---|---|
count | 1000.000000 | 1000.000000 | 1000.000000 | 1000.000000 |
mean | -0.033774 | -0.024787 | 0.027211 | 0.024319 |
std | 0.956820 | 1.012375 | 0.989203 | 0.993449 |
min | -2.869215 | -2.929614 | -3.073605 | -2.907722 |
25% | -0.702000 | -0.718696 | -0.639898 | -0.624963 |
50% | 0.003633 | -0.065578 | 0.013694 | 0.018920 |
75% | 0.586702 | 0.631996 | 0.719782 | 0.677345 |
max | 2.556781 | 3.642657 | 3.187902 | 3.369092 |
3 3.187902
437 3.023239
598 -3.073605
Name: 2, dtype: float64
0 | 1 | 2 | 3 | |
---|---|---|---|---|
3 | -0.768591 | 1.937355 | 3.187902 | 1.261522 |
316 | 1.333864 | 3.642657 | -0.745132 | 0.007678 |
353 | -0.980655 | 1.150037 | -1.778249 | 3.369092 |
390 | 2.341333 | 1.519942 | 0.909764 | 3.027019 |
437 | 1.060555 | -0.875986 | 3.023239 | -0.053622 |
598 | 0.513292 | -0.148589 | -3.073605 | -0.691570 |
data.abs() > 3
: 布尔 DataFrame,指示超过 3 或 -3 的值。
any(axis="columns")
: 检查一行中是否任何值为 True
。
选择包含至少一个异常值的行。
data[data.abs() > 3] = np.sign(data) * 3 # 将绝对值大于 3 的值限制为 -3 或 3
data.describe() # 查看 DataFrame 的描述性统计信息
0 | 1 | 2 | 3 | |
---|---|---|---|---|
count | 1000.000000 | 1000.000000 | 1000.000000 | 1000.000000 |
mean | -0.033774 | -0.025429 | 0.027074 | 0.023922 |
std | 0.956820 | 1.010246 | 0.988321 | 0.992192 |
min | -2.869215 | -2.929614 | -3.000000 | -2.907722 |
25% | -0.702000 | -0.718696 | -0.639898 | -0.624963 |
50% | 0.003633 | -0.065578 | 0.013694 | 0.018920 |
75% | 0.586702 | 0.631996 | 0.719782 | 0.677345 |
max | 2.556781 | 3.000000 | 3.000000 | 3.000000 |
np.sign(data)
: 对于负值返回 -1,对于正值返回 1。
将超出 [-3, 3] 区间的值限制为 -3 和 3。
排列 (随机重新排序) 行或列。
选择数据的随机子集。
0 | 1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|---|
0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
1 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
2 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
3 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
4 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
permutation()
排列行 (第 1 部分)permutation()
排列行 (第 2 部分)0 | 1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|---|
1 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
3 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
2 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
4 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
np.random.permutation(n)
生成一个从 0 到 n-1 的整数的随机排列。
take()
或 iloc[]
可以与排列一起使用以对行进行重新排序。
1 | 2 | 6 | 4 | 3 | 0 | 5 | |
---|---|---|---|---|---|---|---|
0 | 1 | 2 | 6 | 4 | 3 | 0 | 5 |
1 | 8 | 9 | 13 | 11 | 10 | 7 | 12 |
2 | 15 | 16 | 20 | 18 | 17 | 14 | 19 |
3 | 22 | 23 | 27 | 25 | 24 | 21 | 26 |
4 | 29 | 30 | 34 | 32 | 31 | 28 | 33 |
axis="columns"
与 take()
一起使用。0 | 1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|---|
0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
2 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
3 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
sample(n=k)
选择 k
个随机行,不放回。choices = pd.Series([5, 7, -1, 6, 4]) # 创建一个 Series
choices.sample(n=10, replace=True) # 使用 .sample(n=10, replace=True) 随机选择 10 个元素 (有放回)
2 -1
1 7
1 7
1 7
1 7
0 5
4 4
3 6
1 7
3 6
dtype: int64
replace=True
允许有放回采样 (同一行可以被多次选择)。将分类变量转换为 “虚拟” 或 “指标” 矩阵。
用于统计建模和机器学习。
df = pd.DataFrame({"key": ["b", "b", "a", "c", "a", "b"],
"data1": range(6)}) # 创建一个包含分类变量 "key" 的 DataFrame
df # 显示 DataFrame
key | data1 | |
---|---|---|
0 | b | 0 |
1 | b | 1 |
2 | a | 2 |
3 | c | 3 |
4 | a | 4 |
5 | b | 5 |
get_dummies()
a | b | c | |
---|---|---|---|
0 | False | True | False |
1 | False | True | False |
2 | True | False | False |
3 | False | False | True |
4 | True | False | False |
5 | False | True | False |
pd.get_dummies(categorical_column)
创建一个 DataFrame,其中:
dummies = pd.get_dummies(df["key"], prefix="key") # 使用 prefix 参数为虚拟变量的列名添加前缀
df_with_dummy = df[["data1"]].join(dummies) # 将虚拟变量与原始 DataFrame 连接
df_with_dummy # 显示结果 DataFrame
data1 | key_a | key_b | key_c | |
---|---|---|---|---|
0 | 0 | False | True | False |
1 | 1 | False | True | False |
2 | 2 | True | False | False |
3 | 3 | False | False | True |
4 | 4 | True | False | False |
5 | 5 | False | True | False |
prefix
参数为虚拟变量列名添加前缀。
与原始 DataFrame 连接时很有用。
mnames = ["movie_id", "title", "genres"] # 定义列名
movies = pd.read_table("datasets/movielens/movies.dat", sep="::",
header=None, names=mnames, engine="python") # 读取 MovieLens 数据集,分隔符为 "::"
movies[:10] # 显示前 10 行数据
movie_id | title | genres | |
---|---|---|---|
0 | 1 | Toy Story (1995) | Animation|Children's|Comedy |
1 | 2 | Jumanji (1995) | Adventure|Children's|Fantasy |
2 | 3 | Grumpier Old Men (1995) | Comedy|Romance |
3 | 4 | Waiting to Exhale (1995) | Comedy|Drama |
4 | 5 | Father of the Bride Part II (1995) | Comedy |
5 | 6 | Heat (1995) | Action|Crime|Thriller |
6 | 7 | Sabrina (1995) | Comedy|Romance |
7 | 8 | Tom and Huck (1995) | Adventure|Children's |
8 | 9 | Sudden Death (1995) | Action |
9 | 10 | GoldenEye (1995) | Action|Adventure|Thriller |
str.get_dummies()
用于多个类别dummies = movies["genres"].str.get_dummies("|") # 使用 str.get_dummies("|") 处理多个类别,分隔符为 "|"
dummies.iloc[:10, :6] # 显示前 10 行和前 6 列
Action | Adventure | Animation | Children's | Comedy | Crime | |
---|---|---|---|---|---|---|
0 | 0 | 0 | 1 | 1 | 1 | 0 |
1 | 0 | 1 | 0 | 1 | 0 | 0 |
2 | 0 | 0 | 0 | 0 | 1 | 0 |
3 | 0 | 0 | 0 | 0 | 1 | 0 |
4 | 0 | 0 | 0 | 0 | 1 | 0 |
5 | 1 | 0 | 0 | 0 | 0 | 1 |
6 | 0 | 0 | 0 | 0 | 1 | 0 |
7 | 0 | 1 | 0 | 1 | 0 | 0 |
8 | 1 | 0 | 0 | 0 | 0 | 0 |
9 | 1 | 1 | 0 | 0 | 0 | 0 |
str.get_dummies(separator)
处理由分隔符分隔的多个类别。movies_windic = movies.join(dummies.add_prefix("Genre_")) # 将虚拟变量与原始 DataFrame 连接,并为虚拟变量列名添加前缀
movies_windic.iloc[0] # 显示结果 DataFrame 的第一行
movie_id 1
title Toy Story (1995)
genres Animation|Children's|Comedy
Genre_Action 0
Genre_Adventure 0
Genre_Animation 1
Genre_Children's 1
Genre_Comedy 1
Genre_Crime 0
Genre_Documentary 0
Genre_Drama 0
Genre_Fantasy 0
Genre_Film-Noir 0
Genre_Horror 0
Genre_Musical 0
Genre_Mystery 0
Genre_Romance 0
Genre_Sci-Fi 0
Genre_Thriller 0
Genre_War 0
Genre_Western 0
Name: 0, dtype: object
add_prefix()
为虚拟变量列添加前缀。join()
将虚拟变量与原始 DataFrame 组合。get_dummies()
和 cut()
(第 1 部分)get_dummies()
和 cut()
(第 2 部分)(0.0, 0.2] | (0.2, 0.4] | (0.4, 0.6] | (0.6, 0.8] | (0.8, 1.0] | |
---|---|---|---|---|---|
0 | False | False | False | False | True |
1 | False | True | False | False | False |
2 | True | False | False | False | False |
3 | False | True | False | False | False |
4 | False | False | True | False | False |
5 | False | False | True | False | False |
6 | False | False | False | False | True |
7 | False | False | False | True | False |
8 | False | False | False | True | False |
9 | False | False | False | True | False |
统计应用的一个技巧:将 get_dummies()
与离散化函数 (如 cut()
) 结合使用。
为每个箱创建指标变量。
0 1.0
1 2.0
2 3.0
3 NaN
dtype: float64
float64
。Int64Dtype
(第 1 部分)Int64Dtype
(第 2 部分)pd.Int64Dtype()
(或 "Int64"
) 创建一个具有正确 NA 处理的整数 Series。
使用 <NA>
表示缺失值 (pandas.NA 标记值)。
s = pd.Series(['one', 'two', None, 'three'], dtype=pd.StringDtype()) # 使用 pd.StringDtype() 创建一个专门的字符串 Series
s # 显示 Series
0 one
1 two
2 <NA>
3 three
dtype: string
pd.StringDtype()
创建一个专门的字符串数据类型。pyarrow
库。astype()
(第 1 部分)astype()
(第 2 部分)df["A"] = df["A"].astype("Int64") # 将 "A" 列转换为可空整数类型
df["B"] = df["B"].astype("string") # 将 "B" 列转换为专门的字符串类型
df["C"] = df["C"].astype("boolean") # 将 "C" 列转换为可空布尔类型
df # 显示 DataFrame
A | B | C | |
---|---|---|---|
0 | 1 | one | False |
1 | 2 | two | <NA> |
2 | <NA> | three | False |
3 | 4 | <NA> | True |
扩展类型 | 描述 |
---|---|
BooleanDtype |
可空布尔数据,作为字符串传递时使用 "boolean" |
CategoricalDtype |
分类数据类型,作为字符串传递时使用 "category" |
DatetimeTZDtype |
带时区的日期时间 |
Float32Dtype |
32 位可空浮点数,作为字符串传递时使用 "Float32" |
Float64Dtype |
64 位可空浮点数,作为字符串传递时使用 "Float64" |
Int8Dtype |
8 位可空有符号整数,作为字符串传递时使用 "Int8" |
Int16Dtype |
16 位可空有符号整数,作为字符串传递时使用 "Int16" |
Int32Dtype |
32 位可空有符号整数,作为字符串传递时使用 "Int32" |
Int64Dtype |
64 位可空有符号整数,作为字符串传递时使用 "Int64" |
UInt8Dtype |
8 位可空无符号整数,作为字符串传递时使用 "UInt8" |
UInt16Dtype |
16 位可空无符号整数,作为字符串传递时使用 "UInt16" |
UInt32Dtype |
32 位可空无符号整数,作为字符串传递时使用 "UInt32" |
UInt64Dtype |
64 位可空无符号整数,作为字符串传递时使用 "UInt64" |
Python 因其字符串/文本处理能力而广受欢迎。
字符串对象方法通常就足够了。
正则表达式 (regex) 提供了更强大的功能。
Pandas 将这些功能结合起来,并优雅地处理缺失数据。
['a', 'b', ' guido']
split()
: 根据分隔符将字符串拆分为子字符串列表。['a', 'b', 'guido']
strip()
: 删除前导/尾随空格。通常与 split()
一起使用。join()
: 使用分隔符连接字符串的一种更 Pythonic 的方式。in
: 检查子字符串是否存在的最佳方法。
index()
: 查找子字符串的第一次出现的索引;如果未找到则引发错误。
find()
: 类似于 index()
,但如果未找到则返回 -1。
count()
和 replace()
(第 1 部分)count()
和 replace()
(第 2 部分)count()
: 计算子字符串出现的次数。replace()
: 将一个模式的出现替换为另一个模式。方法 | 描述 |
---|---|
count |
返回字符串中子字符串的不重叠出现次数 |
endswith |
如果字符串以指定后缀结尾,则返回 True |
startswith |
如果字符串以指定前缀开头,则返回 True |
join |
使用字符串作为分隔符连接其他字符串序列 |
index |
返回传递的子字符串在字符串中第一次出现的起始索引;如果未找到,则引发 ValueError 异常 |
find |
返回字符串中子字符串第一次出现的第一个字符的位置;类似于 index,但如果未找到则返回 -1 |
rfind |
返回字符串中子字符串最后一次出现的第一个字符的位置;如果未找到则返回 -1 |
replace |
将字符串的出现替换为另一个字符串 |
strip |
修剪两侧的空白字符,包括换行符 |
rstrip |
修剪右侧的空白字符 |
方法 | 描述 |
---|---|
lstrip |
修剪左侧的空白字符 |
split |
使用传递的分隔符将字符串拆分为子字符串列表 |
lower |
将字母字符转换为小写 |
upper |
将字母字符转换为大写 |
casefold |
将字符转换为小写,处理特定于区域的变体 |
ljust |
左对齐;使用空格 (或其他填充字符) 填充右侧 |
rjust |
右对齐;使用空格 (或其他填充字符) 填充左侧 |
正则表达式 (regex) 提供了一种强大的方法来搜索、匹配和操作文本模式。
Python 的内置 re
模块处理正则表达式。
正则表达式函数分为三类:
import re # 导入 re 模块
text = "foo bar\t baz \tqux" # 定义一个包含不同空白字符分隔的字符串
re.split(r"\s+", text) # 使用 re.split() 和正则表达式 "\s+" 将字符串拆分为列表,"\s+" 匹配一个或多个空白字符
['foo', 'bar', 'baz', 'qux']
\s+
: 一个或多个空白字符的正则表达式。
re.split(pattern, text)
: 根据正则表达式模式拆分文本。
regex = re.compile(r"\s+") # 使用 re.compile() 编译正则表达式,创建一个可重用的正则表达式对象
regex.split(text) # 使用编译后的正则表达式对象拆分文本
['foo', 'bar', 'baz', 'qux']
re.compile(pattern)
: 将正则表达式编译为可重用的正则表达式对象。
如果您将对多个字符串应用相同的正则表达式,则建议使用 (节省 CPU 周期)。
findall()
findall()
: 返回字符串中所有不重叠的模式匹配项的列表。text = """Dave [email protected]
Steve [email protected]
Rob [email protected]
Ryan [email protected]""" # 定义一个包含多个电子邮件地址的字符串
pattern = r"[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}" # 用于匹配电子邮件地址的基本正则表达式
# re.IGNORECASE 使正则表达式不区分大小写
regex = re.compile(pattern, flags=re.IGNORECASE) # 编译正则表达式,并设置 re.IGNORECASE 标志以忽略大小写
一个更复杂的正则表达式来匹配电子邮件地址。
re.IGNORECASE
标志使匹配不区分大小写。
findall()
findall()
返回所有匹配的电子邮件地址的列表。search()
(第 1 部分)<re.Match object; span=(5, 20), match='[email protected]'>
search()
(第 2 部分)search()
: 返回字符串中第一个匹配项的匹配对象。
匹配对象提供匹配的开始和结束位置。
regex.match()
返回 None
。
sub()
Dave REDACTED
Steve REDACTED
Rob REDACTED
Ryan REDACTED
sub(replacement, text)
: 返回一个新字符串,其中模式的出现被 replacement
字符串替换。pattern = r"([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\.([A-Z]{2,4})" # 带有捕获组的正则表达式
regex = re.compile(pattern, flags=re.IGNORECASE) # 编译正则表达式,并设置 re.IGNORECASE 标志
m = regex.match("[email protected]") # 使用 .match() 方法匹配字符串的开头
m.groups() # 使用 .groups() 方法获取捕获组的内容
('wesm', 'bright', 'net')
()
定义捕获组。groups()
方法返回一个包含捕获组内容的元组。findall()
[('dave', 'google', 'com'),
('steve', 'gmail', 'com'),
('rob', 'gmail', 'com'),
('ryan', 'yahoo', 'com')]
findall()
返回一个元组列表,其中每个元组包含捕获组。sub()
Dave Username: dave, Domain: google, Suffix: com
Steve Username: steve, Domain: gmail, Suffix: com
Rob Username: rob, Domain: gmail, Suffix: com
Ryan Username: ryan, Domain: yahoo, Suffix: com
sub()
中,\1
、\2
等引用捕获组 (反向引用)。方法 | 描述 |
---|---|
findall |
以列表形式返回字符串中所有不重叠的匹配模式 |
finditer |
类似于 findall ,但返回一个迭代器 |
match |
匹配字符串开头的模式,并可选择将模式组件分段到组中;如果模式匹配,则返回一个匹配对象,否则返回 None |
search |
扫描字符串以查找与模式匹配的子字符串,如果找到则返回一个匹配对象;与 match 不同,匹配可以在字符串中的任何位置 |
split |
在模式的每次出现处将字符串拆分为多个片段 |
sub , subn |
将字符串中模式的所有出现 (sub ) 或前 n 次出现 (subn ) 替换为替换表达式;使用符号 \1 、\2 等 |
Pandas 将字符串操作扩展到 Series 和 DataFrame。
优雅地处理缺失数据。
data = {"Dave": "[email protected]", "Steve": "[email protected]",
"Rob": "[email protected]", "Wes": np.nan} # 创建一个包含电子邮件地址和缺失值的字典
data = pd.Series(data) # 将字典转换为 Series
data # 显示 Series
Dave [email protected]
Steve [email protected]
Rob [email protected]
Wes NaN
dtype: object
str
访问器Dave False
Steve True
Rob True
Wes NaN
dtype: object
Series 有一个 str
属性,提供对字符串方法的访问。
这些方法会跳过并传播 NA 值。
str.contains()
str.contains(substring)
: 检查每个字符串是否包含给定的子字符串。
返回一个布尔 Series。
str
方法一起使用pattern = r"([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\.([A-Z]{2,4})" # 定义用于匹配电子邮件地址的正则表达式
data.str.findall(pattern, flags=re.IGNORECASE) # 将正则表达式与 .str.findall() 方法一起使用,并设置 re.IGNORECASE 标志
Dave [(dave, google, com)]
Steve [(steve, gmail, com)]
Rob [(rob, gmail, com)]
Wes NaN
dtype: object
str
方法一起使用。flags
(如 re.IGNORECASE
)。str.get(i)
或索引到 str
属性 (str[i]
)。str.extract()
0 | 1 | 2 | |
---|---|---|---|
Dave | dave | com | |
Steve | steve | gmail | com |
Rob | rob | gmail | com |
Wes | NaN | NaN | NaN |
str.extract(pattern)
: 返回一个 DataFrame,其中正则表达式中的每个捕获组都成为一列。Series
字符串方法部分列表 - 总结方法 | 描述 |
---|---|
cat |
使用可选的分隔符逐元素连接字符串 |
contains |
如果每个字符串都包含模式/正则表达式,则返回布尔数组 |
count |
计算模式 |
extract |
使用带有组的正则表达式从字符串 Series 中提取一个或多个字符串;结果将是一个 DataFrame,每个组一列 |
endswith |
等效于对每个元素执行 x.endswith(pattern) |
startswith |
等效于对每个元素执行 x.startswith(pattern) |
findall |
计算每个字符串的所有模式/正则表达式匹配项的列表 |
get |
索引到每个元素 (检索第 i 个元素) |
isalnum |
等效于内置的 str.isalnum |
isalpha |
等效于内置的 str.isalpha |
isdecimal |
等效于内置的 str.isdecimal |
isdigit |
等效于内置的 str.isdigit |
islower |
等效于内置的 str.islower |
isnumeric |
等效于内置的 str.isnumeric |
isupper |
等效于内置的 str.isupper |
join |
使用传递的分隔符连接 Series 中每个元素中的字符串 |
len |
计算每个字符串的长度 |
lower, upper |
转换大小写;等效于对每个元素执行 x.lower() 或 x.upper() |
match |
对每个元素使用 re.match 和传递的正则表达式,返回 True 或 False 表示是否匹配 |
pad |
在字符串的左侧、右侧或两侧添加空白字符 |
center |
等效于 pad(side="both") |
repeat |
复制值 (例如,s.str.repeat(3) 等效于对每个字符串执行 x * 3 ) |
replace |
将模式/正则表达式的出现替换为其他字符串 |
slice |
对 Series 中的每个字符串进行切片 |
split |
使用分隔符或正则表达式拆分字符串 |
strip |
修剪两侧的空白字符,包括换行符 |
rstrip |
修剪右侧的空白字符 |
lstrip |
修剪左侧的空白字符 |
介绍 pandas Categorical
类型。
提高某些 pandas 操作的性能和内存使用。
对统计和机器学习应用有用。
列通常包含一组较小的不同值的重复实例。
维度表是数据仓库中的一种常用技术。
更高效的存储和计算。
values
: 引用维度表的整数键。
dim
: 包含不同值的维度表。
take()
恢复原始数据0 apple
1 orange
0 apple
0 apple
0 apple
1 orange
0 apple
0 apple
dtype: object
take()
方法可用于恢复原始字符串 Series。分类或字典编码表示:使用整数表示具有重复值的数据。
类别、字典或级别:不同值的数组。
类别代码或代码:引用类别的整数值。
显著提高分析性能。
在保持代码不变的情况下对类别进行转换。
Categorical
扩展类型 (第 1 部分)fruits = ['apple', 'orange', 'apple', 'apple'] * 2 # 创建一个水果列表
N = len(fruits) # 计算列表长度
rng = np.random.default_rng(seed=12345) # 创建一个随机数生成器,并设置种子以确保结果可重复
df = pd.DataFrame({'fruit': fruits,
'basket_id': np.arange(N),
'count': rng.integers(3, 15, size=N),
'weight': rng.uniform(0, 4, size=N)},
columns=['basket_id', 'fruit', 'count', 'weight']) # 创建一个 DataFrame
df # 显示 DataFrame
basket_id | fruit | count | weight | |
---|---|---|---|---|
0 | 0 | apple | 11 | 1.564438 |
1 | 1 | orange | 5 | 1.331256 |
2 | 2 | apple | 12 | 2.393235 |
3 | 3 | apple | 6 | 0.746937 |
4 | 4 | apple | 5 | 2.691024 |
5 | 5 | orange | 12 | 3.767211 |
6 | 6 | apple | 10 | 0.992983 |
7 | 7 | apple | 11 | 3.795525 |
fruit_cat = df['fruit'].astype('category') # 使用 .astype('category') 将 "fruit" 列转换为 Categorical 类型
fruit_cat # 显示转换后的 Series
0 apple
1 orange
2 apple
3 apple
4 apple
5 orange
6 apple
7 apple
Name: fruit, dtype: category
Categories (2, object): ['apple', 'orange']
astype('category')
: 将列转换为 Categorical
类型。Categorical
对象pandas.core.arrays.categorical.Categorical
.array
属性访问底层的 Categorical
对象。categories
和 codes
属性 (第 1 部分)categories
: 不同值。categories
和 codes
属性 (第 2 部分)codes
: 表示每个值类别的整数代码。df['fruit'] = df['fruit'].astype('category') # 将 DataFrame 的 "fruit" 列转换为 Categorical 类型
df["fruit"] # 显示转换后的列
0 apple
1 orange
2 apple
3 apple
4 apple
5 orange
6 apple
7 apple
Name: fruit, dtype: category
Categories (2, object): ['apple', 'orange']
astype('category')
的结果,将 DataFrame 列转换为分类。Categorical
my_categories = pd.Categorical(['foo', 'bar', 'baz', 'foo', 'bar']) # 直接从 Python 序列创建 Categorical 对象
my_categories # 显示 Categorical 对象
['foo', 'bar', 'baz', 'foo', 'bar']
Categories (3, object): ['bar', 'baz', 'foo']
Categorical
对象。from_codes()
构造函数categories = ['foo', 'bar', 'baz'] # 定义类别
codes = [0, 1, 2, 0, 0, 1] # 定义代码
my_cats_2 = pd.Categorical.from_codes(codes, categories) # 使用 .from_codes() 构造函数从代码和类别创建 Categorical 对象
my_cats_2 # 显示 Categorical 对象
['foo', 'bar', 'baz', 'foo', 'foo', 'bar']
Categories (3, object): ['foo', 'bar', 'baz']
from_codes(codes, categories)
: 从现有代码和类别创建 Categorical
。['foo', 'bar', 'baz', 'foo', 'foo', 'bar']
Categories (3, object): ['foo' < 'bar' < 'baz']
ordered=True
: 指示类别具有有意义的顺序。
默认情况下,类别是无序的。
使用 Categorical
的行为通常与非编码版本 (例如,字符串数组) 相同。
某些 pandas 函数 (如 groupby
) 在使用分类时性能更好。
qcut()
和 Categorical (第 1 部分)[(-3.121, -0.675], (0.687, 3.211], (-3.121, -0.675], (-0.675, 0.0134], (-0.675, 0.0134], ..., (0.0134, 0.687], (0.0134, 0.687], (-0.675, 0.0134], (0.0134, 0.687], (-0.675, 0.0134]]
Length: 1000
Categories (4, interval[float64, right]): [(-3.121, -0.675] < (-0.675, 0.0134] < (0.0134, 0.687] < (0.687, 3.211]]
qcut()
和 Categorical (第 2 部分)bins = pd.qcut(draws, 4, labels=['Q1', 'Q2', 'Q3', 'Q4']) # 使用 labels 参数为四分位数添加标签
bins # 显示带有标签的分箱结果
['Q1', 'Q4', 'Q1', 'Q2', 'Q2', ..., 'Q3', 'Q3', 'Q2', 'Q3', 'Q2']
Length: 1000
Categories (4, object): ['Q1' < 'Q2' < 'Q3' < 'Q4']
pd.qcut()
返回一个 Categorical
对象。
labels
参数用于提供名称。
groupby()
(第 1 部分)bins = pd.Series(bins, name='quartile') # 将分箱结果转换为 Series,并命名为 "quartile"
results = (pd.Series(draws) # 将原始数据转换为 Series
.groupby(bins) # 使用分箱结果进行分组
.agg(['count', 'min', 'max']) # 对每个分组计算数量、最小值和最大值
.reset_index()) # 重置索引
results # 显示结果
quartile | count | min | max | |
---|---|---|---|---|
0 | Q1 | 250 | -3.119609 | -0.678494 |
1 | Q2 | 250 | -0.673305 | 0.008009 |
2 | Q3 | 250 | 0.018753 | 0.686183 |
3 | Q4 | 250 | 0.688282 | 3.211418 |
groupby()
(第 2 部分)0 Q1
1 Q2
2 Q3
3 Q4
Name: quartile, dtype: category
Categories (4, object): ['Q1' < 'Q2' < 'Q3' < 'Q4']
包含分类数据的 Series 具有特殊方法 (类似于 Series.str
)。
通过 cat
访问器访问。
cat
访问器Index(['a', 'b', 'c', 'd'], dtype='object')
cat
访问器提供对分类方法和属性的访问。set_categories()
actual_categories = ['a', 'b', 'c', 'd', 'e'] # 定义新的类别
cat_s2 = cat_s.cat.set_categories(actual_categories) # 使用 .cat.set_categories() 方法设置新的类别
cat_s2 # 显示新的 Categorical Series
0 a
1 b
2 c
3 d
4 a
5 b
6 c
7 d
dtype: category
Categories (5, object): ['a', 'b', 'c', 'd', 'e']
set_categories()
: 更改类别集。
当数据不包含所有可能的类别时很有用。
set_categories()
的 value_counts()
a 2
b 2
c 2
d 2
e 0
Name: count, dtype: int64
value_counts()
尊重定义的类别,即使某些类别在数据中不存在。remove_unused_categories()
0 a
1 b
4 a
5 b
dtype: category
Categories (4, object): ['a', 'b', 'c', 'd']
0 a
1 b
4 a
5 b
dtype: category
Categories (2, object): ['a', 'b']
remove_unused_categories()
: 删除数据中未出现的类别。方法 | 描述 |
---|---|
add_categories |
在现有类别末尾追加新的 (未使用的) 类别 |
as_ordered |
将类别设置为有序 |
as_unordered |
将类别设置为无序 |
remove_categories |
删除类别,将所有已删除的值设置为 null |
remove_unused_categories |
删除数据中未出现的任何类别值 |
rename_categories |
使用指定的新类别名称集替换类别;不能更改类别的数量 |
reorder_categories |
类似于 rename_categories ,但也可以更改结果以使类别有序 |
set_categories |
使用指定的新类别集替换类别;可以添加或删除类别 |
cat_s = pd.Series(['a', 'b', 'c', 'd'] * 2, dtype='category') # 创建一个 Categorical Series
pd.get_dummies(cat_s) # 使用 pd.get_dummies() 函数将 Categorical Series 转换为虚拟变量
a | b | c | d | |
---|---|---|---|---|
0 | True | False | False | False |
1 | False | True | False | False |
2 | False | False | True | False |
3 | False | False | False | True |
4 | True | False | False | False |
5 | False | True | False | False |
6 | False | False | True | False |
7 | False | False | False | True |
pd.get_dummies(categorical_series)
创建一个包含虚拟变量的 DataFrame。NaN
、None
),包括 dropna
、fillna
、isna
和 notna
。duplicated
、drop_duplicates
)、映射值 (map
)、替换值 (replace
)、重命名索引 (rename
)、分箱 (cut
、qcut
)、异常值检测、排列、采样 (sample
) 和创建虚拟变量 (get_dummies
)。Int64Dtype
、StringDtype
、CategoricalDtype
等) 提供了对特定数据类型和缺失值的改进处理。re
模块) 和 pandas 的 str
访问器高效地进行字符串操作。Categorical
类型为具有重复值的数据提供了内存和性能优势,提供了诸如 cat.codes
、cat.categories
、set_categories
和 remove_unused_categories
之类的方法。Categorical
类型如何提高效率?您会在什么情况下选择使用 Categorical
数据?re
模块和 pandas 的 str
访问器的文档。您还能找到哪些其他有用的函数?cut()
和 qcut()
之间的权衡。您会在什么情况下使用其中一个而不是另一个?