第7章 数据规整化:清理、转换、合并、重塑(5)

第7章 数据规整化:清理、转换、合并、重塑(5)

数据转换

前部分都是数据的重排,对数据的处理还包括过滤,清理等。

移除重复数据

  • duplicated()
  • drop_duplicates()
data = DataFrame({'k1':['one']*3+['two']*4,'k2':[1,1,2,3,3,4,4]})
Out[126]: 
    k1  k2
0  one   1
1  one   1
2  one   2
3  two   3
4  two   3
5  two   4
6  two   4

###返回布尔型Series,表示各行是否重复
data.duplicated()
Out[127]: 
0    False
1     True
2    False
3    False
4     True
5    False
6     True
dtype: bool

####返回移除重复行的DataFrame
data.drop_duplicates() ###注意索引的保留
Out[128]: 
    k1  k2
0  one   1
2  one   2
3  two   3
5  two   4

###duplicated/drop_duplicates默认判断全部列,可以指定部分列进行重复项判断
data['v1'] = range(7)
Out[130]: 
    k1  k2  v1
0  one   1   0
1  one   1   1
2  one   2   2
3  two   3   3
4  two   3   4
5  two   4   5
6  two   4   6

data.drop_duplicates(['k1']) ###仅判断k1列中的重复元素
Out[133]: 
    k1  k2  v1
0  one   1   0
3  two   3   3

####此处书上错误
####duplicated/drop_duplicates默认保留第一个出现的值的组合,keep参数可以控制保留项
####keep三个参数,'first' 'last' False,默认为'first',为False是删除所有重复项,first/last分别是删除重复项但保留第一个/最后一个出现的重复项
data.drop_duplicates(['k1','k2'],keep = 'last')
Out[135]: 
    k1  k2  v1
1  one   1   1
2  one   2   2
4  two   3   4
6  two   4   6

利用函数或映射进行数据转换

data = 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]})
Out[137]: 
          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

####肉类到动物的映射
##字典存储映射
meat_to_animal={'bacon':'pig','pulled pork':'pig','pastrami':'cow','corned beef':'cow','honey ham':'pig','nova lox':'Salmon'}

###Series中map方法可以接受一个函数或含有映射关系的字典型对象,对Series中每个元素处理
####注意先处理大小写问题,str.lower
####或者引入lamda。 data['animal'] = data['food'].map(lamda x: meat_to_animal[x.lower()])
data['animal'] = data['food'].map(str.lower).map(meat_to_animal)

替换值

  • fillna填充缺失数据
  • map修改对象的数据子集
  • replace
data = Series([1,-999,2,-999,-1000,3]) ##-999代表数据缺失的标记值。要将其替换为NAN

data.replace(-999,np.nan)###用np.nan替换-999
data.replace([-999,-1000],np.nan)####一次替换多个值,-999和-1000都替换为NAN
data.replace([-999,-1000],[np.nan,0])####一一对应替换 -999→NAN,-1000→0
data.replace({-999:np.nan,-1000:0}) ####传入字典参数

重命名轴索引

与Series一样,轴标签中的元素也可以通过函数或者映射进行转换,从而得到新对象。

data = DataFrame(np.arange(12).reshape(3,4),index=['Ohio','Colorado','New York'],columns=['one','two','three','four'])

data.index = data.index.map(str.upper) ###index中字符全替换为大写再赋值回去

date_new = data.rename(index = str.title,columns=str.upper)##创建转化后的新的数据集,保留原始数据
####str.title将字符串转化为标题版本,即首字母大写,其余小写

###rename结合字典可以对部分轴标签更新
data_new2 = data.rename(index={'OHIO':'IDIANA'},columns={'three':'peekaboo'})
Out[154]: 
          one  two  peekaboo  four
IDIANA      0    1         2     3
COLORADO    4    5         6     7
NEW YORK    8    9        10    11

####rename就地修改,直接修改源数据,不返回新数据
_ = data.rename(index={'OHIO':'INDIANA'},inplace = True)
In [158]:data
Out[158]: 
          one  two  three  four
INDIANA     0    1      2     3
COLORADO    4    5      6     7
NEW YORK    8    9     10    11

离散化和区间划分

连续数据的拆分

ages = [20,22,25,27,21,23,37,31,61,45,41,32]
bins = [18,25,35,60,100] ##设定划分区间18-25,26-35,36-60,61-100
cats = pd.cut(ages,bins) ##返回一个Categorical对象,默认区间为左开右闭,通过right参数来调整,right = False为左闭右开,默认right = True
In [164]:cats
Out[164]: 
[(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]): [(18, 25] < (25, 35] < (35, 60] < (60, 100]]

###对Categorical对象的描述与书上有不同
####Categorical对象由两个部分组成,一个是划分的区间,还有一个是原数据划分后的结果,其中有两个属性,Categorical.categories(返回划分的区间,并表明闭区间在左侧还是右侧)和Categorical.codes(表明原数据中每个数据所处的区间,用划分区间的下标索引表示,从0开始)
In [169]:cats.categories
Out[169]: 
IntervalIndex([(18, 25], (25, 35], (35, 60], (60, 100]]
              closed='right',
              dtype='interval[int64]')

In [170]:cats.codes
Out[170]: array([0, 0, 0, 1, 0, 0, 2, 1, 3, 2, 2, 1], dtype=int8)

####给每个区间计数
In [172]:pd.value_counts(cats)
Out[172]: 
(18, 25]     5
(35, 60]     3
(25, 35]     3
(60, 100]    1
dtype: int64

####可以给每个区间设定一个名称,通过labels参数传入每个区间的名字
group_name = ['Youth','YoungAdult','MiddleAged','Senior']
pd.cut(ages,bins,labels = group_name)
Out[175]: 
[Youth, Youth, Youth, YoungAdult, Youth, ..., YoungAdult, Senior, MiddleAged, MiddleAged, YoungAdult]
Length: 12
Categories (4, object): [Youth < YoungAdult < MiddleAged < Senior]

###如果传入的是区间数量而不是确切边界,则会根据数据最小值和最大值,计算等长区间
data = np.random.randn(20)
pd.cut(data,4,precision = 2)###设置区间边界精度
Out[182]: 
[(0.99, 1.94], (-1.87, -0.91], (-0.91, 0.037], (0.037, 0.99], (0.99, 1.94], ..., (0.99, 1.94], (0.99, 1.94], (-1.87, -0.91], (-0.91, 0.037], (-1.87, -0.91]]
Length: 20
Categories (4, interval[float64]): [(-1.87, -0.91] < (-0.91, 0.037] < (0.037, 0.99] < (0.99, 1.94]]

######qcut与cut类似,但是是根据样本分位数对数据进行区间划分,cut可能无法使区间内含有相同数量的数据,但是qcut可以获得数量基本相同的区间
data = np.random.randn(1000)
cats = pd.qcut(data,4) ####按四分位数进行划分
Out[184]: 
[(0.606, 2.823], (-0.683, -0.0468], (-0.683, -0.0468], (-0.0468, 0.606], (0.606, 2.823], ..., (-0.683, -0.0468], (-3.382, -0.683], (0.606, 2.823], (-3.382, -0.683], (0.606, 2.823]]
Length: 1000
Categories (4, interval[float64]): [(-3.382, -0.683] < (-0.683, -0.0468] < (-0.0468, 0.606] < (0.606, 2.823]]

In [186]:pd.value_counts(cats)
Out[186]: 
(0.606, 2.823]       250
(-0.0468, 0.606]     250
(-0.683, -0.0468]    250
(-3.382, -0.683]     250
dtype: int64

###可自定义分位数,0-1之间的数值,包含端点
new_cats = pd.qcut(data,[0,0.1,0.5,0.9,1])
In [188]:pd.value_counts(new_cats)
Out[188]: 
(-0.0468, 1.206]     400
(-1.329, -0.0468]    400
(1.206, 2.823]       100
(-3.382, -1.329]     100
dtype: int64

检测过滤异常值

异常值即孤立点、离群点

data = DataFrame(np.random.randn(1000,4)) ###生成4列,每列都是正态分布数的DataFrame对象
In [190]:data.describe() ####data属性
Out[190]: 
                 0            1            2            3
count  1000.000000  1000.000000  1000.000000  1000.000000
mean      0.036955    -0.030808     0.004385     0.017893
std       1.005653     0.979606     1.003002     0.999522
min      -3.400193    -3.871381    -3.626467    -3.561846
25%      -0.634620    -0.667826    -0.718142    -0.681812
50%       0.038195    -0.050365    -0.040234     0.024882
75%       0.768188     0.602451     0.684530     0.682487
max       2.859131     3.395861     3.192252     3.020070

col = data[3]
In [192]:col[np.abs(col)>3]   ###找出3列中绝对值大于3的值
Out[192]: 
29     3.020070
279   -3.055511
500   -3.561846
711   -3.541687
Name: 3, dtype: float64

###找出全部含有绝对值大于3的值的行
data[(np.abs(data)>3).any(axis = 1)] ###设定any方法中的axis = 1表示每行中含有绝对值大于3的值
Out[197]: 
            0         1         2         3
17  -0.748195 -3.159036 -0.404608  0.904498
29  -0.164734 -1.256519 -0.724999  3.020070
109  0.452139 -1.042520  3.143075  1.048354
279 -1.958829  0.087400 -0.392875 -3.055511
392  0.045182  2.131359 -3.445043  0.416538
500 -2.099903 -1.963188 -0.240716 -3.561846
556 -0.600726  0.470719 -3.626467 -0.585577
576 -0.460733  0.562222  3.192252 -1.666503
682 -0.716962  3.395861  0.047119  0.173432
711 -0.473312 -0.193344  1.278363 -3.541687
751 -3.110940  0.388629 -0.221459  0.790747
769  0.416308 -3.653692  1.500504 -0.837095
840 -3.400193  1.916887 -1.275942  0.483493
887  0.159239  1.655584 -3.086544 -0.213076
959  0.227707  3.008310  0.691871  0.501017
967  0.304056 -3.871381 -1.409443  0.430060

####限制data中所有值在[-3,3]
data[np.abs(data)>3]=np.sign(data)*3 ###返回符号 ±,sign(-3)=-1,sign(3)=1
In [203]:data.describe()
Out[203]: 
                 0            1            2            3
count  1000.000000  1000.000000  1000.000000  1000.000000
mean      0.037466    -0.029528     0.005207     0.019032
std       1.004020     0.972518     0.998189     0.995644
min      -3.000000    -3.000000    -3.000000    -3.000000
25%      -0.634620    -0.667826    -0.718142    -0.681812
50%       0.038195    -0.050365    -0.040234     0.024882
75%       0.768188     0.602451     0.684530     0.682487
max       2.859131     3.000000     3.000000     3.000000

排列和随机采样

  • numpy.random.permutation
df = DataFrame(np.arange(20).reshape(5,4))

sampler = np.random.permutation(5)####返回一个随机排列的数列,或者范围内的随机排列的数列,如果传入参数是个多维ndarray,则沿着第一个索引随机排列,即二维数组,沿着行的索引随机排列
###shuffle有相同效果,但是只接受array_like,不能接受int,且不返回打乱后的数组,是inplace修改
In [207]:sampler
Out[207]: array([3, 1, 2, 0, 4])

df.take(sampler)####沿着轴返回给定顺寻索引的dataframe数据,默认axis=0
Out[208]: 
    0   1   2   3
3  12  13  14  15
1   4   5   6   7
2   8   9  10  11
0   0   1   2   3
4  16  17  18  19

df.take(np.random.permutation(len(df))[:3])###切取permutation生成的随机排列array的前三个,再按照索引顺序切取df数据
Out[209]: 
    0   1   2   3
1   4   5   6   7
3  12  13  14  15
4  16  17  18  19

bag = np.array([5,7,-1,6,4])

sampler = np.random.randint(low = 0,high = len(bag),size = 10)###randint(最小值,最大值,个数)
Out[212]: array([2, 2, 0, 4, 2, 2, 1, 4, 1, 3])

draws = bag.take(sampler)
Out[214]: array([-1, -1,  5,  4, -1, -1,  7,  4,  7,  6])

计算指标/哑变量

  • get_dummies
df = DataFrame({'key':['b','b','a','c','a','b'],'data1':range(6)})
Out[220]: 
   data1 key
0      0   b
1      1   b
2      2   a
3      3   c
4      4   a
5      5   b

pd.get_dummies(df['key'])####哑矩阵将传入参数不同种类展开为不同列,例子中abc展开,矩阵中只有0,1两个值,0代表非,1代表是
Out[221]: 
   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

####给哑矩阵每个列加一个前缀名,参数prefix控制
dummies = pd.get_dummies(df['key'],prefix = 'key')
Out[223]: 
   key_a  key_b  key_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['data1']合并为一个DataFrame
df_with_dummy = df[['data1']].join(dummies)
Out[225]: 
   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

####dummies和cut结合可以清晰展示每个数据的区间
values = np.random.rand(10)
Out[227]: 
array([ 0.39412391,  0.07717691,  0.5872264 ,  0.25836265,  0.2311182 ,
        0.93356344,  0.16665829,  0.96166322,  0.13581445,  0.80504075])
bins = [0,0.2,0.4,0.6,0.8,1]
pd.get_dummies(pd.cut(values,bins))
Out[229]: 
   (0.0, 0.2]  (0.2, 0.4]  (0.4, 0.6]  (0.6, 0.8]  (0.8, 1.0]
0           0           1           0           0           0
1           1           0           0           0           0
2           0           0           1           0           0
3           0           1           0           0           0
4           0           1           0           0           0
5           0           0           0           0           1
6           1           0           0           0           0
7           0           0           0           0           1
8           1           0           0           0           0
9           0           0           0           0           1

字符串操作

val = 'a,b, guido'

val.split(',')###逗号分隔字符串
Out[232]: ['a', 'b', ' guido']

pieces = [x.strip() for x in val.split(',')]###strip()剪去空白符,包括换号符等
Out[234]: ['a', 'b', 'guido']

'::'.join(pieces)###用"::"连接pieces中的字符串
Out[235]: 'a::b::guido'

'guido' in val ###判断是否包含子串
Out[236]: True

val.index(',')####返回第一个出现','符号的位置
Out[237]: 1

val.find(':')###在val中找':'
Out[238]: -1

val.count(',')##返回','出现的次数
Out[239]: 2

val.replace(',','::')###用'::'替换',',传入空字符串可以执行删除操作
Out[240]: 'a::b:: guido'

Python内置字符串方法

方法说明
count返回子串在字符串中出现的次数
endswith、startswith如果字符串以某个后缀结尾(以某个前缀开头),则返回True
join字符串连接
index如果在字符串中找到子串,则返回子串第一个字符所在的位置,如果没找到引发异常
find如果在字符串中找到子串,则返回子串第一个字符所在的位置,如果没找到返回-1
rfind如果在字符串中找到子串,则返回最后一个发现的子串第一个字符所在的位置,如果没找到返回-1
replace替换
strip、rstrip、lstrip去除空白符
split用制定分隔符拆分字符串
lower、upper字母大小写转换
ljust、rjust用空格(或其他字符)填充字符串空白侧以返回符合最低宽度的字符串
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值