利用Python进行数据分析——Pandas(3)


  • 函数应用和映射
    umPy的ufuncs(元素级数组方法)也可用于操作pandas对象:
    在这里插入图片描述
    另一个常见的操作是,将函数应用到由各列或行所形成的一维数组上。DataFrame的apply方法即可实现此功能:
    在这里插入图片描述
    许多最为常见的数组统计功能都被实现成DataFrame的方法(如sum和mean),因此无需使用apply方法。
    除标量值外,传递给apply的函数还可以返回由多个值组成的Series:
In [164]: def f(x):
...: return Series([x.min(), x.max()], index=['min', 'max'])
In [165]: frame.apply(f)
b d e
min -0.555730 0.281746 -1.296221
max 1.246435 1.965781 1.393406

此外,元素级的Python函数也是可以用的。假如你想得到frame中各个浮点值的格式化字符串,使用applymap即可:

In [166]: format = lambda x: '%.2f' % x
In [167]: frame.applymap(format)
Out[167]:
b d e
Utah -0.20 0.48 -0.52
Ohio -0.56 1.97 1.39
Texas 0.09 0.28 0.77
Oregon 1.25 1.01 -1.30

之所以叫做applymap,是因为Series有一个用于应用元素级函数的map方法:

In [168]: frame['e'].map(format)
Out[168]:
Utah -0.52
Ohio 1.39
Texas 0.77
Oregon -1.30
Name: e

  • 排序和排名

根据条件对数据集排序(sorting)也是一种重要的内置运算。要对行或列索引进行排序(按字典顺序),可使用sort_index方法,它将返回一个已排序的新对象:

In [169]: obj = Series(range(4), index=['d', 'a', 'b', 'c'])
In [170]: obj.sort_index()
Out[170]:
a 1
b 2
c 3
d 0

而对于DataFrame,则可以根据任意一个轴上的索引进行排序:

In [174]: frame.sort_index(axis=1, ascending=False)
Out[174]:
d c b a
three 0 3 2 1
one 4 7 6 5

若要按值对Series进行排序,可使用其order方法:

In [177]: obj = Series([4, np.nan, 7, np.nan, -3, 2])
In [178]: obj.order()
Out[178]:
4 -3
5 2
0 4
2 7
1 NaN
3 NaN

在DataFrame上,你可能希望根据一个或多个列中的值进行排序。将一个或多个列的名字传递给by选项即可达到该目的:

In [182]: frame.sort_index(by=['a', 'b'])
Out[182]:
a b
2 0 -3
0 0 4
3 1 2
1 1 7

排名(ranking)跟排序关系密切,且它会增设一个排名值(从1开始,一直到数组中有效数据的数量)。它跟numpy.argsort产生的间接排序索引差不多,只不过它可以根据某种规则破坏平级关系。接下来介绍Series和DataFrame的rank方法。默认情况下,rank是通过“为各组分配一个平均排名”的方式破坏平级关系的:

In [183]: obj = Series([7, -5, 7, 4, 2, 0, 4])
In [184]: obj.rank()
Out[184]:
0 6.5
1 1.0
2 6.5
3 4.5
4 3.0
5 2.0
6 4.5

也可以根据值在原数据中出现的顺序给出排名:

In [185]: obj.rank(method='first')
Out[185]:
0 6
1 1
2 7
3 4
4 3
5 2
6 5

当然,你也可以按降序进行排名:

In [186]: obj.rank(ascending=False, method='max')
Out[186]:
0 2
1 7
2 2
3 4
4 5
5 6
6 4

在这里插入图片描述


  • 带有重复值的轴索引

直到目前为止,我所介绍的所有范例都有着唯一的轴标签(索引值)。虽然许多pandas函数(如reindex)都要求标签唯一,但这并不是强制性的。我们来看看下面这个简单的带有重复索引值的Series:(索引的is_unique属性可以告诉你它的值是否是唯一的)

In [190]: obj = Series(range(5), index=['a', 'a', 'b', 'b', 'c'])
In [191]: obj
Out[191]:
a 0
a 1
b 2
b 3
c 4
In [192]: obj.index.is_unique
Out[192]: False

对于带有重复值的索引,数据选取的行为将会有些不同。如果某个索引对应多个值,则返回一个Series;而对应单个值的,则返回一个标量值。对DataFrame的行进行索引时也是如此。

汇总和计算描述统计

pandas对象拥有一组常用的数学和统计方法。它们大部分都属于约简和汇总统计,用于从Series中提取单个值(如sum或mean)或从DataFrame的行或列中提取一个Series。跟对应的NumPy数组方法相比,它们都是基于没有缺失数据的假设而构建的。接下来看一个简单的DataFrame:

In [198]: df = DataFrame([[1.4, np.nan], [7.1, -4.5],
...: [np.nan, np.nan], [0.75, -1.3]],
...: index=['a', 'b', 'c', 'd'],
...: columns=['one', 'two'])
In [199]: df
Out[199]:
one two
a 1.40 NaN
b 7.10 -4.5
c NaN NaN
d 0.75 -1.3

调用DataFrame的sum方法将会返回一个含有列小计的Series:

In [200]: df.sum()
Out[200]:
one 9.25
two -5.80

传入axis=1将会按行进行求和运算:

In [201]: df.sum(axis=1)
Out[201]:
a 1.40
b 2.60
c NaN
d -0.55

NA值会自动被排除,除非整个切片(这里指的是行或列)都是NA。通过skipna选项可以禁用该功能:

In [202]: df.mean(axis=1, skipna=False)
Out[202]:
a NaN
b 1.300
c NaN
d -0.275

  • 唯一值、值计数以及成员资格

还有一类方法可以从一维Series的值中抽取信息。以下面这个Series为例:

from pandas import Series
obj=Series(['c', 'a', 'd', 'a', 'a', 'b', 'b', 'c', 'c'])
uniques=obj.unique()
print(uniques)
#output
['c' 'a' 'd' 'b']

返回的唯一值是未排序的,如果需要的话,可以对结果再次进行排序(uniques.sort())。value_counts用于计算一个Series中各值出现的频率:

In [220]: obj.value_counts()
Out[220]:
c 3
a 3
b 2
d 1

为了便于查看,结果Series是按值频率降序排列的。value_counts还是一个顶级pandas方法,可用于任何数组或序列:

In [221]: pd.value_counts(obj.values, sort=False)
Out[221]:
a 3
b 2
c 3
d 1

最后是isin,它用于判断矢量化集合的成员资格,可用于选取Series中或DataFrame列中数据的子集:

from pandas import Series
obj=Series(['c', 'a', 'd', 'a', 'a', 'b', 'b', 'c', 'c'])
mask=obj.isin(['b','c'])
print(mask)
print(obj[mask])
#output
0     True
1    False
2    False
3    False
4    False
5     True
6     True
7     True
8     True
dtype: bool
0    c
5    b
6    b
7    c
8    c
dtype: object

处理缺失数据

缺失数据(missing data)在大部分数据分析应用中都很常见。pandas的设计目标之一就是让缺失数据的处理任务尽量轻松。例如,pandas对象上的所有描述统计都排除了缺失数据,正如我们在本章稍早的地方所看到的那样。

pandas使用浮点值NaN(Not a Number)表示浮点和非浮点数组中的缺失数据。它只是一个便于被检测出来的标记而已:(Python内置的None值也会被当做NA处理)

string_data = Series(['aardvark', 'artichoke', np.nan, 'avocado'])
print(string_data.isnull())
string_data[0]=None
print(string_data.isnull())

#output
0    False
1    False
2     True
3    False
dtype: bool
0     True
1    False
2     True
3    False
dtype: bool

NA处理方法:
在这里插入图片描述


  • 滤除缺失数据

过滤掉缺失数据的办法有很多种。纯手工操作永远都是一个办法,但dropna可能会更实用一些。对于一个Series,dropna返回一个仅含非空数据和索引值的Series:

In [234]: from numpy import nan as NA
In [235]: data = Series([1, NA, 3.5, NA, 7])
In [236]: data.dropna()
Out[236]:
0 1.0
2 3.5
4 7.0

当然,也可以通过布尔型索引达到这个目的:

In [237]: data[data.notnull()]
Out[237]:
0 1.0
2 3.5
4 7.0

而对于DataFrame对象,事情就有点复杂了。你可能希望丢弃全NA或含有NA的行或列。dropna默认丢弃任何含有缺失值的行:

data = DataFrame([[1., 6.5, 3.], [1., NA, NA],[NA, NA, NA], [NA, 6.5, 3.]])
print(data.dropna())
#output
     a    b    c
0  1.0  6.5  3.0

传入how='all’将只丢弃全为NA的那些行:(要用这种方式丢弃列,只需传入axis=1即可)

print(data.dropna(how='all'))
data.ix[0,2]=NA
data.ix[3,2]=NA
print(data.dropna(how='all',axis=1))
#output
     0    1    2
0  1.0  6.5  3.0
1  1.0  NaN  NaN
3  NaN  6.5  3.0
     0    1
0  1.0  6.5
1  1.0  NaN
2  NaN  NaN
3  NaN  6.5

  • 填充缺失数据

你可能不想滤除缺失数据(有可能会丢弃跟它有关的其他数据),而是希望通过其他方式填补那些“空洞”。对于大多数情况而言,fillna方法是最主要的函数。通过一个常数调用fillna就会将缺失值替换为那个常数值:

In [250]: df.fillna(0)
Out[250]:
0 1 2
0 -0.577087 0.000000 0.000000
1 0.523772 0.000000 0.000000
2 -0.713544 0.000000 0.000000
3 -1.860761 0.000000 0.560145
4 -1.265934 0.000000 -1.063512
5 0.332883 -2.359419 -0.199543
6 -1.541996 -0.970736 -1.307030

若是通过一个字典调用fillna,就可以实现对不同的列填充不同的值:

In [251]: df.fillna({1: 0.5, 3: -1})
Out[251]:
0 1 2
0 -0.577087 0.500000 NaN
1 0.523772 0.500000 NaN
2 -0.713544 0.500000 NaN
3 -1.860761 0.500000 0.560145
4 -1.265934 0.500000 -1.063512
5 0.332883 -2.359419 -0.199543
6 -1.541996 -0.970736 -1.307030

fillna默认会返回新对象,但也可以对现有对象进行就地修改:

# 总是返回被填充对象的引用
In [252]: _ = df.fillna(0, inplace=True)
In [253]: df
Out[253]:
0 1 2
0 -0.577087 0.000000 0.000000
1 0.523772 0.000000 0.000000
2 -0.713544 0.000000 0.000000
3 -1.860761 0.000000 0.560145
4 -1.265934 0.000000 -1.063512
5 0.332883 -2.359419 -0.199543
6 -1.541996 -0.970736 -1.307030

对reindex有效的那些插值方法也可用于fillna。
只要稍微动动脑子,你就可以利用fillna实现许多别的功能。比如说,你可以传入Series的平均值或中位数:

In [259]: data = Series([1., NA, 3.5, NA, 7])
In [260]: data.fillna(data.mean())
Out[260]:
0 1.000000
1 3.833333
2 3.500000
3 3.833333
4 7.000000
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值