数据清洗和准备:置换和随机抽样,计算指标/虚拟指标,pandas 中的向量化字符串函数

7.2.7 置换和随机抽样

使用 numpy.ranodm.permutation 对dataframe 中的 series 或行进行置换(随机排序)是非常方便的。调用 permutation 根据你想要的轴长度可以产生一个表示新顺序的整数数组。

df=pd.DataFrame(np.arange(5*4).reshape((5,4)))
sampler=np.random.permutation(5)
sampler                    # 就是随机一下索引。。。
array([2, 1, 4, 3, 0])

df.take(sampler)            # 这个take 等价于 iloc 索引 等于 df.iloc[sampler]
   0	1	2	3
2	8	9	10	11
1	4	5	6	7
4	16	17	18	19
3	12	13	14	15
0	0	1	2	3


df.sample(n=3)             # 使用 series or dataframe 的sample 方法,选出一个不含有替代值的随机子集
   0	1	2	3
0	0	1	2	3
1	4	5	6	7
4	16	17	18	19              # 这个索引是随机排列的。


choices=pd.Series([5,7,-1,6,4])
draws=choices.sample(n=10,replace=True)     # 生成一个带有替代值(允许又重复选择),将 replace 传入就行
draws
0    5
1    7
0    5
0    5
4    4
1    7
1    7
4    4
3    6
1    7
dtype: int64

7.2.8 计算指标/虚拟指标

将分类变量转换为 ‘虚拟’ 或 ‘指标’ 矩阵式是另一种统计建模或机器学习的转换操作,如果 dataframe 中的一列有 k 个不同的值,就可以衍生一个 k 列的值为 1 和0 的矩阵或 dataframe .pandas有 get_dummies 方法实现该功能。

df = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'b'],
                   'data1': range(6)})
pd.get_dummies(df['key'])
	a	b	c
0	0	1	0       # key这一列,第一行是b
1	0	1	0
2	1	0	0
3	0	0	1
4	1	0	0
5	0	1	0

dummies=pd.get_dummies(df['key'],prefix='key')       # 在指标dataframe(就是上面那个)的列加上前缀,并与其他数据结合
df_with_dummy=df[['data1']].join(dummies)# 这里是df[['data1']] 是一个dataframe ,data['data1'] 是一个series 没有join 方法
df_with_dummy
	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


# 如果dataframe 中的一行属于多个类别,情况就复杂了,,看看 MovieLens IM 数据集。搜了一下好像很有名的。。。
# https://github.com/wesm/pydata-book/blob/1st-edition/ch02/movielens/movies.dat 从这下载
mnames = ['movie_id', 'title', 'genres']
movies = pd.read_table('movies.dat', sep='::',header=None, names=mnames)
movies[:10]
	movie_id	title	genres                       # 报错信息就是C不支持一些特性换了python的引擎。。应该没事的。。
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


# 为每个电影流派添加指标变量需要进行一些数据处理,首先我们从数据集中提取出所有不同流派的列表
all_genres=[]
for x in movies.genres:
    all_genres.extend(x.split('|'))
genres=pd.unique(all_genres)         # 取唯一值
genres
array(['Animation', "Children's", 'Comedy', 'Adventure', 'Fantasy',
       'Romance', 'Drama', 'Action', 'Crime', 'Thriller', 'Horror',
       'Sci-Fi', 'Documentary', 'War', 'Musical', 'Mystery', 'Film-Noir',
       'Western'], dtype=object)
       
zero_matrix=np.zeros((len(movies),len(genres)))          # 使用全0 的dataframe 是构建指标 dataframe 的一种方式
dummies=pd.DataFrame(zero_matrix,columns=genres)      # 列名就是我们提取出来的流派,索引就是movie 的。3883行
gen=movies.genres[0]    # 爷服了,,我一直以为这个 genres[0] 是列表的第一个 'Animation‘。。我就好奇这是怎么索引出来的
gen.split('|')                    # 这 genres[0] 是movie genres 列的第一个。。。。。。
['Animation', "Children's", 'Comedy']

dummies.columns.get_indexer(gen.split('|'))      # 使用这个计算每一个流派的列指标。
array([0, 1, 2], dtype=int64)                  # 就是得到movies.genres 拆分后各流派在 dumies 列的索引。

for i,gen in enumerate(movies.genres):
    indices=dummies.columns.get_indexer(gen.split('|'))      # 就是获得每个位置的索引,然后赋值为 1
    dummies.iloc[i,indices]=1   

movies_windic=movies.join(dummies.add_prefix('Genre_'))     # 进行一下联合,加个前缀
movies_windic.iloc[0]                       # 这是获得第一行的内容
movie_id                                       1
title                           Toy Story (1995)
genres               Animation|Children's|Comedy
Genre_Animation                                1
Genre_Children's                               1
Genre_Comedy                                   1
Genre_Adventure                                0
Genre_Fantasy                                  0           # 额,,真是神奇哈,,这就是指标了,,还蛮复杂的。。
Genre_Romance                                  0
Genre_Drama                                    0
Genre_Action                                   0
Genre_Crime                                    0
Genre_Thriller                                 0
Genre_Horror                                   0
Genre_Sci-Fi                                   0
Genre_Documentary                              0
Genre_War                                      0
Genre_Musical                                  0
Genre_Mystery                                  0
Genre_Film-Noir                                0
Genre_Western                                  0
Name: 0, dtype: object

对于更大的数据,这种使用多成员构建指标变量并不是特别快速(额,,)更好的方式是写一个直接将数据写为NumPy
数值的底层函数,然后将结果封装进 dataframe ??????

values=np.random.rand(10)
values
array([0.66319175, 0.30772294, 0.39933069, 0.12280386, 0.57973843,
       0.15229327, 0.13299343, 0.51790015, 0.46602084, 0.02590613])

bins=[0,0.2,0.4,0.6,0.8,1]
pd.get_dummies(pd.cut(values,bins)).iloc[:2]            # 将get_dummies and cut(分箱) 结合是统计应用的一个有效方法。
	(0.0, 0.2]	(0.2, 0.4]	(0.4, 0.6]	(0.6, 0.8]	(0.8, 1.0]
0	0	0	0	1	0
1	0	1	0	0	0

有数据分析的感觉了,,,,,

7.3.1 字符串对象方法

很多字符串处理和脚本应用中,内建的字符串方法是足够用的。

在这里插入图片描述

7.3.2 正则表达式

我以前写过三篇,感觉比较详细了(其实大部分都用不上。。)脑补链接

import re
text = """Dave dave@google.com
Steve steve@gmail.com
Rob rob@gmail.com
Ryan ryan@yahoo.com
AI路漫漫 moden54567789@gmail.com  
"""
pattern = r'[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}'

# re.IGNORECASE 使正则不区分大小写
regex = re.compile(pattern, flags=re.IGNORECASE)

regex.findall(text)
['dave@google.com',
 'steve@gmail.com',
 'rob@gmail.com',
 'ryan@yahoo.com',
 'moden54567789@gmail.com']      # hehe..这是我的邮箱啊,,,

regex.search(text).group()
'dave@google.com'

regex.match(text)
None

print(regex.sub('REDACTED',text))
Dave REDACTED
Steve REDACTED
Rob REDACTED
Ryan REDACTED
AI路漫漫 REDACTED  

pattern = r'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\.([A-Z]{2,4})'
regex = re.compile(pattern, flags=re.IGNORECASE)
m = regex.match('wesm@bright.net')          # 就是一个分组
m.groups()
('wesm', 'bright', 'net')

regex.findall(text)
[('dave', 'google', 'com'),
 ('steve', 'gmail', 'com'),
 ('rob', 'gmail', 'com'),
 ('ryan', 'yahoo', 'com'),
 ('moden54567789', 'gmail', 'com')]

print(regex.sub(r'Username: \1, Domain: \2, Suffix: \3', text))     # 分组的特殊索引
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
AI路漫漫 Username: moden54567789, Domain: gmail, Suffix: com  

7.3.3 pandas 中的向量化字符串函数

data = {'Dave': 'dave@google.com', 'Steve': 'steve@gmail.com',
        'Rob': 'rob@gmail.com', 'Wes': np.nan}
data = pd.Series(data)
# 可以使用 data,map将字符串和有效的正则应用到每个值上,
# 但是在 NA 上会失败,为了解决这个问题series 有面向数组的方法用于跳过NA 值,这些方法通过 series 的str 属性进行调用。

data.str.contains('gmail')        # 检测是否有这个字段
Dave     False
Steve     True
Rob       True
Wes        NaN
dtype: object


pattern            # 正则也可以结合任意的 re 模块选项使用
'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\\.([A-Z]{2,4})'

data.str.findall(pattern, flags=re.IGNORECASE)
Dave     [(dave, google, com)]
Steve    [(steve, gmail, com)]
Rob        [(rob, gmail, com)]
Wes                        NaN
dtype: object

matchs=data.str.match(pattern,flags=re.IGNORECASE)
matchs
Dave     True
Steve    True              # 这个返回的布尔值,,,
Rob      True
Wes       NaN
dtype: object

data.str.get(0)       # 就是索引,获得第零个元素,'dave@google.com' 的第一个元素
Dave       d
Steve      s
Rob        r
Wes      NaN
dtype: object

data.str[:5]        # 切片索引
Dave     dave@
Steve    steve
Rob      rob@g
Wes        NaN
dtype: object

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值