DataFrame常常出现重复行
data = DataFrame({'k1': ['one'] * 3 + ['two'] * 4,
'k2': [1, 1, 2, 3, 3, 4, 4]})
DataFrame的duplicated方法返回布尔型的Series,表示各行是否是重复行
data.duplicated()
可以使用drop_duplicates删除重复行
data.drop_duplicates()
上面的两个方法默认判断全部列,当然也可以指定部分列进行重复项判断
data['v1'] = range(7)
data.drop_duplicates(['k1'])
两个方法默认保留的是第一个出现的值组合,当take_last=True时,则保留最后一个
data.drop_duplicates(['k1', 'k2'], take_last=True)
利用函数或映射进行数据转换
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]})
此时,假设添加一列表示该肉类来源的动物类型,首先定义肉类到动物的映射
meat_to_animal = {
'bacon': 'pig',
'pulled pork': 'pig',
'pastrami': 'cow',
'corned beef': 'cow',
'honey ham': 'pig',
'nova lox': 'salmon'
}
Series的map方法可以接受一个函数,或含有映射关系的字典对象
data['animal'] = data['food'].map(str.lower).map(meat_to_animal)
或者只是传入lambda函数
data['food'].map(lambda x: meat_to_animal[x.lower()])
替换值
使用fillna方法填充缺失数据可以视为数值替换的特殊情况。虽然map可以修改对象的数据子集,但是使用
replace则更为方便。
data = Series([1., -999., 2., -999., -1000., 3.])
通过NA替换-999
data.replace(-999, np.nan)
替换多个值
data.replace([-999, -1000], np.nan)
如果需要对不同的值进行不同的替换,可以传入替换关系的列表
data.replace([-999, -1000], [np.nan, 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)
或者是使用
data.rename(index=str.title, columns=str.upper)
可以结合字典对象实现对部分标签的更新
data.rename(index={'OHIO': 'INDIANA'},
columns={'three': 'peekaboo'})
rename实现帮助实现了赋值DataFrame,并对索引和列标签进行赋值。
如果需要修改某个数据集,需要传入replace=True
_ = data.rename(index={'OHIO': 'INDIANA'}, inplace=True)
离散化和面元划分
为便于分析,连续数据常常被离散化或拆分为“面元”。
假设有一组人员数据,希望划分为不同的年龄组
ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32]
bins = [18, 25, 35, 60, 100]
cats = pd.cut(ages, bins)
pandas返回的是特殊的Categorical对象,它含有一个表示不同分类名称的levels数组,以及一个为年龄数据进行标号的labels属性
cats.labels
cats.levels
pd.value_counts(cats)
通过right=False设置为左闭右开区间
pd.cut(ages, [18, 26, 36, 61, 100], right=False)
设置自己的面元名称
group_names = ['Youth', 'YoungAdult', 'MiddleAged', 'Senior']
pd.cut(ages, bins, labels=group_names)
如果cut传入的是面元的数量而不是确切的面元边界,则根据数据的最小值和最大值计算等长面元
data = np.random.rand(20)
pd.cut(data, 4, precision=2)
qcut是类似于cut的函数,它可以根据样本分位数对数据进行面元划分
data = np.random.randn(1000) # Normally distributed
cats = pd.qcut(data, 4) # Cut into quartiles
qcut也可以自定义分位数
pd.qcut(data, [0, 0.1, 0.5, 0.9, 1.])
检测和过滤异常值
异常值的过滤或变换运算在很大程度上就是数组运算。
np.random.seed(12345)
data = DataFrame(np.random.randn(1000, 4))
data.describe()
寻找某列绝对值超过3的值
col = data[3]
col[np.abs(col) > 3]
选出全部含有“超过3或-3的值”的行
data[(np.abs(data) > 3).any(1)]
将上面筛选的行的值限制在-3到3的区间
data[np.abs(data) > 3] = np.sign(data) * 3
排列和随机采样
利用numpy.random.permutation函数可以轻松实现对Series或DataFrame的列排列工作
df = DataFrame(np.arange(5 * 4).reshape((5, 4)))
sampler = np.random.permutation(5)
可以在基于ix的索引操作或take函数使用排序后的数组
df.take(sampler)
截取子集
df.take(np.random.permutation(len(df))[:3])
计算指标/哑变量
另一种常用于统计建模或机器学习的转换方式是:将分类变量转换为“哑变量矩阵’或”指标矩阵“
如果DataFrame的某一列中含有k个不同的值,则可以拍生成k列矩阵或DataFrame
df = DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'b'],
'data1': range(6)})
pd.get_dummies(df['key'])
给指标DataFrame的列加上一个前缀
dummies = pd.get_dummies(df['key'], prefix='key')
与其他数据合并
df_with_dummy = df[['data1']].join(dummies)
如果DataFrame中的某行同属多个分类