numpy Head 与 Tail、属性与底层数据、加速操作、二进制操作、描述性统计、函数应用

基础用法

本节介绍 Pandas 数据结构的基础用法。下列代码创建上一节用过的示例数据对象:

In [1]: index = pd.date_range('1/1/2000', periods=8)

In [2]: s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])

In [3]: df = pd.DataFrame(np.random.randn(8, 3), index=index,
   ...:                   columns=['A', 'B', 'C'])
   ...: 

n=10
index=pd.date_range('20000101',periods=n)
print(index)
s=pd.Series(np.random.rand(8),index=list(string.ascii_letters[:8]))
# 这是一个方便用户从 Matlab 移植代码的函数,并包装了 random_sample。该函数采用元组来指定输出的大小,这与 numpy.zeros 和 numpy.ones 等其他 NumPy 函数一致。
# 创建给定形状的数组,并用 [0, 1) 上均匀分布的随机样本填充它。
print(s)
df=pd.DataFrame(np.random.rand(n,8),index=index,columns=list(string.ascii_letters[:8]))
print(df)


DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-03', '2000-01-04',
               '2000-01-05', '2000-01-06', '2000-01-07', '2000-01-08',
               '2000-01-09', '2000-01-10'],
              dtype='datetime64[ns]', freq='D')
a    0.516861
b    0.220140
c    0.667483
d    0.550804
e    0.631757
f    0.494191
g    0.908128
h    0.544240
dtype: float64
                   a         b         c         d         e         f  \
2000-01-01  0.951364  0.165370  0.630935  0.898385  0.040457  0.846490   
2000-01-02  0.636938  0.081687  0.899861  0.887537  0.427308  0.678841   
2000-01-03  0.954679  0.590853  0.779015  0.758092  0.318983  0.797294   
2000-01-04  0.000130  0.314111  0.346645  0.382747  0.644762  0.215349   
2000-01-05  0.150452  0.720875  0.363832  0.954863  0.298944  0.880833   
2000-01-06  0.006456  0.399737  0.081659  0.310611  0.495450  0.466368   
2000-01-07  0.386115  0.415283  0.238122  0.993131  0.114366  0.098060   
2000-01-08  0.325408  0.339976  0.122992  0.035576  0.910130  0.398590   
2000-01-09  0.780130  0.928054  0.853599  0.879124  0.095143  0.117855   
2000-01-10  0.764207  0.449446  0.367501  0.709571  0.872381  0.210814   

                   g         h  
2000-01-01  0.893280  0.336661  
2000-01-02  0.182542  0.554913  
2000-01-03  0.470463  0.322261  
2000-01-04  0.513242  0.928213  
2000-01-05  0.772144  0.953689  
2000-01-06  0.404961  0.624106  
2000-01-07  0.414454  0.517201  
2000-01-08  0.198384  0.800897  
2000-01-09  0.132946  0.581366  
2000-01-10  0.578434  0.481795  

Head 与 Tail

head()open in new windowtail()open in new window 用于快速预览 Series 与 DataFrame,默认显示 5 条数据,也可以指定显示数据的数量。

In [4]: long_series = pd.Series(np.random.randn(1000))

In [5]: long_series.head()
Out[5]: 
0   -1.157892
1   -1.344312
2    0.844885
3    1.075770
4   -0.109050
dtype: float64

In [6]: long_series.tail(3)
Out[6]: 
997   -0.289388
998   -1.020544
999    0.589993
dtype: float64

属性与底层数据

Pandas 可以通过多个属性访问元数据:

  • shape:
    • 输出对象的轴维度,与 ndarray 一致
  • 轴标签
    • Series: Index (仅有此轴)
    • DataFrame: Index (行) 与列 column

注意: 为属性赋值是安全的

In [7]: df[:2]
Out[7]: 
                   A         B         C
2000-01-01 -0.173215  0.119209 -1.044236
2000-01-02 -0.861849 -2.104569 -0.494929

In [8]: df.columns = [x.lower() for x in df.columns]

In [9]: df
Out[9]: 
                   a         b         c
2000-01-01 -0.173215  0.119209 -1.044236
2000-01-02 -0.861849 -2.104569 -0.494929
2000-01-03  1.071804  0.721555 -0.706771
2000-01-04 -1.039575  0.271860 -0.424972
2000-01-05  0.567020  0.276232 -1.087401
2000-01-06 -0.673690  0.113648 -1.478427
2000-01-07  0.524988  0.404705  0.577046
2000-01-08 -1.715002 -1.039268 -0.370647

Pandas 对象(Indexopen in new windowSeriesopen in new windowDataFrameopen in new window)相当于数组的容器,用于存储数据、执行计算。大部分类型的底层数组都是 numpy.ndarrayopen in new window。不过,Pandas 与第三方支持库一般都会扩展 NumPy 类型系统,添加自定义数组(见数据类型open in new window)。

.array 属性用于提取 Indexopen in new windowSeriesopen in new window 里的数据。

In [10]: s.array
Out[10]: 
<PandasArray>
[ 0.4691122999071863, -0.2828633443286633, -1.5090585031735124,
 -1.1356323710171934,  1.2121120250208506]
Length: 5, dtype: float64

In [11]: s.index.array
Out[11]: 
<PandasArray>
['a', 'b', 'c', 'd', 'e']
Length: 5, dtype: object

arrayopen in new window 一般指 ExtensionArrayopen in new window。至于什么是 ExtensionArrayopen in new window 及 Pandas 为什么要用 ExtensionArrayopen in new window 不是本节要说明的内容。更多信息请参阅数据类型open in new window

提取 NumPy 数组,用 to_numpy()open in new windownumpy.asarray()

In [12]: s.to_numpy()
Out[12]: array([ 0.4691, -0.2829, -1.5091, -1.1356,  1.2121])

In [13]: np.asarray(s)
Out[13]: array([ 0.4691, -0.2829, -1.5091, -1.1356,  1.2121])

SeriesIndex 的类型是 ExtensionArrayopen in new window 时, to_numpy()open in new window 会复制数据,并强制转换值。详情见数据类型open in new window

to_numpy()open in new window 可以控制 numpy.ndarrayopen in new window 生成的数据类型。以带时区的 datetime 为例,NumPy 未提供时区信息的 datetime 数据类型,Pandas 则提供了两种表现形式:

  1. 一种是带 Timestampopen in new windownumpy.ndarrayopen in new window,提供了正确的 tz 信息。
  2. 另一种是 datetime64[ns],这也是一种 numpy.ndarrayopen in new window,值被转换为 UTC,但去掉了时区信息。

时区信息可以用 dtype=object 保存。

In [14]: ser = pd.Series(pd.date_range('2000', periods=2, tz="CET"))

In [15]: ser.to_numpy(dtype=object)
Out[15]: 
array([Timestamp('2000-01-01 00:00:00+0100', tz='CET', freq='D'),
       Timestamp('2000-01-02 00:00:00+0100', tz='CET', freq='D')],
      dtype=object)

或用 dtype='datetime64[ns]' 去除。

In [16]: ser.to_numpy(dtype="datetime64[ns]")
Out[16]: 
array(['1999-12-31T23:00:00.000000000', '2000-01-01T23:00:00.000000000'],
      dtype='datetime64[ns]')

提取 DataFrame 里的原数据稍微有点复杂。DataFrame 里所有列的数据类型都一样时,DataFrame.to_numpy()open in new window 返回底层数据:

In [17]: df.to_numpy()
Out[17]: 
array([[-0.1732,  0.1192, -1.0442],
       [-0.8618, -2.1046, -0.4949],
       [ 1.0718,  0.7216, -0.7068],
       [-1.0396,  0.2719, -0.425 ],
       [ 0.567 ,  0.2762, -1.0874],
       [-0.6737,  0.1136, -1.4784],
       [ 0.525 ,  0.4047,  0.577 ],
       [-1.715 , -1.0393, -0.3706]])

DataFrame 为同构型数据时,Pandas 直接修改原始 ndarray,所做修改会直接反应在数据结构里。对于异质型数据,即 DataFrame 列的数据类型不一样时,就不是这种操作模式了。与轴标签不同,不能为值的属性赋值。

注意

处理异质型数据时,输出结果 ndarray 的数据类型适用于涉及的各类数据。若 DataFrame 里包含字符串,输出结果的数据类型就是 object。要是只有浮点数或整数,则输出结果的数据类型是浮点数。

以前,Pandas 推荐用 Series.valuesopen in new windowDataFrame.valuesopen in new window 从 Series 或 DataFrame 里提取数据。旧有代码库或在线教程里仍在用这种操作,但 Pandas 已改进了此功能,现在,推荐用 .arrayto_numpy 提取数据,别再用 .values 了。.values 有以下几个缺点:

  1. Series 含扩展类型open in new window时,Series.valuesopen in new window 无法判断到底是该返回 NumPy array,还是返回 ExtensionArray。而 Series.arrayopen in new window 则只返回 ExtensionArrayopen in new window,且不会复制数据。Series.to_numpy()open in new window 则返回 NumPy 数组,其代价是需要复制、并强制转换数据的值。
  2. DataFrame 含多种数据类型时,DataFrame.valuesopen in new window 会复制数据,并将数据的值强制转换同一种数据类型,这是一种代价较高的操作。DataFrame.to_numpy()open in new window 则返回 NumPy 数组,这种方式更清晰,也不会把 DataFrame 里的数据都当作一种类型。

加速操作

借助 numexprbottleneck 支持库,Pandas 可以加速特定类型的二进制数值与布尔操作。

处理大型数据集时,这两个支持库特别有用,加速效果也非常明显。 numexpr 使用智能分块、缓存与多核技术。bottleneck 是一组专属 cython 例程,处理含 nans 值的数组时,特别快。

请看下面这个例子(DataFrame 包含 100 列 X 10 万行数据):

操作 0.11.0版 (ms) 旧版 (ms) 提升比率
df1 > df2 13.32 125.35 0.1063
df1 * df2 21.71 36.63 0.5928
df1 + df2 22.04 36.50 0.6039

强烈建议安装这两个支持库,更多信息,请参阅推荐支持库open in new window

这两个支持库默认为启用状态,可用以下选项设置:

0.20.0 版新增。

pd.set_option('compute.use_bottleneck', False)
pd.set_option('compute.use_numexpr', False)

二进制操作

Pandas 数据结构之间执行二进制操作,要注意下列两个关键点:

  • 多维(DataFrame)与低维(Series)对象之间的广播机制;
  • 计算中的缺失值处理。

这两个问题可以同时处理,但下面先介绍怎么分开处理。

匹配/广播机制

DataFrame 支持 add()open in new windowsub()open in new windowmul()open in new windowdiv()open in new windowradd()open in new windowrsub()open in new window 等方法执行二进制操作。广播机制重点关注输入的 Series。通过 axis 关键字,匹配 indexcolumns 即可调用这些函数。

In [18]: df = pd.DataFrame({
   
    
    
   ....:     'one': pd.Series(np.random.randn(3), index=['a', 'b', 'c']),
   ....:     'two': pd.Series(np.random.randn(4), index=['a', 'b', 'c', 'd']),
   ....:     'three': pd.Series(np.random.randn(3), index=['b', 'c', 'd'])})
   ....: 

In [19]: df
Out[19]: 
        one       two     three
a  1.394981  1.772517       NaN
b  0.343054  1.912123 -0.050390
c  0.695246  1.478369  1.227435
d       NaN  0.279344 -0.613172

In [20]: row = df.iloc[1]

In [21]: column = df['two']

In [22]: df.sub(row, axis='columns')
Out[22]: 
        one       two     three
a  1.051928 -0.139606       NaN
b  0.000000  0.000000  0.000000
c  0.352192 -0.433754  1.277825
d       NaN -1.632779 -0.562782

In [23]: df.sub(row, axis=1)
Out[23]: 
        one       two     three
a  1.051928 -0.139606       NaN
b  0.000000  0.000000  0.000000
c  0.352192 -0.433754  1.277825
d       NaN -1.632779 -0.562782

In [24]: df.sub(column, axis='index')
Out[24]: 
        one  two     three
a -0.377535  0.0       NaN
b -1.569069  0.0 -1.962513
c -0.783123  0.0 -0.250933
d       NaN  0.0 -0.892516

In [25]: df.sub(column, axis=0)
Out[25]: 
        one  two     three
a -0.377535  0.0       NaN
b -1.569069  0.0 -1.962513
c -0.783123  0.0 -0.250933
d       NaN  0.0 -0.892516

pandas中iat和iloc都是用于按位置选择数据的方法,二者有些细微的区别:

  1. iat是按整数位置选择单个元素,而iloc是按整数位置选择子集。

  2. iat只能接受整数索引,而iloc可以接受slice对象进行切片。

  3. iat的索引从0开始,iloc的索引从0或1开始取决于索引是否含有0。

例子:

import pandas as pd

df = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB'), index=[0, 1])

# iat选择单个元素
df.iat[0,1] # 2

# iloc选择子集
df.iloc[0:1,0:1] 
#     A
# 0  1

# iloc支持切片
df.iloc[:,0:1]
#     A 
# 0  1
# 1  3

总结:

  • iat用于按位置选择单个元素
  • iloc用于按位置选择子集,支持切片
  • iloc索引通常从0开始,iat索引总是从0开始

df.sub(column, axis=‘index’)中的axis参数指定进行计算的轴向。

在Pandas中,axis=0或axis='index’表示沿着行的方向进行计算,即对各列进行操作。

axis=1或axis='columns’表示沿着列的方向进行计算,即对各行进行操作。

例如:

import pandas as pd

df = pd.DataFrame([[1, 2], [3, 4]], columns=['A', 'B'])

# 沿行方向,以A列为基准,计算其他列与A列的差值
df.sub(df['A'], axis='index')

# 结果:
   A  B
0  0  1
1  0  1

# 沿列方向,以行0为基准,计算其他行与行0的差值 
df.sub(df.iloc[0], axis='columns')

# 结果:
     A    B
0  0.0  0.0  
1  2.0  2.0

所以在df.sub(column, axis=‘index’)中,表示以列column为基准,计算df中其他列与该列的差值。

axis参数在Pandas中非常常用,可以灵活地指定计算的方向。

还可以用 Series 对齐多层索引 DataFrame 的某一层级。

In [26]: dfmi = df.copy()

In [27]: dfmi.index = pd.MultiIndex.from_tuples([(1, 'a'), (1, 'b'),
   ....:                                         (1, 'c'), (2, 'a')],
   ....:                                        names=['first', 'second'])
   ....: 

In [28]: dfmi.sub(column, axis=0, level='second')
Out[28]: 
                   one       two     three
first second                              
1     a      -0.377535  0.000000       NaN
      b      -1.569069  0.000000 -1.962513
      c      -0.783123  0.000000 -0.250933
2     a            NaN -1.493173 -2.385688

Series 与 Index 还支持 divmod()open in new window 内置函数,该函数同时执行向下取整除与模运算,返回两个与左侧类型相同的元组。示例如下:

In [29]: s = pd.Series(np.arange(10))

In [30]: s
Out[30]: 
0    0
1    1
2    2
3    3
4    4
5    5
6    6
7    7
8    8
9    9
dtype: int64

In [31]: div, rem = divmod(s, 3)

In [32]: div
Out[32]: 
0    0
1    0
2    0
3    1
4    1
5    1
6    2
7    2
8    2
9    3
dtype: int64

In [33]: rem
Out[33]: 
0    0
1    1
2    2
3    0
4    1
5    2
6    0
7    1
8    2
9    0
dtype: int64

In [34]: idx = pd.Index(np.arange(10))

In [35]: idx
Out[35]: Int64Index([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype='int64')

In [36]: div, rem = divmod(idx, 3)

In [37]: div
Out[37]: Int64Index([0, 0, 0, 1, 1, 1, 2, 2, 2, 3], dtype='int64')

In [38]: rem
Out[38]: Int64Index([0, 1, 2, 0, 1, 2, 0, 1, 2, 0]

猜你喜欢

转载自blog.csdn.net/m0_61634551/article/details/134170593