@合并重叠数据
还有一种数据组合问题不能用简单的合并或连接运算来处理。比如说,你可能有索引全部或部分重叠的两个数据集
使用numpy的where函数,它用于表达一种矢量化的if - else
a = pd.Series([np.nan, 2.5, np.nan, 3.5, 4.5, np.nan], index = ['f', 'e', 'd', 'c', 'b', 'a']) b = pd.Series(np.arange(len(a), dtype = np.float64), index = ['f', 'e', 'd', 'c', 'b', 'a']) b[-1] = np.nan a b np.where(pd.isnull(a), b, a) a Out[117]: f NaN e 2.5 d NaN c 3.5 b 4.5 a NaN dtype: float64 b Out[118]: f 0.0 e 1.0 d 2.0 c 3.0 b 4.0 a NaN dtype: float64 np.where(pd.isnull(a), b, a) Out[119]: array([ 0. , 2.5, 2. , 3.5, 4.5, nan])
Series有一个combine_first方法,实现的也是一样的功能,而且会进行数据对齐
b[:-2].combine_first(a[2:]) Out[120]: a NaN b 4.5 c 3.0 d 2.0 e 1.0 f 0.0 dtype: float64
对于DataFrame, combine_first自然也会在列上做同样的事情,因此你可以将其看做:用参数对象中的数据为调用者对象的缺失数据打补丁
df1 = pd.DataFrame({'a': [1., np.nan, 5., np.nan], 'b': [np.nan, 2., np.nan, 6.], 'c': range(2, 18, 4)}) df2 = pd.DataFrame({'a': [5., 4., np.nan, 3., 7.], 'b': [np.nan, 3., 4., 6., 8.]}) df1
Out[123]:
a b c
0 1.0 NaN 2
1 NaN 2.0 6
2 5.0 NaN 10
3 NaN 6.0 14
df2
Out[124]:
a b
0 5.0 NaN
1 4.0 3.0
2 NaN 4.0
3 3.0 6.0
4 7.0 8.0
#df1中的缺失值用df2中的值补充 df1.combine_first(df2)
Out[125]:
a b c
0 1.0 NaN 2.0
1 4.0 2.0 6.0
2 5.0 4.0 10.0
3 3.0 6.0 14.0
4 7.0 8.0 NaN
@重塑和轴向旋转
用于重新排列表格型数据的基础运算。这些函数也称作重塑(reshape)或轴向旋转(pivot)运算
(1)重塑层次化索引
层次化索引为DF数据的重排任务提供了一种具有良好一致性的方式。主要功能:
- stack: 将数据的列“旋转”为行
- unstack: 将数据的行“旋转”为列
#重塑和轴旋转 data = pd.DataFrame(np.arange(6).reshape((2, 3)), index = pd.Index(['Ohio', 'Colorado'], name = 'state'), columns = pd.Index(['one', 'two', 'three'], name = 'number')) data
Out[127]:
number one two three
state
Ohio 0 1 2
Colorado 3 4 5
#使用该数据的stack方法即可将列转换为行,得到一个Series result = data.stack() result Out[129]: state number Ohio one 0 two 1 three 2 Colorado one 3 two 4 three 5 dtype: int32
#对于 一个层次化索引的Series, 你可以用unstack将其重排为一个DataFrame result.unstack() Out[134]: number one two three state Ohio 0 1 2 Colorado 3 4 5
默认情况下,unstack操作的是最内层(stack也是如此)。传入分层级别的编号或名称即可对其他级别进行unstack操作:
(2)将长格式旋转为宽格式
时间序列数据通常是以所谓的“长格式” 或 “堆叠格式”存储在数据库和CSV中的
2、数据转换
之前是合并数据集和重排数据集,另一类重要操作则是过滤、清理以及其他的转换工作。
(1)移除重复数据
data = pd.DataFrame({'K1': ['one']*3+['two']*4, 'K2': [1, 1, 2, 3, 3, 4, 4]}) data
Out[10]:
K1 K2
0 one 1
1 one 1
2 one 2
3 two 3
4 two 3
5 two 4
6 two 4
duplicated方法返回一个布尔型Series,表示各行是否是重复行:
data.duplicated() Out[11]: 0 False 1 True 2 False 3 False 4 True 5 False 6 True dtype: bool
还有一个与此相关的drop_duplicates方法,它用于返回一个移除了重复行的DataFrame
data.drop_duplicates() Out[13]: K1 K2 0 one 1 2 one 2 3 two 3 5 two 4
这两个方法默认会判断全部列,也可以指定部分列进行重复项判断。假设你还有一列值,且只希望根据K1列过滤重复项:
data['v1'] = range(7) data.drop_duplicates(['K1']) Out[15]: K1 K2 v1 0 one 1 0 3 two 3 3
duplicates和drop_duplicates默认保留的是第一个出现 的值组合,传入take_last = True 则保留最后一个
data.drop_duplicates(['K1', 'K2'], take_last = True) Out[16]: K1 K2 v1 1 one 1 1 2 one 2 2 4 two 3 4 6 two 4 6
(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 Out[4]: 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', 'honey ham': 'pig', 'nova lox': 'salmon'}
Series的map方法可以接受一个函数或含有映射关系的字典型对象,但是这里有一个小问题,即有些肉类的首字母大写了,而另一些则没有,因此,我们还需要将各个值转换为小写:
data['animal'] = data['food'].map(str.lower).map(meat_to_animal) data Out[10]: 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['food'].map(lambda x: meat_to_animal[x.lower()]) Out[22]: 0 pig 1 pig 2 pig 3 COW 4 COW 5 pig 6 COW 7 pig 8 salmon Name: food, dtype: object
使用map是一种实现元素转换以及其他数据清理工作的便捷方式
(3)替换值
利用fillna方法填充缺失数据可以看做值替换的一种特殊情况,虽然前面 提到的map可以用于修改对象的数据子集,而replace则提供了一种实现该功能的更简单、更灵活的方式
#替换值 data = pd.Series([1., -999., -2, -999., -1000., 3.]) data
Out[24]:
0 1.0
1 -999.0
2 -2.0
3 -999.0
4 -1000.0
5 3.0
dtype: float64
#用NaN代替-999 data.replace(-999, np.nan)
Out[25]:
0 1.0
1 NaN
2 -2.0
3 NaN
4 -1000.0
5 3.0
dtype: float64
#如果你希望一次性替换多个值,可传入一个由待替换值组成的列表以及一个替换值 data.replace([-999, -1000], np.nan)
Out[26]:
0 1.0
1 NaN
2 -2.0
3 NaN
4 NaN
5 3.0
dtype: float64
#如果你希望对不同的值进行替换,则传入一个由替换关系组成的列表即可 data.replace([-999, -1000], [np.nan, 0]) Out[27]: 0 1.0 1 NaN 2 -2.0 3 NaN 4 0.0 5 3.0 dtype: float64
传入的参数也可以是字典
data.replace({-999: np.nan, -1000: 0}) Out[28]: 0 1.0 1 NaN 2 -2.0 3 NaN 4 0.0 5 3.0 dtype: float64
(4)重命名轴索引