Numpy与Pandas入门笔记

Numpy部分

1. Ndarray 对象

NumPy 最重要的一个特点是其 N 维数组对象 ndarray,它是一系列同类型数据的集合,以 0 下标为开始进行集合中元素的索引。

从上面的描述中,我们可以得出Ndarray对象的两个重要特点:

  • ndarray中的每个元素的数据类型相同;
  • ndarray 中的每个元素在内存中都有相同存储大小的区域;

Pandas部分

1. Pandas数据结构

Pandas处理以下三个数据结构:

  • 系列 Series
  • 数据帧 DataFrame
  • 面板 Panel

考虑这些数据结构的最好方法是,较高维数据结构是其较低维数据结构的容器

例如,DataFrameSeries的容器,PanelDataFrame的容器

数据结构 维数 描述
系列 1 1D标记均匀数组,大小不变
数据帧 2 一般2D标记,大小可变的表结构与潜在的异质类型的列
面板 3 一般3D标记,大小可变数组

1.1. Series

系列是具有均匀数据的一维数组结构。例如,以下系列是整数:10,23,56,...的集合

特点:

  • 均匀数据;
  • 尺寸大小不变;
  • 数据的值可变;

1.2. DataFrame

数据帧(DataFrame)是一个具有异构数据的二维数组

姓名 年龄 性别 等级
Maxsu 25 4.45
Katie 34 2.78
Vina 46 3.9

数据以行和列表示。每列表示一个属性,每行代表一个人

上面数据帧中四列的数据类型如下:

类型
姓名 字符串
年龄 整数
性别 字符串
等级 浮点型

2. Pandas快速入门

2.1. 对象创建

(1)创建Series

通过传递值列表来创建一个系列,让Pandas创建一个默认的整数索引:

1
2
3
4
5
6
7
8
9
10
s = pd.Series([1,3,5,np.nan,6,8])

>> s
0 1.0
1 3.0
2 5.0
3 NaN
4 6.0
5 8.0
dtype: float64

(2)创建DataFrame

通过传递numpy数组,使用datetime索引和标记列来创建DataFrame:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
dates = pd.date_range('20170101', periods=7)
>> dates
DatetimeIndex(['2017-01-01', '2017-01-02', '2017-01-03', '2017-01-04',
'2017-01-05', '2017-01-06', '2017-01-07'],
dtype='datetime64[ns]', freq='D')

# 可以将pandas中的index理解成行名
df = pd.DataFrame(np.random.randn(7,4), index=dates, columns=list('ABCD'))
>> df
A B C D
2017-01-01 -0.732038 0.329773 -0.156383 0.270800
2017-01-02 0.750144 0.722037 -0.849848 -1.105319
2017-01-03 -0.786664 -0.204211 1.246395 0.292975
2017-01-04 -1.108991 2.228375 0.079700 -1.738507
2017-01-05 0.348526 -0.960212 0.190978 -2.223966
2017-01-06 -0.579689 -1.355910 0.095982 1.233833
2017-01-07 1.086872 0.664982 0.377787 1.012772

也可以通过传递可以转换为类似系列的对象的字典来创建DataFrame。参考以下示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
df2 = pd.DataFrame({ 'A' : 1.,
'B' : pd.Timestamp('20170102'),
'C' : pd.Series(1,index=list(range(4)),dtype='float32'),
'D' : np.array([3] * 4,dtype='int32'),
'E' : pd.Categorical(["test","train","test","train"]),
'F' : 'foo' })
>> df2
A B C D E F
0 1.0 2017-01-02 1.0 3 test foo
1 1.0 2017-01-02 1.0 3 train foo
2 1.0 2017-01-02 1.0 3 test foo
3 1.0 2017-01-02 1.0 3 train foo

可以通过dtypes来查看每一列的数据类型:

1
2
3
4
5
6
7
8
>> df2.dtypes
A float64
B datetime64[ns]
C float32
D int32
E category
F object
dtype: object

2.2. 查看数据

查看DataFrame的顶部和底部的数据行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
dates = pd.date_range('20170101', periods=7)
df = pd.DataFrame(np.random.randn(7,4), index=dates, columns=list('ABCD'))
print(df.head())
print("--------------" * 10)
print(df.tail(3))

# 输出如下:
# A B C D
# 2017-01-01 -0.520856 -0.555019 -2.286424 1.745681
# 2017-01-02 1.114030 0.861933 0.795958 0.420670
# 2017-01-03 -0.343605 -0.937356 0.052693 -0.540735
# 2017-01-04 1.587684 -0.743756 0.021738 -0.702190
# 2017-01-05 1.243403 0.930299 0.234343 1.604182
# ------------------------------------------------------------
# A B C D
# 2017-01-05 1.243403 0.930299 0.234343 1.604182
# 2017-01-06 -0.087004 -0.368055 1.434022 0.464193
# 2017-01-07 -1.248981 0.973724 -0.288384 -0.577388

显示索引,列和底层numpy数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
dates = pd.date_range('20170101', periods=7)
df = pd.DataFrame(np.random.randn(7,4), index=dates, columns=list('ABCD'))
print("index is :" )
print(df.index)
print("columns is :" )
print(df.columns)
print("values is :" )
print(df.values)

# 输出
# index is :
# DatetimeIndex(['2017-01-01', '2017-01-02', '2017-01-03', '2017-01-04',
# '2017-01-05', '2017-01-06', '2017-01-07'],
# dtype='datetime64[ns]', freq='D')
# columns is :
# Index(['A', 'B', 'C', 'D'], dtype='object')
# values is :
# [[ 2.23820398 0.18440123 0.08039084 -0.27751926]
# [-0.12335513 0.36641304 -0.28617579 0.34383109]
# [-0.85403491 0.63876989 1.26032173 -1.27382333]
# [-0.07262661 -0.01788962 0.28748668 1.12715561]
# [-1.14293392 -0.88263364 0.72250762 -1.64051326]
# [ 0.41864083 0.40545953 -0.14591541 -0.57168728]
# [ 1.01383531 -0.22793823 -0.44045634 1.04799829]]

描述显示数据的快速统计摘要:

1
2
3
4
5
6
7
8
9
10
11
12
print(df.describe())

# 输出:
# A B C D
# count 7.000000 7.000000 7.000000 7.000000
# mean -0.675425 -0.257835 0.144049 0.275621
# std 1.697957 0.793953 1.301520 1.412291
# min -2.595040 -1.200401 -1.230538 -0.976166
# 25% -1.992393 -0.723464 -0.897041 -0.800919
# 50% -1.050666 -0.445612 0.004719 -0.705840
# 75% 0.592677 0.068574 0.874195 1.398337
# max 1.717166 1.150948 2.279856 2.416514

2.3. 对DataFrame的简单操作

下面的实例操作都是对以下命令产生的DataFrame进行的操作:

1
2
dates = pd.date_range('20170101', periods=6)
df = pd.DataFrame(np.random.randn(6,4), index=dates, columns=list('ABCD'))

(1)调换转置

1
2
3
4
5
6
7
8
9
print(df.T)

# 输出:

# 2017-01-01 2017-01-02 2017-01-03 2017-01-04 2017-01-05 2017-01-06
# A 0.932454 -2.148503 1.398975 1.565676 -0.167527 -0.242041
# B 0.584585 1.373330 -0.069801 -0.102857 1.286432 -0.703491
# C -0.345119 -0.680955 1.686750 1.184996 0.016170 -0.663963
# D 0.431751 0.444830 -1.524739 0.040007 0.220172 1.423627

(2)通过轴排序:

1
2
3
4
5
6
7
8
9
10
11
# 通过轴1进行降序排序,即按照列名进行降序排序
print(df.sort_index(axis=1, ascending=False))

# 输出:
# D C B A
# 2017-01-01 0.426359 2.542352 -0.324047 0.418973
# 2017-01-02 -0.834625 -1.356709 0.150744 -1.690500
# 2017-01-03 -0.018274 0.900801 1.072851 0.149830
# 2017-01-04 -1.075027 -0.889379 -0.663223 -1.404002
# 2017-01-05 -1.273966 -1.335761 -1.356561 -1.135199
# 2017-01-06 -1.590793 0.693430 -0.504164 0.143386

(3)按值排序

1
2
3
4
5
6
7
8
9
print(df.sort_values(by='B'))

# A B C D
# 2017-01-06 0.764517 -1.526019 0.400456 -0.182082
# 2017-01-05 -0.177845 -1.269836 -0.534676 0.796666
# 2017-01-04 -0.981485 -0.082572 -1.272123 0.508929
# 2017-01-02 -0.290117 0.053005 -0.295628 -0.346965
# 2017-01-03 0.941131 0.799280 2.054011 -0.684088
# 2017-01-01 0.597788 0.892008 0.903053 -0.821024

2.4. 选择/索引DataFrame区块

在Pandas中,对DataFrame进行区块切片,比较容易搞不清楚的是它到底在对行进行切片,还是在对列进行切片?

比如,按标签进行选择的基本语法为:df.loc[·]

当方括号中有两个维度的值,即有用逗号隔开的前后两个值,那么前面的那个是行的索引或行名,后一个是列的索引或列名,但是当只有一个维度的值时,例如df.loc[datas[0]],那么它是优先对行进行搜索然后切片,还是对列优先?

默认对行进行切片

可以对上面一直用到的测试数据做一个小小的实验:

  • df.loc[datas[0]]能正常执行;
  • df.loc['A']报错
  • (1)df[·]df.A形式

    df[·]df.A形式都可以对列进行索引,df['A']df.A的效果是一样的,当只按列进行索引时,df[·]形式还可以同时索引多列,如:df[['A','B']]

    df[·]形式除了上面提到的可以索引列之外,还可以对行进行索引,不过此时只能使用数值进行索引,且必须为以a:b形式的一个区间,如:df[0:1]

    注意:df[·]形式要么以列名进行列索引,要么以行区间值进行行索引,不能同时进行行索引和列索引

  • (2)df.loc[·]形式

    上面已经讨论了,df.loc[·]形式默认进行行索引(不建议使用这种方法,不规范也不好记,容易混淆),它也可以同时进行索引和列索引,但必须为df.loc[·,·]形式

    注意:df.loc[·]形式的索引方式必须为标签名,不可以用位置数值进行索引

  • (3)df.iloc[·]形式

    这种索引方式类似于Numpy,以位置数值进行索引/切片

    一般情况下都是对行和列同时进行索引,即使用形式为df.iloc[·,·]

    当然也只可以值进行一个维度的索引,此时默认为对行进行索引(不建议使用这种方法,不规范也不好记,容易混淆)

  • (4)布尔索引

    使用单列的值来选择数据:

    1
    2
    3
    4
    5
    6
    print(df[df.A > 0])

    # A B C D
    # 2017-01-03 0.276486 -1.003779 0.721863 -0.558061
    # 2017-01-04 1.177206 -0.464778 -0.116442 -0.385712
    # 2017-01-06 0.846665 -1.398207 -0.145356 0.924342

    从满足布尔条件的DataFrame中选择值:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    print(df[df > 0])

    # A B C D
    # 2017-01-01 NaN 1.963213 0.643244 0.945643
    # 2017-01-02 0.364237 0.917368 NaN NaN
    # 2017-01-03 0.702624 NaN 0.088565 NaN
    # 2017-01-04 1.274313 NaN 2.313910 NaN
    # 2017-01-05 2.586315 0.588273 NaN 1.482597
    # 2017-01-06 NaN 0.405928 0.309201 NaN

参考资料:

(1) 菜鸟教程《Numpy教程》

(2) 易教程《Pandas教程》