数据排序:sort_values
与 sort_index
的灵活应用 – 程序员的优雅舞步 💃🕺
各位尊敬的程序员朋友们,大家好!我是你们的老朋友,一个在数据海洋里摸爬滚打多年的老水手。今天,我们要聊聊数据分析中的一项基本功,也是一项隐藏着无数优雅舞步的关键技巧:数据排序。具体来说,我们将深入探讨 Pandas 库中的两个明星函数:sort_values
和 sort_index
。
想象一下,你手里拿着一副扑克牌,乱七八糟地散落着。如果你想玩得溜,是不是得先整理整理,按照花色或者大小排个顺序?数据也是一样!未经排序的数据就像一盘散沙,让人摸不着头脑;而排序后的数据,则像一位训练有素的舞者,每一个动作都清晰流畅,每一个节奏都恰到好处。
那么,sort_values
和 sort_index
这两位舞者,究竟有何不同?又该如何在不同的场合下,邀请他们翩翩起舞呢? 别着急,让我们慢慢揭开这层神秘的面纱!
第一幕:sort_values
– 优雅的数值排序大师 🎭
sort_values
,顾名思义,就是根据 数值 来进行排序的。它就像一位经验丰富的选美评委,只关注选手的内在(数值),而忽略她们的外貌(索引)。
1. 基本用法:
最简单的用法,就是直接调用 sort_values()
函数。默认情况下,它会按照升序进行排列。
import pandas as pd
# 创建一个示例 DataFrame
data = {'姓名': ['张三', '李四', '王五', '赵六'],
'成绩': [85, 92, 78, 95]}
df = pd.DataFrame(data)
print("原始 DataFrame:n", df)
# 按照成绩进行升序排序
df_sorted = df.sort_values(by='成绩')
print("n按照成绩升序排序后的 DataFrame:n", df_sorted)
输出结果:
原始 DataFrame:
姓名 成绩
0 张三 85
1 李四 92
2 王五 78
3 赵六 95
按照成绩升序排序后的 DataFrame:
姓名 成绩
2 王五 78
0 张三 85
1 李四 92
3 赵六 95
注意,sort_values(by='成绩')
中的 by
参数,指定了要按照哪一列进行排序。这里,我们指定了 ‘成绩’ 这一列。
2. 降序排列:
如果你想要按照降序排列,只需要设置 ascending=False
即可。
df_sorted_desc = df.sort_values(by='成绩', ascending=False)
print("n按照成绩降序排序后的 DataFrame:n", df_sorted_desc)
输出结果:
按照成绩降序排序后的 DataFrame:
姓名 成绩
3 赵六 95
1 李四 92
0 张三 85
2 王五 78
3. 多列排序:
有时候,单凭一列数据可能无法区分出优先级,这时就需要多列排序。 想象一下,选美比赛不仅仅看颜值,还要看才艺、气质等等。sort_values
同样支持多列排序,只需要将 by
参数设置为一个列表即可。列表中的元素,按照优先级从高到低排列。
# 创建一个包含两列数值的 DataFrame
data = {'班级': ['一班', '一班', '二班', '二班'],
'成绩': [85, 92, 78, 95],
'排名': [3, 1, 4, 2]}
df = pd.DataFrame(data)
print("原始 DataFrame:n", df)
# 先按照班级升序排序,再按照成绩降序排序
df_sorted_multi = df.sort_values(by=['班级', '成绩'], ascending=[True, False])
print("n先按照班级升序,再按照成绩降序排序后的 DataFrame:n", df_sorted_multi)
输出结果:
原始 DataFrame:
班级 成绩 排名
0 一班 85 3
1 一班 92 1
2 二班 78 4
3 二班 95 2
先按照班级升序,再按照成绩降序排序后的 DataFrame:
班级 成绩 排名
1 一班 92 1
0 一班 85 3
3 二班 95 2
2 二班 78 4
注意,ascending
参数也需要是一个列表,与 by
参数一一对应。
4. 处理缺失值:
如果你的数据中包含缺失值(NaN),sort_values
默认会将缺失值放在最后面。你可以通过 na_position
参数来控制缺失值的位置。
na_position='first'
:将缺失值放在最前面。na_position='last'
:将缺失值放在最后面 (默认值)。
import numpy as np
# 创建一个包含缺失值的 DataFrame
data = {'姓名': ['张三', '李四', '王五', '赵六'],
'成绩': [85, np.nan, 78, 95]}
df = pd.DataFrame(data)
print("原始 DataFrame:n", df)
# 将缺失值放在最前面
df_sorted_na_first = df.sort_values(by='成绩', na_position='first')
print("n将缺失值放在最前面排序后的 DataFrame:n", df_sorted_na_first)
# 将缺失值放在最后面 (默认值)
df_sorted_na_last = df.sort_values(by='成绩', na_position='last')
print("n将缺失值放在最后面排序后的 DataFrame:n", df_sorted_na_last)
输出结果:
原始 DataFrame:
姓名 成绩
0 张三 85.0
1 李四 NaN
2 王五 78.0
3 赵六 95.0
将缺失值放在最前面排序后的 DataFrame:
姓名 成绩
1 李四 NaN
2 王五 78.0
0 张三 85.0
3 赵六 95.0
将缺失值放在最后面排序后的 DataFrame:
姓名 成绩
2 王五 78.0
0 张三 85.0
3 赵六 95.0
1 李四 NaN
总结一下,sort_values
的常用参数:
参数 | 描述 |
---|---|
by |
指定要排序的列名(可以是单个列名,也可以是列名列表,用于多列排序) |
axis |
指定排序的轴,0 表示按行排序(默认),1 表示按列排序(不常用) |
ascending |
指定排序方式,True 表示升序(默认),False 表示降序(可以是单个布尔值,也可以是布尔值列表,用于多列排序) |
inplace |
是否在原始 DataFrame 上进行修改,True 表示直接修改原始 DataFrame,False 表示返回一个新的 DataFrame(默认) |
kind |
指定排序算法,’quicksort’(快速排序,默认)、’mergesort’(归并排序)、’heapsort’(堆排序) |
na_position |
指定缺失值的位置,’first’ 表示放在最前面,’last’ 表示放在最后面(默认) |
ignore_index |
是否重置索引,True 表示重置索引,False 表示保留原始索引(默认),如果 inplace=True ,则该参数无效,索引始终会被重置,从 0 开始。 |
第二幕:sort_index
– 索引排序的魔法师 🧙♂️
sort_index
,顾名思义,就是根据 索引 来进行排序的。它就像一位图书馆管理员,只关心图书的编号(索引),而忽略图书的内容(数值)。
1. 基本用法:
同样,最简单的用法就是直接调用 sort_index()
函数。默认情况下,它会按照升序进行排列。
# 创建一个索引不规则的 DataFrame
data = {'姓名': ['张三', '李四', '王五', '赵六'],
'成绩': [85, 92, 78, 95]}
df = pd.DataFrame(data, index=[3, 1, 0, 2])
print("原始 DataFrame:n", df)
# 按照索引进行升序排序
df_sorted_index = df.sort_index()
print("n按照索引升序排序后的 DataFrame:n", df_sorted_index)
输出结果:
原始 DataFrame:
姓名 成绩
3 张三 85
1 李四 92
0 王五 78
2 赵六 95
按照索引升序排序后的 DataFrame:
姓名 成绩
0 王五 78
1 李四 92
2 赵六 95
3 张三 85
2. 降序排列:
与 sort_values
类似,设置 ascending=False
可以进行降序排列。
df_sorted_index_desc = df.sort_index(ascending=False)
print("n按照索引降序排序后的 DataFrame:n", df_sorted_index_desc)
输出结果:
按照索引降序排序后的 DataFrame:
姓名 成绩
3 张三 85
2 赵六 95
1 李四 92
0 王五 78
3. 处理多层索引:
sort_index
同样支持多层索引(MultiIndex)的排序。 你可以指定按照哪一层索引进行排序。
# 创建一个包含多层索引的 DataFrame
index = pd.MultiIndex.from_tuples([('A', 1), ('A', 2), ('B', 1), ('B', 2)], names=['字母', '数字'])
data = {'值': [10, 20, 30, 40]}
df = pd.DataFrame(data, index=index)
print("原始 DataFrame:n", df)
# 按照第一层索引(字母)进行排序
df_sorted_level0 = df.sort_index(level=0)
print("n按照第一层索引(字母)排序后的 DataFrame:n", df_sorted_level0)
# 按照第二层索引(数字)进行排序
df_sorted_level1 = df.sort_index(level=1)
print("n按照第二层索引(数字)排序后的 DataFrame:n", df_sorted_level1)
输出结果:
原始 DataFrame:
值
字母 数字
A 1 10
2 20
B 1 30
2 40
按照第一层索引(字母)排序后的 DataFrame:
值
字母 数字
A 1 10
2 20
B 1 30
2 40
按照第二层索引(数字)排序后的 DataFrame:
值
字母 数字
A 1 10
B 1 30
A 2 20
B 2 40
总结一下,sort_index
的常用参数:
参数 | 描述 |
---|---|
axis |
指定排序的轴,0 表示按行索引排序(默认),1 表示按列索引排序 |
level |
指定排序的层级,用于多层索引排序 |
ascending |
指定排序方式,True 表示升序(默认),False 表示降序 |
inplace |
是否在原始 DataFrame 上进行修改,True 表示直接修改原始 DataFrame,False 表示返回一个新的 DataFrame(默认) |
sort_remaining |
是否对剩余层级进行排序,True 表示进行排序(默认),False 表示不进行排序,仅对指定的 level 进行排序。 |
na_position |
指定缺失值的位置,’first’ 表示放在最前面,’last’ 表示放在最后面(默认),仅当索引包含缺失值时有效。 |
ignore_index |
是否重置索引,True 表示重置索引,False 表示保留原始索引(默认),如果 inplace=True ,则该参数无效,索引始终会被重置,从 0 开始。 |
第三幕:sort_values
与 sort_index
的爱恨情仇 💔❤️
现在,我们已经分别认识了 sort_values
和 sort_index
这两位舞者。那么,在实际应用中,我们应该如何选择呢?
简单来说:
- 如果你想根据 数值 进行排序,就选择
sort_values
。 - 如果你想根据 索引 进行排序,就选择
sort_index
。
但是,事情并没有那么简单!有时候,这两位舞者可以互相配合,共同完成更加复杂的任务。
案例分析:
假设你有一个存储用户信息的 DataFrame,其中索引是用户的 ID,数据包含用户的姓名、年龄和消费金额。
import numpy as np
# 创建一个示例 DataFrame
data = {'姓名': ['张三', '李四', '王五', '赵六', '钱七'],
'年龄': [25, 30, 28, 22, np.nan],
'消费金额': [100, 200, 150, 250, 180]}
df = pd.DataFrame(data, index=[3, 1, 0, 2, 4])
print("原始 DataFrame:n", df)
需求 1: 按照消费金额进行排序,并重置索引。
# 使用 sort_values 按照消费金额排序,并使用 ignore_index 重置索引
df_sorted_reset = df.sort_values(by='消费金额', ignore_index=True)
print("n按照消费金额排序并重置索引后的 DataFrame:n", df_sorted_reset)
这个需求很简单,直接使用 sort_values
就可以搞定。ignore_index=True
可以重置索引,使索引从 0 开始。
需求 2: 按照索引进行排序,然后按照年龄进行排序。
# 先按照索引排序
df_sorted_index = df.sort_index()
print("n按照索引排序后的 DataFrame:n", df_sorted_index)
# 再按照年龄排序
df_sorted_age = df_sorted_index.sort_values(by='年龄')
print("n按照索引排序后再按照年龄排序后的 DataFrame:n", df_sorted_age)
这个需求需要先使用 sort_index
按照索引排序,然后再使用 sort_values
按照年龄排序。
需求 3: 按照消费金额进行排序,但是要保留原始索引的顺序。
这个需求比较 tricky!我们需要先保存原始索引,然后按照消费金额排序,最后再按照原始索引排序。
# 1. 保存原始索引
original_index = df.index
# 2. 按照消费金额排序
df_sorted_value = df.sort_values(by='消费金额')
# 3. 按照原始索引排序
df_sorted_final = df_sorted_value.loc[original_index] #这里如果原始index有重复值,会报错,需要额外处理
print("n按照消费金额排序但保留原始索引顺序的 DataFrame:n", df_sorted_final)
注意事项:
inplace=True
会直接修改原始 DataFrame,因此需要谨慎使用。- 如果你的数据量非常大,选择合适的排序算法(
kind
参数)可以提高效率。 - 处理多层索引时,要仔细考虑层级的顺序和排序方式。
结语: 数据排序的艺术 🎨
数据排序不仅仅是一种技术,更是一种艺术。 通过灵活运用 sort_values
和 sort_index
,我们可以将杂乱无章的数据变成井然有序的信息,从而更好地理解数据背后的故事。
希望今天的分享能帮助大家更好地掌握数据排序的技巧,在数据分析的道路上越走越远! 🚀
记住,代码的世界也需要优雅!让我们一起用优雅的舞步,征服数据海洋吧! 🌊
最后,送给大家一句程序员的座右铭: Bug 是代码的灵魂,排序是数据的生命! 😉