pandas数据变换(二)

本文介绍如何使用Python的pandas库进行数据离散化处理,包括使用cut和qcut函数进行分箱,以及如何检测和过滤数据集中的异常值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

5.离散化和装箱

连续型数据经常离散化或分散成bins(分箱)来分析。

假设又一组数据,数据代表不同的年龄,把人分到不同的年龄组

import numpy as pd
import pandas as pd
from numpy import nan as NA

ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32]
#把上诉年龄下面分到不同的bins中,19~25, 26~35, 36~60, >60。可以用pandas里的cut:
bins=[18,25,30,60,100]
cats=pd.cut(ages,bins)
print(cats)

#输出:
[(18, 25], (18, 25], (18, 25], (25, 30], (18, 25], ..., (30, 60], (60, 100], (30, 60], (30, 60], (30, 60]]
Length: 12
Categories (4, interval[int64]): [(18, 25] < (25, 30] < (30, 60] < (60, 100]]
#可以看到bins 被cut分为4个部分,每个部分都是范围,然后将ages中的年龄返回表示在bins 中的哪个部分

返回的是一个特殊的Categorical object。我们看到的结果描述了pandas.cut如何得到bins。可以看作是一个string数组用来表示bin的名字,它内部包含了一个categories数组,用来记录不同类别的名字,并伴有表示ages的label

print(cats.codes) #表示ages的label,因为bins 一共又4个部分0-3
print(cats.categories) #返回类别

#输出:
[0 0 0 1 0 0 2 2 3 2 2 2]
IntervalIndex([(18, 25], (25, 30], (30, 60], (60, 100]]
              closed='right',
              dtype='interval[int64]')

print(pd.value_counts(cats)) #统计cats中每个相同类别的个数,因为cats返回的是灭个年龄的类别
                             #这里pd.value_counts(cats)是pandas.cut后bin的数量

#输出:
(30, 60]     5
(18, 25]     5
(60, 100]    1
(25, 30]     1
dtype: int64

我们在创建bin的区间时,默认时左开又闭,但是我们可以向cut函数中传入参数right=False,意思是左闭右开。

print(pd.cut(ages,[18,26,31,61,101],right=False))

#输出:
[[18, 26), [18, 26), [18, 26), [26, 31), [18, 26), ..., [31, 61), [61, 101), [31, 61), [31, 61), [31, 61)]
Length: 12
Categories (4, interval[int64]): [[18, 26) < [26, 31) < [31, 61) < [61, 101)]

在默认中bin的类别名称就是一个数字到另外一个数字的范围,我们可以使用一个list或数组来给labels选项来设定bin的名字

group_names = ['Youth', 'YoungAdult', 'MiddleAged', 'Senior']
print(pd.cut(ages,bins,labels=group_names)) #只是将(18,25],(25,30]等换了一个名字而已,bin的范围大小还是不变

#输出:
[Youth, Youth, Youth, YoungAdult, Youth, ..., MiddleAged, Senior, MiddleAged, MiddleAged, MiddleAged]
Length: 12
Categories (4, object): [Youth < YoungAdult < MiddleAged < Senior]

当给一个bins的数量来切分,而不是自己去设定每个bins的范围,那么cut函数会根据传入数据的最大值和最小值来计算等长的bins,就是每个bins的长度范围等长

data=pd.cut(np.random.randn(20),4,precision=2) #np.random.randn(20)产生20个随机数字,然后bin分为4种,然后切分,precision=2表示精确每个bins到小数点后两位

#输出:
[(-1.04, -0.11], (-1.04, -0.11], (-0.11, 0.82], (-1.04, -0.11], (0.82, 1.75], ..., (-1.04, -0.11], (-1.04, -0.11], (-1.98, -1.04], (-1.04, -0.11], (-0.11, 0.82]]
Length: 20
Categories (4, interval[float64]): [(-1.98, -1.04] < (-1.04, -0.11] < (-0.11, 0.82] < (0.82, 1.75]]

近似函数qcut(),它分的bins ,会保证每个bins有相同个数的数据点,因为qcut是按照百分比来切分的

data=np.random.randn(1000)
cats=pd.qcut(data,4)
print(cats)
print(pd.value_counts(cats)) #统计每个bin的数据量,最后可以看出每个bin的数据量都是一样的

#输出:
Length: 1000
Categories (4, interval[float64]): [(-3.06, -0.591] < (-0.591, 0.0336] < (0.0336, 0.687] <
                                    (0.687, 3.55]]
(0.687, 3.55]       250
(0.0336, 0.687]     250
(-0.591, 0.0336]    250
(-3.06, -0.591]     250
dtype: int64

cut和qcut,这些离散函数对于量化群聚分析很有用!!!

 

6.检测和过滤异常值

过滤和转换异常值是数组中很重的一个操作,所以这个知识点很重要,谨记!

data=pd.DataFrame(np.random.randn(1000,4))
print(data.describe())  describe函数是查看数据的分布情况 可返回变量和观测的数量、缺失值和唯一值的数目、平均值、分位数等相关信息。我之前有赋过一张表,里面解释了每个的意思,这里mean是平均值,std标准差

#
                 0            1            2            3
count  1000.000000  1000.000000  1000.000000  1000.000000
mean      0.034130    -0.010546     0.031287    -0.018945
std       1.027747     1.026583     1.034798     0.967755
min      -3.315814    -3.168130    -3.458382    -2.902957
25%      -0.639957    -0.689596    -0.647237    -0.681589
50%       0.055545     0.015397     0.049480     0.005087
75%       0.695106     0.716642     0.681778     0.647246
max       3.574917     2.545372     2.973921     3.583291

假设我们想找这个data中绝对值大于3的数字

#因为数据过大有1000行,我们就返回data的前5行来寻找
print(data.head())

#输出:
         0         1         2         3
0  1.611005 -1.069570  0.141291 -0.952645
1 -0.380136  1.683400 -0.580652 -0.700371
2 -1.142718 -0.735791 -3.064287 -1.216154
3  0.506688 -0.265969 -1.303375 -1.019275
4 -1.118206  1.550753  1.315599 -0.488782

col=data1[2]  #取得data中columns为2得那一列得数据
print(col.head())

#输出:
0    0.141291
1   -0.580652
2   -3.064287
3   -1.303375
4    1.315599

print(np.abs(col)>3)
print(col[np.abs(col) > 3]) #np.abs(col)>3 会返回col这个列的布尔类型数据,不满足条件的为False,满足条件的为True

#输出:
995    False
996    False
997    False
998    False
999    False
Name: 2, Length: 1000, dtype: bool  #这个只是截取一部分
52    -3.218709
62     3.114901
482   -3.588008
737    3.080875
813    3.057308
Name: 2, dtype: float64


print(data[(np.abs(data) > 3)].head()) #这个表示data数据中得每一行得数字绝对值都必须大于3,显然那是不可能的,所以返回的
                                       #首5行数据缺位缺失值,表明没有这样的值
print(data[(np.abs(data)>3).any(1)])   #表示选取data数据中,每行有一列的数字满足这个条件的

#输出:
 0   1   2   3
0 NaN NaN NaN NaN
1 NaN NaN NaN NaN
2 NaN NaN NaN NaN
3 NaN NaN NaN NaN
4 NaN NaN NaN NaN
            0         1         2         3
100 -3.072365 -0.078140 -0.201873  1.131444
136  0.220908 -0.783075  3.210207 -0.064182
304 -1.450086 -1.400088  0.296908  3.086599
393  0.954320  3.335903 -0.302396 -0.455293
488 -0.035747  0.749712 -0.824296 -3.323456
519 -0.848282 -3.334016 -0.099327  0.693206
575 -3.493005  1.583037 -0.493140  0.316778
648  0.414687 -3.104181  0.685408 -0.945478
715  0.411987 -0.787592 -3.338853  0.087688
884  3.285694  1.539924 -0.632090  0.613689
975 -3.045808 -0.373709  2.035942  0.262163

np.sign() 函数是根据传入数据的正负号 来得到+1 或 -1,返回一个新的data

print(np.sign(data).head())  #根据data数据中得到-1 或+1

#输出:
     0    1    2    3
0 -1.0 -1.0 -1.0  1.0
1  1.0  1.0  1.0 -1.0
2  1.0  1.0  1.0 -1.0
3  1.0 -1.0 -1.0 -1.0
4 -1.0  1.0 -1.0 -1.0

data[np.abs(data)>3]=np.sign(data)*3 # 将data中数据大于3的数字赋值为3,或则-3
print(data[(np.abs(data)>=3).any(1)])

#输出:
         0         1         2         3
38   1.283115  1.094888 -0.941362 -3.000000
72  -0.231678  3.000000  0.402873 -0.872957
356  0.133103  1.337680  3.000000  1.996030
376 -3.000000  0.877116 -1.267313 -0.644417
388 -0.908056  0.393500  3.000000 -0.787527
409 -1.227639 -1.330704  0.404324 -3.000000
421  0.075262 -0.513744  3.000000 -0.140479
582 -3.000000  0.130571 -1.276300 -0.162316
612  3.000000  0.602845 -1.699048  1.446110
840 -0.328060 -0.849822 -3.000000 -1.000604
885 -0.532064 -0.651618 -1.639361 -3.000000
891 -0.877902 -1.451622 -1.658073 -3.000000
892 -2.354666 -0.331953  1.283252 -3.000000

print(data.describe())  #显示数据中各种信息
#输出:
                 0            1            2            3
count  1000.000000  1000.000000  1000.000000  1000.000000
mean     -0.060311     0.018493     0.040830     0.008197
std       1.038350     1.008272     0.984851     0.983521
min      -3.000000    -3.000000    -3.000000    -3.000000
25%      -0.721603    -0.650585    -0.602932    -0.672454
50%      -0.066891     0.020827     0.011951     0.077265
75%       0.653727     0.712820     0.719602     0.698649
max       3.000000     3.000000     3.000000     2.669392

可以看到数据中最大值max的变化

7.排列和随机采样

排列(随机排列-->顺序是随机)一个Series 或DataFrame 中的row,用numpy.random.permutation函数很容易做到。可以设定好需要的axis,来表示想排列多少row 。它会产生一个数组表示新的顺序

data=pd.DataFrame(np.arange(5*4).reshape(5,4)) #arange(5*4) 产生数字20个,从0到19 生成为二维数组,为5*4

#输出:
     0   1   2   3
0   0   1   2   3
1   4   5   6   7
2   8   9  10  11
3  12  13  14  15
4  16  17  18  19

s=np.random.permutation(5)
print(s)

#这个数组能被用在基于iloc上的indexing(根据索引寻找)或take函数(根据索引返回索引的表)
print(data.take(s))

#输出:
[1 4 3 0 2]   #产生一个数组表示新的顺序
    0   1   2   3
1   4   5   6   7
4  16  17  18  19
3  12  13  14  15
0   0   1   2   3
2   8   9  10  11

为了选中一个data中一个新的随机的子集,而且没有替代功能,返回一个新的Series 或DataFrame ,我们可以使用sample()

print(data.sample(n=3)) #产生一个随机的子集,row大小为3

#输出:
    0   1   2   3
4  16  17  18  19
0   0   1   2   3
1   4   5   6   7

如果想要产生的样本具有替代功能(即允许其中的数据有重复),我们可以在sample()中传入参数repalce=True

df=pd.Series([2,4,8,9,5])
print(df.sample(n=10,replace=True)) #产生一个随机子集,row大小为10

#输出:
4    5
4    5
3    9
0    2
1    4
3    9
3    9
4    5
1    4
0    2
dtype: int64

8.计算指示器/虚拟变量 Computing Indicator/Dummy Variables

虚拟变量,又称虚设变量、名义变量或哑变量,用以反映质的属性的一个人工变量,是量化了的自变量,通常取值为0或1

如果DataFrame中的一列有k个不同的值,我们可以用一个矩阵或DataFrame用k列来表示,1或0。(就是相当于返回一个新的DataFrame,列索引为一列k个不同的值,然后1或0表明一列的每行拥有的值是什么,就是在每列下面1为 有这个值,0表明没有这个值)

那么这些我们可以使用pandas的get_dummies函数

df = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'b'],
                   'data1': range(6)})
print(df)
print(pd.get_dummies(df['key'])) #传入索引列为key的数据

#输出:
   data1 key
0      0   b
1      1   b
2      2   a
3      3   c
4      4   a
5      5   b
   a  b  c
0  0  1  0
1  0  1  0
2  1  0  0
3  0  0  1
4  1  0  0
5  0  1  0
#这里的b为1,因为在df中 Key列第一行的数据就是为b,这样依次类推
dummies=pd.get_dummies(df['key'],prefix='key') #我们可以使用get_dummies()中的参数prefix来给每一列加上一个字首(prefix)
print(dummies)

#输出:
        key1_a  key1_b  key1_c
0       0       1       0
1       0       1       0
2       1       0       0
3       0       0       1
4       1       0       0
5       0       1       0

df_dummies=df[['data1']].join(dummies) #df[['data1']](注意这里是两个[])加上dummies 组合成一个新的DataFrame结构
print(df_dummies)

#输出:
   data1  key_a  key_b  key_c
0      0      0      1      0
1      1      0      1      0
2      2      1      0      0
3      3      0      0      1
4      4      1      0      0
5      5      0      1      0

因为自己看得那个jupyter,有些知识点涉及到了数据集,暂时还没有下载到那个数据集,所以后面的无法学习,等有了再学习。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值