7.2.2 使用函数或映射进行数据交换
data = pd.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]})
data # 关于肉类的数据,培根,手撕猪肉,熏牛肉,咸牛肉,蜂蜜火腿,盐渍三文鱼。。。。。。
meat_to_animal = { # 来添加一列表明每种肉的来源,,
'bacon': 'pig',
'pulled pork': 'pig',
'pastrami': 'cow',
'corned beef': 'cow',
'honey ham': 'pig',
'nova lox': 'salmon'
}
lowercased=data['food'].str.lower() # 可以看到一些肉类时大写的,使用 str.lower()方法将所有值都小写。
lowercased
0 bacon
1 pulled pork
2 bacon
3 pastrami
4 corned beef
5 bacon
6 pastrami
7 honey ham
8 nova lox
Name: food, dtype: object
data['animal']=lowercased.map(meat_to_animal) # series 的map 方法接收一个函数或一个包含映射关系的字典型对象。
data
food ounces animal
0 bacon 4.0 pig
1 pulled pork 3.0 pig
2 bacon 12.0 pig
3 Pastrami 6.0 cow
4 corned beef 7.5 cow
5 Bacon 8.0 pig
6 pastrami 3.0 cow
7 honey ham 5.0 pig
8 nova lox 6.0 salmon
data['animal'].map(lambda x:meat_to_animal[x.lower()]) # 也可以传入一个可以完成所有工作的函数,,感觉不是很好理解啊。
使用 map 是一种可以便捷执行按元素转换及其他清洗相关操作的方法。
7.2.3 替代值
使用 fillna 填充缺失值时通用值替换的特殊案例。map 可以用来修改一个对象中的子集的值,但是 replace 提供了更为简单灵活的实现。
data=pd.Series([1,-999,2,-999,-1000,3])
data.replace([-1000,-999],np.nan) # 可以传入 inplace = True, 来改变原对象。
0 1.0
1 NaN
2 2.0
3 NaN
4 NaN
5 3.0
dtype: float64
data.replace([-999,-1000],[np.nan,0]) # 不同的值替换为不同的值
data.replace({-999:np.nan,-1000:0}) # 也可以通过字典传递
data.replace 与 data.str.replace 是不同的,前一个是对字符串进行按元素替代的。
7.2.4 重命名轴索引
和Series 中的值一样,可以通过函数或某种形式的映射对轴标签进行类似的转换,生成新的且带有不同标签的对象,你可以可以在不生成新的数据结构的情况下修改轴。
data = pd.DataFrame(np.arange(12).reshape((3, 4)),
index=['Ohio', 'Colorado', 'New York'],
columns=['one', 'two', 'three', 'four'])
transform=lambda x:x[:4].upper() # 与 series 类似,轴索引也有一个 map 方法。这里只要前四个字母
data.index.map(transform)
Index(['OHIO', 'COLO', 'NEW '], dtype='object')
data.index=data.index.map(transform) # 应用到原 dataframe 上
data.rename(index=str.title,columns=str.upper) # 这个方法不会修改原数据集
ONE TWO THREE FOUR
Ohio 0 1 2 3
Colorado 4 5 6 7
New York 8 9 10 11
data.rename(index={'Ohio':'eee'},columns={'three':'三'},inplace=True) # rename 可以结合字典型对象使用,修改原值
one two 三 four
eee 0 1 2 3
Colorado 4 5 6 7
New York 8 9 10 11
7.2.5 离散化和分箱
连续值经常需要离散化,或者分离成’箱子‘ 进行分析,假如你在研究一群人的数据,想对他们进行分组,放入离散的年龄框中。
并且将这些年龄分为 18~25, 26~35 等若干组,可以使用pandas的 cut 方法:
ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32]
bins=[18,25,35,60,100] # 各组的下界
cats=pd.cut(ages,bins)
cats
[(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]]
pandas 返回的对象是一个特殊的 Categorical 对象。输出的是由pandas.cut 计算出的箱。你可以将它当作一个表示箱名的字符串数组;他在内部包含一个categories 数组,它指定了不同的类别名称以及codes 属性中的ages 数据标签:
cats.codes
array([0, 0, 0, 1, 0, 0, 2, 1, 3, 2, 2, 1], dtype=int8)
cats.categories
IntervalIndex([(18, 25], (25, 35], (35, 60], (60, 100]],
closed='right',
dtype='interval[int64]')
pd.value_counts(cats) # 这个是对 pandas.cut 结果中的箱数量的计数。。
(18, 25] 5
(35, 60] 3
(25, 35] 3
(60, 100] 1
dtype: int64
pd.cut(ages,[18,26,36,61,100],right=False) # 默认是左开右闭,right=False 改一下
[[18, 26), [18, 26), [18, 26), [26, 36), [18, 26), ..., [26, 36), [61, 100), [36, 61), [36, 61), [26, 36)]
Length: 12
Categories (4, interval[int64]): [[18, 26) < [26, 36) < [36, 61) < [61, 100)]
group_names = ['小年轻', '步入中年', '中年', '大叔']
pd.cut(ages, bins, labels=group_names) # 通过 laberls 传递一个列表或数组来传入自定义的箱名。
[小年轻, 小年轻, 小年轻, 步入中年, 小年轻, ..., 步入中年, 大叔, 中年, 中年, 步入中年]
Length: 12
Categories (4, object): [小年轻 < 步入中年 < 中年 < 大叔]
data=np.random.rand(20)
pd.cut(data,4,precision=2) # 传递个整数作为箱的个数,根据最大值最小值计算出等长的箱,precision=2是限制精度为两位。
[(0.75, 0.99], (0.25, 0.5], (0.5, 0.75], (0.5, 0.75], (0.0017, 0.25], ..., (0.75, 0.99], (0.75, 0.99], (0.75, 0.99], (0.5, 0.75], (0.5, 0.75]]
Length: 20
Categories (4, interval[float64]): [(0.0017, 0.25] < (0.25, 0.5] < (0.5, 0.75] < (0.75, 0.99]]
qcut 是一个与分箱密切相关的函数,基于样本分数位进行分箱。使用 cut 通常不会使每个箱具有相同数据量的数据点。但是 qcut 可以获得等长的箱:
分位数(Quantile),亦称分位点,是指将一个随机变量的概率分布范围分为几个等份的数值点,常用的有中位数(即二分位数)、四分位数、百分位数等。
data=np.random.randn(1000) # 正态分布
cats=pd.qcut(data,4)
pd.value_counts(cats)
(0.689, 3.234] 250
(0.013, 0.689] 250
(-0.688, 0.013] 250
(-2.714, -0.688] 250
dtype: int64
cats=pd.qcut(data,[0,0.1,0.5,0.9,1]) # 自定义分位数(0到9之间,包括边),这里就是 1:4:4:1
pd.value_counts(cats)
(0.00551, 1.277] 400
(-1.312, 0.00551] 400 # 这里按大小排一下就是 1 4 4 1
(1.277, 3.178] 100
(-3.726, -1.312] 100
dtype: int64
7.2.6 检测和过滤异常值
data=pd.DataFrame(np.random.randn(1000,4))
data.describe()
0 1 2 3
count 1000.000000 1000.000000 1000.000000 1000.000000
mean -0.046855 -0.037590 -0.025516 0.000239
std 0.996804 0.968972 0.974601 0.985552
min -2.825149 -3.102762 -3.101988 -3.450912
25% -0.716746 -0.679858 -0.708844 -0.696253
50% -0.073610 -0.040148 -0.057884 0.029316
75% 0.636879 0.621425 0.655887 0.702969
max 3.021937 2.704446 3.175656 2.715394
col = data[2]
col[np.abs(col)>3] # 选出第三行中绝对值大于三的值
123 3.175656
612 3.142433
749 -3.101988
Name: 2, dtype: float64
data[(np.abs(data)>3).any(1)] # 选出绝对值大于三的所有行,这行里有一个就行,使用 any() 方法。
0 1 2 3
80 -1.662567 -0.507703 -0.670220 -3.450912
117 -2.185866 0.026732 0.827076 -3.239595
123 -0.930652 1.675178 3.175656 0.043078
155 1.010232 -3.102762 0.343464 -1.268382
278 3.021937 0.703424 2.160534 0.119472
612 -1.131423 -1.296522 3.142433 -0.019182
749 -0.439125 0.085791 -3.101988 0.238118
821 -0.504162 -1.001123 1.387467 -3.163276
np.sign(data).head() # 这个方法根据数据的正负生成 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 # 这样可以将绝对值大于三的值都改成3/-3,来限制数值