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