pandas索引堆叠、数据合并与分组、数据离散化

一、df的索引堆叠

  • 在用pandas进行数据重排时,经常用到stack和unstack两个函数。stack的意思是堆叠,堆积,unstack即“不要堆叠”

  • 可以简单的理解为stack()将数据从表格转换为花括号(思维导图那种)格式,unstack()将数据从花括号(思维导图那种)转换为表格格式

  • 详情可以查看这里

  • 示例

data=pd.DataFrame(np.arange(12).reshape((3,4))+100,
 index=pd.Index(['date1','date2','date3']),
 columns=pd.Index(['store1','store2','store3','store4'])
 )

data2=data.stack()
data3=data2.unstack()

print(f"data:\n{data}")
print(f"data2:\n{data2}")
print(f"data3:\n{data3}")

"""
data:
       store1  store2  store3  store4
date1     100     101     102     103
date2     104     105     106     107
date3     108     109     110     111

data2:
date1  store1    100
       store2    101
       store3    102
       store4    103
date2  store1    104
       store2    105
       store3    106
       store4    107
date3  store1    108
       store2    109
       store3    110
       store4    111
dtype: int32

data3:
       store1  store2  store3  store4
date1     100     101     102     103
date2     104     105     106     107
date3     108     109     110     111
"""

二、数据合并

  • panfas共有3种合并方法:concat、merge、append
  • 最常用的说merge,其次是concat

1. concat

  • 用于沿指定轴将多个 DataFrame或 Series 对象连接在一起的函数

  • 语法:pd.concat(objs, axis=0, join='outer', ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, copy=True)

    • objs‌:要合并的 pandas 对象的列表或字典。这些对象可以是 DataFrame 或 Series。
    • axis‌:指定连接的轴,0 表示按行连接(垂直合并),1 表示按列连接(水平合并),默认为 0。
    • join‌:指定连接的方式,'outer' 表示取并集,保留所有列,缺失的数据填充为 NaN;'inner' 表示取交集,只保留两个对象都有的列。默认为 'outer'。
    • ignore_index‌:是否忽略原始索引,默认为 False。如果为 True,则不保留原来的索引,而是创建一个新的从 0 开始的索引。
    • keys‌:用于创建多级索引的键,可以是任何可哈希的值。
    • levels‌ 和 ‌names‌:用于构建层次化索引的特定级别和名称。
    • verify_integrity‌:是否检查新连接的轴是否包含重复项,默认为 False。
    • copy‌:是否复制数据,默认为 True。如果为 False,则不进行不必要的复制

(1)简单级联合并

pd.concat([df1, df2]) # 上下合并,垂直合并,效果同numpy中的numpy.vstack()
pd.concat([df1, df2], axis=1)  # 左右合并,水平合并。效果同numpy.hstack()
pd.concat([df1, df2], ignore_index=True)  # 忽略行索引,合并后重置行索引
pd.concat([df1, df2], keys=['x', 'y'])  # 使用多层索引 keys 

(2)不匹配级联

pd.concat([df3, df4]) # 对应索引没有值的会自动用NaN填充

pd.concat([df3, df4], join='outer') # join的默认值为 outer,取并集, 所有数据都会显示,缺失则补NaN

pd.concat([df3, df4], join='inner')# 内连接:只连接匹配的项, 交集, 只显示共同的            

(3)示例

df1 = pd.DataFrame({'A': [1, 2, 3,4]}, index=['a', 'b', 'c','d'])
df2 = pd.DataFrame({'B': [4, 5, 6]}, index=['a', 'b', 'd'])
result1 = pd.concat([df1, df2])
result2 = pd.concat([df1, df2],ignore_index=True)
result3 = pd.concat([df1, df2], axis=1)
result4 = pd.concat([df1, df2], axis=1,ignore_index=True)

print("df1:\n{}".format(df1))
print("df2:\n{}".format(df2))
print("result1:\n{}".format(result1))
print("result2:\n{}".format(result2))
print("result3:\n{}".format(result3))
print("result4:\n{}".format(result4))

"""
df1:
   A
a  1
b  2
c  3
d  4
df2:
   B
a  4
b  5
d  6
result1:
     A    B
a  1.0  NaN
b  2.0  NaN
c  3.0  NaN
d  4.0  NaN
a  NaN  4.0
b  NaN  5.0
d  NaN  6.0
result2:
     A    B
0  1.0  NaN
1  2.0  NaN
2  3.0  NaN
3  4.0  NaN
4  NaN  4.0
5  NaN  5.0
6  NaN  6.0
result3:
   A    B
a  1  4.0
b  2  5.0
c  3  NaN
d  4  6.0
result4:
   0    1
a  1  4.0
b  2  5.0
c  3  NaN
d  4  6.0
"""

2. merge

  • pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,left_index=False,right_index=False, sort=True,suffixes=('_x', '_y'), copy=True,indicator=False,validate=None)
  • df.merge(right, how='inner', on=None, left_on=None, right_on=None,left_index=False, right_index=False, sort=True,suffixes=('_x', '_y'), copy=True, indicator=False, validate=None)
  • df.merge()相比pd.merge()只是将left变成了df,其他参数都不变
  • 参数说明:
    • left: 拼接的左侧DataFrame对象
    • right: 拼接的右侧DataFrame对象
    • on: 合并时要参照的列或索引级别名称。 必须在左侧和右侧DataFrame对象中都能找到。 如果未传递且left_index和right_index为False,则DataFrame中的列的交集将被推断为连接键。作用类似SQL中的联表查询时的on
    • left_on:合并时,以左侧DataFrame中的列或索引级别用作键。 可以是列名,索引级名称,也可以是长度等于DataFrame长度的数组。
    • right_on: 合并时,以右侧DataFrame中的列或索引级别用作键。 可以是列名,索引级名称,也可以是长度等于DataFrame长度的数组。
    • left_index: 如果为True,则使用左侧DataFrame中的索引(行标签)作为其连接键。 对于具有MultiIndex(分层)的DataFrame,级别数必须与右侧DataFrame中的连接键数相匹配。
    • right_index: 与left_index功能相似。
    • how: One of ‘left’, ‘right’, ‘outer’, ‘inner’. 默认inner。inner是取交集,outer取并集。比如left:[‘A’,‘B’,‘C’];right[’’A,‘C’,‘D’];inner取交集的话,left中出现的A会和right中出现的买一个A进行匹配拼接,如果没有是B,在right中没有匹配到,则会丢失。’outer’取并集,出现的A会进行一一匹配,没有同时出现的会将缺失的部分添加缺失值。
    • sort: 参数用于控制合并后的结果是否按照连接键进行排序。默认值为False,表示不对结果进行排序。如果设置为True,则会按照连接键的字典顺序对结果进行排序。
      • sort=True时,合并后的结果会按照连接键的字典顺序进行排序。这有助于确保结果的顺序一致性,但在大数据集上可能会影响性能
      • sort=False时,结果不会进行排序,这通常可以提高处理速度,尤其是在处理大数据集时。然而,不排序可能会导致结果的顺序与预期不同
    • suffixes: 用于重叠列的字符串后缀元组。 默认为(‘x’,’ y’)。
    • copy: 始终从传递的DataFrame对象复制数据(默认为True),即使不需要重建索引也是如此。
    • indicator:将一列添加到名为_merge的输出DataFrame,其中包含有关每行源的信息。 _merge是分类类型,并且对于其合并键仅出现在“左”DataFrame中的观察值,取得值为left_only,对于其合并键仅出现在“右”DataFrame中的观察值为right_only,并且如果在两者中都找到观察点的合并键,则为left_only。

(2)普通合并示例

import pandas as pd

df1 = pd.DataFrame({'员工姓名': ['张三', '李红'], '性别': ['男', '女'], '年龄': ['20', '22'], '公司名称': ['阿里巴巴有限公司', '阿里巴巴有限公司']})
df2 = pd.DataFrame({'员工姓名': ['张三', '李红'], '性别': ['男', '女'], '年龄': ['20', '22'], '工资': [10000, 12000]})

df = pd.merge(df1, df2)  # 未指定on或者left_on、right_on,则默认按照df1和df2中所有同名的列作为匹配的key。结果:将df1中的“公司名称”和df2中“工资”都合并上了

print("df1:\n{}".format(df1))
print("df2:\n{}".format(df2))
print("df:\n{}".format(df))

"""
df1:
  员工姓名 性别  年龄      公司名称
0   张三  男  20  阿里巴巴有限公司
1   李红  女  22  阿里巴巴有限公司
df2:
  员工姓名 性别  年龄     工资
0   张三  男  20  10000
1   李红  女  22  12000
df:
  员工姓名 性别  年龄      公司名称     工资
0   张三  男  20  阿里巴巴有限公司  10000
1   李红  女  22  阿里巴巴有限公司  12000
"""

(2)on示例

# 1. 无后缀示例
left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],
                      'key2': ['K0', 'K1', 'K0', 'K1'],
                         'A': ['A0', 'A1', 'A2', 'A3'],
                         'B': ['B0', 'B1', 'B2', 'B3']})

right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
                      'key2': ['K0', 'K0', 'K0', 'K0'],
                         'C': ['C0', 'C1', 'C2', 'C3'],
                         'D': ['D0', 'D1', 'D2', 'D3']})
print(left)
print(right)
result = pd.merge(left, right, on=['key1', 'key2'])  # 没写how,默认取交集

print(result)

"""
  key1 key2   A   B
0   K0   K0  A0  B0
1   K0   K1  A1  B1
2   K1   K0  A2  B2
3   K2   K1  A3  B3

  key1 key2   C   D
0   K0   K0  C0  D0
1   K1   K0  C1  D1
2   K1   K0  C2  D2
3   K2   K0  C3  D3

  key1 key2   A   B   C   D
0   K0   K0  A0  B0  C0  D0
1   K1   K0  A2  B2  C1  D1
2   K1   K0  A2  B2  C2  D2
"""

# 分析:on=['key1', 'key2'],说明是按照key1、key2两列来取交集。left的key1、key2从上往下看,其列表组合为[['K0', 'K0'],['K0', 'K1'],['K1', 'K0'],['K2', 'K1']],right的key1、key2从上往下看,其列表组合为[['K0', 'K0'],['K1', 'K0'],['K1', 'K0'],['K2', 'K0']],所以left和right的key1、key2列表中相同的部分为 ['K0', 'K0']、['K1', 'K0'],因此合并后只有1个['K0', 'K0']、2个['K1', 'K0']共3组数据

# 2. 有后缀示例
import pandas as pd

df1 = pd.DataFrame({'员工姓名': ['张三', '李红'], '性别': ['男', '女'], '年龄': ['20', '22'], '公司名称': ['阿里巴巴有限公司', '阿里巴巴有限公司']})
df2 = pd.DataFrame({'员工姓名': ['张三', '李红'], '性别': ['男', '女'], '年龄': ['20', '22'], '工资': [10000, 12000]})

# df = pd.merge(df1, df2)
df = pd.merge (df1, df2, how ='inner', on=['性别','年龄'])  # 除了性别、年龄这两列外,df1和df2中其它同名的列,列名会自电加上后缀

print("df1:\n{}".format(df1))
print("df2:\n{}".format(df2))
print("df:\n{}".format(df))

"""
df1:
  员工姓名 性别  年龄      公司名称
0   张三  男  20  阿里巴巴有限公司
1   李红  女  22  阿里巴巴有限公司
df2:
  员工姓名 性别  年龄     工资
0   张三  男  20  10000
1   李红  女  22  12000
df:
  员工姓名_x 性别  年龄      公司名称 员工姓名_y     工资
0     张三  男  20  阿里巴巴有限公司     张三  10000
1     李红  女  22  阿里巴巴有限公司     李红  12000
"""

(3)left_on和right_on示例

  • 这两个参数通常是使用在两个DataFrame的列名都不相同,但表达意思相同。如例子中的员工姓名、姓名表达意思相同,就要用到 left_on='员工姓名' 和 right_on= '姓名'来指定匹配的列,还可以把多余的列删除掉
df1 = pd.DataFrame({'姓名': ['张三', '李红'], '性别': ['男', '女'], '年龄': ['20', '22'], '公司名称': ['阿里巴巴有限公司', '阿里巴巴有限公司']})
df2 = pd.DataFrame({'员工姓名': ['张三', '李红'], '性别': ['男', '女'], '年龄': ['20', '22'], '工资': [10000, 12000]})


df3 = pd.merge(df1, df2,left_on=['姓名'],right_on=['员工姓名'])
df4 = pd.merge(df1, df2,left_on=['姓名'],right_on=['员工姓名']).drop('员工姓名',axis=1)
print("df3:\n{}".format(df3))
print("df4:\n{}".format(df4))

"""
df1:
   姓名 性别  年龄      公司名称
0  张三  男  20  阿里巴巴有限公司
1  李红  女  22  阿里巴巴有限公司
df2:
  员工姓名 性别  年龄     工资
0   张三  男  20  10000
1   李红  女  22  12000
df3:
   姓名 性别_x 年龄_x      公司名称 员工姓名 性别_y 年龄_y     工资
0  张三    男   20  阿里巴巴有限公司   张三    男   20  10000
1  李红    女   22  阿里巴巴有限公司   李红    女   22  12000
df4:
   姓名 性别_x 年龄_x      公司名称 性别_y 年龄_y     工资
0  张三    男   20  阿里巴巴有限公司    男   20  10000
1  李红    女   22  阿里巴巴有限公司    女   22  12000
"""

(4)left_index和right_index示例

  • 这两个参数使用的场景通常是我们需要合并列并且合并index,通过设置left_index=Trueright_index=True使得键与index进行配合
df1 = pd.DataFrame({'姓名': ['张三', '李红'],
                    '公司名称': ['阿里巴巴有限公司', '阿里巴巴有限公司']})
df2 = pd.DataFrame({'员工姓名': ['张三', '李红'],
                    '工资': [10000, 12000]})
df1 = df1.set_index('姓名')
df2 = df2.set_index('员工姓名')

# 合并
df = pd.merge(df1, df2,
              left_index=True,
              right_index=True)

print("df1:\n{}".format(df1))
print("df2:\n{}".format(df2))
print("df:\n{}".format(df))

"""
df1:
        公司名称
姓名          
张三  阿里巴巴有限公司
李红  阿里巴巴有限公司
df2:
         工资
员工姓名       
张三    10000
李红    12000
df:
        公司名称     工资
姓名                 
张三  阿里巴巴有限公司  10000
李红  阿里巴巴有限公司  12000
"""

3. append

  • 用于将一个DataFrame追加到另一个DataFrame的末尾,并返回一个新的DataFrame。这个函数的主要用途是在不改变原始DataFrame的情况下,向其添加新的行数据

  • 语法:df.append(other, ignore_index=False, verify_integrity=False, sort=False)

    • other‌:要追加的数据,可以是DataFrame、Series、字典或列表。

    • ignore_index‌:是否忽略原始DataFrame的索引,默认为False。如果设置为True,则会重新生成索引。

    • verify_integrity‌:是否验证索引的完整性,默认为False。如果设置为True,且存在重复索引,则会报错。

    • sort‌:是否对列进行排序,默认为False。

(1)示例

import pandas as pd

df1 = pd.DataFrame({'姓名': ['张三', '李红'], '性别': ['男', '女'], '年龄': ['20', '22'], '公司名称': ['阿里巴巴有限公司', '阿里巴巴有限公司']})
df2 = pd.DataFrame({'员工姓名': ['张三', '李红'], '性别': ['男', '女'], '年龄': ['20', '22'], '工资': [10000, 12000]})
                   
df4 = df1.append(df2)
df5 = df1.append(df2,sort=True)
print("df1:\n{}".format(df1))
print("df2:\n{}".format(df2))
print("df4:\n{}".format(df4))
print("df5:\n{}".format(df5))

"""
df1:
   姓名 性别  年龄      公司名称
0  张三  男  20  阿里巴巴有限公司
1  李红  女  22  阿里巴巴有限公司
df2:
  员工姓名 性别  年龄     工资
0   张三  男  20  10000
1   李红  女  22  12000
df4:
    姓名 性别  年龄      公司名称 员工姓名       工资
0   张三  男  20  阿里巴巴有限公司  NaN      NaN
1   李红  女  22  阿里巴巴有限公司  NaN      NaN
0  NaN  男  20       NaN   张三  10000.0
1  NaN  女  22       NaN   李红  12000.0
df5:
       公司名称 员工姓名   姓名       工资  年龄 性别
0  阿里巴巴有限公司  NaN   张三      NaN  20  男
1  阿里巴巴有限公司  NaN   李红      NaN  22  女
0       NaN   张三  NaN  10000.0  20  男
1       NaN   李红  NaN  12000.0  22  女
"""

三、数据分组聚合

  • df.groupby(),对数据内容进行分组,一般搭配统计函数使用
  • 使用.groups属性可以查看分组情况
# 不同颜色的不同笔的价格数据
col =pd.DataFrame({'color': ['white','red','green','red','green'],
                   'object': ['pen','pencil','pencil','ashtray','pen'],
                   'price1':[5.56,4.20,1.30,0.56,2.75],
                   'price2':[4.75,4.12,1.60,0.75,3.15]})

print(col)
# 进行分组,对颜色分组
print(col.groupby(['color']).groups)
print(col.groupby(['color'])['price1'])
# 进行分组,对颜色分组后,对每组颜色的价格数据price求平均值
print(col.groupby(['color'])['price1'].mean())
print('*'*50)
# 下面这两种写法,也能实现相同的效果
print(col['price1'].groupby(col['color']).mean())
print(col.groupby(['color'],as_index=False)['price1'].mean())

"""
   color   object  price1  price2
0  white      pen    5.56    4.75
1    red   pencil    4.20    4.12
2  green   pencil    1.30    1.60
3    red  ashtray    0.56    0.75
4  green      pen    2.75    3.15

{'green': [2, 4], 'red': [1, 3], 'white': [0]}

<pandas.core.groupby.generic.SeriesGroupBy object at 0x000001E587686148>

color
green    2.025
red      2.380
white    5.560
Name: price1, dtype: float64
**************************************************
color
green    2.025
red      2.380
white    5.560
Name: price1, dtype: float64
   color  price1
0  green   2.025
1    red   2.380
2  white   5.560
"""

四、数据离散化

  • pd.cut()与pd.qcut()用于将连续数据进行离散化处理的两个重要函数,它们都能将连续元素划分为几个区间(也称为“bins”),但采用的策略有所不同
  • 使用场景和区别
    • 分箱原则‌:pd.cut()依赖于用户定义的区间边界,适合于当你事先知道想要的具体区间划分时使用;而pd.qcut()是基于数据的分布自动确定区间,确保每个区间内的样本数量大致相同,适合于探索数据分布或进行等频率分组分析。
    • 适用场景‌:如果你需要确保每个区间内的数据量均衡,比如在进行等频数的统计分析时,应使用pd.qcut();若需要根据数值的特定区间来进行分析,比如基于阈值的分类,则应使用pd.cut()。

1. pd.cut()

  • pd.cut()是基于值的等距分箱方法‌,它将数据按照指定的区间或区间个数进行分割。主要参数包括:

    • x‌:需要进行切割的序列或数组。

    • bins‌:可以是区间个数(整数)或具体的区间边界列表。

    • right‌:布尔值,默认为True,表示每个区间的右端点是闭合的,左端点是开放的。

    • include_lowest‌:布尔值,默认为False,表示区间不包括左端点的值。

    • labels‌:可选参数,用于指定每个区间的标签。

    • retbins‌:布尔值,默认为False,如果为True,函数除了返回切割后的Series,还会返回用于切割的边界值。

    • precision‌:保留小数点后的位数,默认为3。

    • duplicates‌:如何处理重叠区间,默认为'raise',意即如果有重复的区间边界会抛出错误,也可以设为'drop'来自动去除重复边界。

  • 默认情况下,每个区间包括最大值,不包括最小值,即左开右闭(]

  • 最左边的值, 一般设置成最小值减去最大值的 0.1%

2. pd.qcut()

  • pd.qcut()是基于分位数的等频分箱方法‌,它将数据划分为具有大致相同数量观测值的区间。主要参数包括:

  • x‌:需要进行切割的序列或数组。

  • q‌:分位数或区间个数,可以是小数或整数列表。例如,q=4会将数据分为四个等频区间。

  • labels‌、‌retbins‌、‌precision‌、‌duplicates‌等参数与pd.cut()类似,用法和意义一致

3. pd.cut()示例

  • 例如:把年龄划分为18岁以下、18-30岁、30-45岁、45-60岁、60岁以上等5个标签(类别)。

  • Pandas 包中的 cutqcut 都可以实现分箱操作,区别在于:

    • cut:按照数值进行分割,等间隔

    • qcut:按照数据分布进行分割,等频率

import pandas as pd
import numpy as np

ages = np.array([1, 5, 10, 40, 36, 12, 58, 62, 77, 89, 100, 18, 20, 25, 30, 32])

# 平分为5个区间
m_cut = pd.cut(ages, 5)
# 查看每个区间的范围和其中值的个数
value_cnt = pd.cut(ages, 5).value_counts()

print(f"ages:\n{ages}")
print(f"m_cut:\n{m_cut}")  # 打印结果显示ages中的元素分别对应哪个区间
print(f"value_cnt:\n{value_cnt}")

# 平分并指定每个区间的label
label_cut = pd.cut(ages, 5, labels=['婴儿', '青年', '中年', '壮年', '老年'])

# 按我们指定的区间进行分割
bins_cut = pd.cut(ages,
                  bins=[0, 5, 20, 30, 50, 100],
                  labels=['婴儿', '青年', '中年', '壮年', '老年'])

# 返回分割后的bins(设置 retbins=True 即可)
re_bins_cut = pd.cut(ages,
                     bins=[0, 5, 20, 30, 50, 100],
                     labels=['婴儿', '青年', '中年', '壮年', '老年'],
                     retbins=True)

# 只返回数据所属的bins(设置 labels=False 即可)
re_bins_cut1 = pd.cut(ages,
                      bins=[0, 5, 20, 30, 50, 100],
                      labels=False)

print(f"label_cut:\n{label_cut}")
print(f"bins_cut:\n{bins_cut}")
print(f"re_bins_cut:\n{re_bins_cut}")
print(f"re_bins_cut1:\n{re_bins_cut1}")


"""
ages:
[  1   5  10  40  36  12  58  62  77  89 100  18  20  25  30  32]
m_cut:
[(0.901, 20.8], (0.901, 20.8], (0.901, 20.8], (20.8, 40.6], (20.8, 40.6], ..., (0.901, 20.8], (0.901, 20.8], (20.8, 40.6], (20.8, 40.6], (20.8, 40.6]]
Length: 16
Categories (5, interval[float64, right]): [(0.901, 20.8] < (20.8, 40.6] < (40.6, 60.4] <
                                           (60.4, 80.2] < (80.2, 100.0]]
value_cnt:
(0.901, 20.8]    6
(20.8, 40.6]     5
(40.6, 60.4]     1
(60.4, 80.2]     2
(80.2, 100.0]    2
dtype: int64
label_cut:
['婴儿', '婴儿', '婴儿', '青年', '青年', ..., '婴儿', '婴儿', '青年', '青年', '青年']
Length: 16
Categories (5, object): ['婴儿' < '青年' < '中年' < '壮年' < '老年']
bins_cut:
['婴儿', '婴儿', '青年', '壮年', '壮年', ..., '青年', '青年', '中年', '中年', '壮年']
Length: 16
Categories (5, object): ['婴儿' < '青年' < '中年' < '壮年' < '老年']
re_bins_cut:
(['婴儿', '婴儿', '青年', '壮年', '壮年', ..., '青年', '青年', '中年', '中年', '壮年']
Length: 16
Categories (5, object): ['婴儿' < '青年' < '中年' < '壮年' < '老年'], array([  0,   5,  20,  30,  50, 100]))
re_bins_cut1:
[0 0 1 3 3 1 4 4 4 4 4 1 1 2 2 3]
"""

4. pd.qcut()示例

  • pd.qcut 实现按数据的数量进行分割,尽量保证每个分组里元素的个数相同

  • 例如:把年龄划分为18岁以下、18-30岁、30-45岁、45-60岁、60岁以上等5个标签(类别)。

  • Pandas 包中的 cutqcut 都可以实现分箱操作,区别在于:

    • cut:按照数值进行分割,等间隔

    • qcut:按照数据分布进行分割,等频率

import pandas as pd
import numpy as np

factors = np.random.randn(9)

# 简单按个数分箱
m_qcut = pd.qcut(factors, 3)

value_cnt = pd.qcut(factors, 3).value_counts() # 可以看到,每个区间的元素个数是相同的

# 添加标签
label_qcut = pd.qcut(factors,
        3,
        labels=['a','b','c'])

# 返回对应的分组下标
re_label_qcut = pd.qcut(factors, 3, labels=False)

# 返回bins值
re_bins_qcut = pd.qcut(factors, 3, retbins=True)

print(f"factors:\n{factors}")
print(f"m_qcut:\n{m_qcut}")
print(f"value_cnt:\n{value_cnt}")
print(f"label_qcut:\n{label_qcut}")
print(f"re_label_qcut:\n{re_label_qcut}")
print(f"re_bins_qcut:\n{re_bins_qcut}")

"""
factors:
[-0.45766098 -0.80389265 -0.01923068 -0.22016907  0.29515105  0.30977175
 -0.16378733  0.32406162  0.28579771]
m_qcut:
[(-0.805, -0.183], (-0.805, -0.183], (-0.183, 0.289], (-0.805, -0.183], (0.289, 0.324], (0.289, 0.324], (-0.183, 0.289], (0.289, 0.324], (-0.183, 0.289]]
Categories (3, interval[float64, right]): [(-0.805, -0.183] < (-0.183, 0.289] < (0.289, 0.324]]
value_cnt:
(-0.805, -0.183]    3
(-0.183, 0.289]     3
(0.289, 0.324]      3
dtype: int64
label_qcut:
['a', 'a', 'b', 'a', 'c', 'c', 'b', 'c', 'b']
Categories (3, object): ['a' < 'b' < 'c']
re_label_qcut:
[0 0 1 0 2 2 1 2 1]
re_bins_qcut:
([(-0.805, -0.183], (-0.805, -0.183], (-0.183, 0.289], (-0.805, -0.183], (0.289, 0.324], (0.289, 0.324], (-0.183, 0.289], (0.289, 0.324], (-0.183, 0.289]]
Categories (3, interval[float64, right]): [(-0.805, -0.183] < (-0.183, 0.289] < (0.289, 0.324]], array([-0.80389265, -0.18258124,  0.28891549,  0.32406162]))
"""

5. 运用示例

import pandas as pd
import numpy as np

df = pd.DataFrame([x**2 for x in range(11)],
                  columns=['number'])

# 按照数值由小到大 将数据分成4份
df['cut_group'] = pd.cut(df['number'], 4)

# 分成四组 并且让每组变量的数量相同
df['qcut_group'] = pd.qcut(df['number'], 4)
print(df['qcut_group'].value_counts())
'''
(-0.001, 6.5]    3
(6.5, 25.0]      3
(56.5, 100.0]    3
(25.0, 56.5]     2
'''

五、数据透视

posted @ 2025-03-18 15:37  BigSun丶  阅读(99)  评论(0)    收藏  举报