Python数据分析之numpy&pandas

483 阅读6分钟

1. 概述

numpy介绍

numpy 是使用Python进行科学计算的基础包。它包含如下的内容:

  • 一个强大的N维数组对象。
  • 复杂的(广播)功能。
  • 用于集成C / C ++和Fortran代码的工具。
  • 有用的线性代数,傅里叶变换和随机数功能。 除了明显的科学用途外,NumPy还可以用作通用数据的高效多维容器。可以定义任意数据类型。这使NumPy能够无缝快速地与各种数据库集成。

NumPy是在BSD许可下获得许可的,允许重用而不受限制。

pandas介绍

pandas 是一个开源的,BSD许可的库,为Python (opens new window)编程语言提供高性能,易于使用的数据结构和数据分析工具。

Pandas是NumFOCUS (opens new window)赞助的项目。这将有助于确保Pandas成为世界级开源项目的成功,并有可能捐赠 (opens new window)给该项目。

2. numpy数据分析

numpy属性

import numpy as np

array = np.array([[1, 2, 3],  # 定义矩阵
                  [2, 3, 4]])

print(array)
print(f"number of dim: {array.ndim}")  # 维度
print(f"shape: {array.shape}")  # 多少行,多少列
print(f"size: {array.size}")  # 有多少元素

numpy的创建array

定义一维数组

import numpy as np

a = np.array([2, 3, 4], dtype=np.int)  # 定义数字格式
print(a)  # 没有逗号分隔列表
print(a.dtype)  # 打印数字格式 int、float默认64位

a_arange = np.arange(10, 20, 2)  # 定义一个有序数组 [起始、终止)、步长
a_split = np.linspace(1, 10, 4)  # 定义一个分段数列 [起始、终止]、分成几段
print(f"a_arange: {a_arange}")
print(f"a_split: \n{a_split}")

定义多维矩阵

import numpy as np

m = np.array([[2, 3, 4],
             [3, 4, 5]])  # 生成矩阵
print(m)

mzeros = np.zeros((3, 4))  # 定义零元矩阵
mones = np.ones((3, 4))  # 定义1元矩阵
mempty = np.empty((3, 4))  # 定义几乎为0的空矩阵
m_arange = np.arange(12).reshape((3, 4))  # 定义一个有序矩阵
m_split = np.linspace(1, 10, 6).reshape((2, 3))  # 定义一个分段矩阵
print(f"mzeros: \n{mzeros}")
print(f"mones: \n{mones}")
print(f"mempty: \n{mempty}")
print(f"m_arange: \n{m_arange}")
print(f"m_split: \n{m_split}")

numpy的基础运算

数组运算

import numpy as np

a = np.array([10, 20, 30, 40])
b = np.arange(1, 5)

print(f"a = {a}")
print(f"b = {b}")
print(f"a+b = {a+b}")
print(f"a-b = {a-b}")
print(f"b^2 = {b**2}")
print(f"sin(a) = {np.sin(a)}")
print(f"cos(a) = {np.cos(a)}")
print(f"exp(a) = {np.exp(a)}")
print(f"b<3 = {b<3}")  # b的数值小于3?
print(f"b=3 = {b==3}")  # b的数值等于3?

矩阵计算

import numpy as np

a = np.array([[1, 1],
              [0, 1]])
b = np.arange(1, 5).reshape((2, 2))

print(f"a : \n{a}")
print(f"b : \n{b}")
print(f"a*b : \n{a*b}")  # 元素逐个相乘
print(f"a@b : \n{np.dot(a, b)}")  # 矩阵乘法 等价于 a.dot(b)

import numpy as np

a = np.random.random((2, 4))  # 从(0, 1)随机创建一个矩阵 2行4列

print(f"a = \n{a}")
print(f"sum(a) = {np.sum(a)}")  # 矩阵元素的和
print(f"min(a) = {np.min(a)}")  # 矩阵元素的最小值
print(f"max(a) = {np.max(a)}")  # 矩阵元素的最大值
print(f"行sum(a) = {np.sum(a, axis=1)}")  # 每行的和
print(f"列min(a) = {np.min(a, axis=0)}")  # 每列的最小值

import numpy as np

A = np.arange(14, 2, -1).reshape((3, 4))

print(f"A = \n{A}")
print(f"min(A)_arg = {np.argmin(A)}")  # 矩阵A最小值的索引
print(f"max(A)_arg = {np.argmax(A)}")  # 矩阵A最大值的索引
print(f"mean(A) = {np.mean(A)}")  # 平均值 等价于A.mean()或np.average(A)
print(f"median(A) = {np.median(A)}")  # 中位数
print(f"cumsum(A) = {np.cumsum(A)}")  # 矩阵A各元素累加
print(f"diff(A) = \n{np.diff(A)}")  # 矩阵A各元素累差
print(f"nonzero(A) = {np.nonzero(A)}")  # 矩阵的非零元素索引 行--列
print(f"sort(A) = \n{np.sort(A)}")  # 对矩阵逐行按从小到大进行排序
print(f"transpose(A) = \n{A.T}")  # 矩阵转置,等价于np.tranpose(A)
print(f"clip(A) = \n{np.clip(A, 5, 9)}")  # 所有矩阵元素值小于5的变为5,大于9的变为9,其他数不变

numpy的索引

import numpy as np

A = np.arange(3, 15).reshape((3, 4))

print(f"A = \n{A}")
print(f"A[2] = {A[2]}")  # 矩阵按行索引 第三行
print(f"A[1][1] = {A[1][1]}")  # 矩阵按元素索引 第二行第二列 等价于A[1, 1]
print(f"A[2, :] = {A[2, :]}")  # 矩阵第三行的所有数
print(f"A[:, 1] = {A[:, 1]}")  # 矩阵第二列的所有数
print(f"A[2, 0:2] = {A[2, 0:2]}")  # 矩阵第三行的第一个数到第二个数

print("矩阵按行输出: ")
for row in A:  #  按行输出
    print(row)

print("矩阵按列输出: ")
for column in A.T:  # 按列输出
    print(column)

print("矩阵按元素输出: ")
for item in A.flat:  # 迭代器 将矩阵拉直为行向列
    print(item)

numpy的array合并

import numpy as np

A = np.array([1, 1, 1])
B = np.array([2, 2, 2])

print(f"A = {A}")
print(f"B = {B}")
print(f"vertical stack: \n{np.vstack((A, B))}")  # 将A、B上下合并
print(f"horizontal stack: \n{np.hstack((A, B))}")  # 将A、B左右合并
print(f"A column dim: \n{A[np.newaxis, :]}")  # 在A的行上加维度, 将序列变为矩阵
print(f"A row dim: \n{A[:, np.newaxis]}")  # 在A的列上加维度, 将序列变为矩阵
print(f"arrays combine: \n{np.concatenate((A, B, B, A), axis=0)}")  # 多个数组横向合并 默认水平合并

numpy的array分割

import numpy as np

A = np.arange(12).reshape((3, 4))

print(f"A: \n{A}")
print(f"split row: \n{np.split(A, 3, axis=0)}")  # 将A按行均分为三部分
print(f"split column: \n{np.split(A, 2, axis=1)}")  # 将A按列均分为两部分
print(f"split neq column: \n{np.array_split(A, 3, axis=1)}")  # 将A按列不等分为三部分 2,1,1
print(f"vsplit(A): \n{np.vsplit(A, 3)}")  # 将A按纵向分为三块
print(f"hsplit(A): \n{np.hsplit(A, 2)}")  # 将A按横向分为两块

numpy的copy & deep copy

import numpy as np

a = np.arange(4)

print(f"a = {a}")

b = a  # numpy copy 将a的值赋给b,且关联a
c = a.copy()  # deep copy 将a的值赋给c,但不关联a

a[1:3] = [22, 33]

print(f"a = {a}")
print(f"b = {b}")
print(f"c = {c}")

3. pandas数据处理

pandas基础介绍

创建一维数表

import pandas as pd
import numpy as np

s = pd.Series([1, 3, 6, np.nan, 44, 1])  # 创建一个序列
print(f"s = \n{s}")  # 打印列表,自动添加序号和数据类型

打印时间数表

dates = pd.date_range('2020.12.16', periods=6)
print(f"dates = {dates}")  # 打印时间列表

指定序列索引

df = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=['a', 'b', 'c', 'd'])  # 行索引index 列索引columns
df1 = pd.DataFrame(np.arange(12).reshape((3, 4)))
df2 = pd.DataFrame({'A': 1.,
                    'B': pd.Timestamp('20130102'),
                    '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'})

更多的数据处理

print(f"df2.dtypes = \n{df2.dtypes}")  # 打印每一列的数据格式
print(f"df2.index = \n{df2.index}")  # 打印每一列序号
print(f"df2.columns = \n{df2.columns}")  # 打印每一列的名字
print(f"df2.values = \n{df2.values}")  # 打印每一列的值
print(f"df2.describe = \n{df2.describe()}")  # 打印每一列的统计信息
print(f"df2.T = \n{df2.T}")  # 打印矩阵转置后结果

将表格排序

print(f"df2.sort_column = \n{df2.sort_index(axis=1, ascending=False)}")  # 将表格按列名称逆序排序
print(f"df2.sort_row = \n{df2.sort_index(axis=0, ascending=False)}")  # 将表格按行名称逆序排序
print(f"df2.sort_values = \n{df2.sort_values(by='E')}")  # 将表格按E列值排序

pandas筛选数据

将表格切片

import pandas as pd
import numpy as np

dates = pd.date_range('2020.12.16', periods=6)
df = pd.DataFrame(np.arange(24).reshape((6, 4)), index=dates, columns=['A', 'B', 'C', 'D'])

print(f"df = \n{df}")
print(f"df.A = \n{df.A}")  # 列标为'A'的列 等价于df['A']
print(f"df[0:3] = \n{df[0:3]}")  # 从第一行到第三行切片 等价于df['2020-12-16':'20201218']

用loc方法筛选数据

# select by label: loc
print(f"df.loc['20201216'] : \n{df.loc['20201216']}")  # 以行标签索引选择
print(f"df.loc[:, ['A', 'B']] : \n{df.loc[:, ['A', 'B']]}")  # 所有行,以列标签索引选择
print(f"df.loc['20201220', ['A', 'B']] : \n{df.loc['20201220', ['A', 'B']]}")  # 某一行,以列标签索引选择

用iloc方法筛选数据

# select by position: iloc
print(f"df.iloc[3] : \n{df.iloc[3]}")  # 选择第四行数据
print(f"df.iloc[3, 0] : \n{df.iloc[3, 0]}")  # 选择第四行第一列数据
print(f"df.iloc[3:5, 1:3] : \n{df.iloc[3:5, 1:3]}")  # 切片
print(f"df.iloc[[1, 3, 5], 1:3] : \n{df.iloc[[1, 3, 5], 1:3]}")  # 逐个选择

# Boolean indexing
print(f"df[df.A > 8] : \n{df[df.A > 8]}")  # 选择满足条件的数据

pandas设置值

import pandas as pd
import numpy as np

dates = pd.date_range('20201216', periods=6)
df = pd.DataFrame(np.arange(24).reshape((6, 4)), index=dates, columns=['A', 'B', 'C', 'D'])

print(f"df: \n{df}")

df.iloc[2, 2] = '@'  # 根据位置改值
df.loc['20201218', 'B'] = '$'  # 根据标签改值

df[df.A > 10] = '*'  # 根据值更改信息(df.A[]则只会更改A列的数据)

df['E'] = np.nan  # 增加列
df['F'] = pd.Series([1, 2, 3, 4, 5, 6], index=pd.date_range('20201216', periods=6))  # 增加列 用指定序列填充
print(f"df: \n{df}")

7.png

pandas处理丢失数据

丢数据

import pandas as pd
import numpy as np

dates = pd.date_range('20201216', periods=6)
df = pd.DataFrame(np.arange(24).reshape((6, 4)), index=dates, columns=['A', 'B', 'C', 'D'])

df.iloc[0, 1] = np.nan
df.iloc[1, 2] = np.nan

print(f"df: \n{df}")
print(f"df.dropna_row: \n{df.dropna(axis=0, how='any')}")  # 丢掉有丢失数据的行,出现任何一个nan就丢  how:{'any', 'all'}
print(f"df.dropna_row: \n{df.dropna(axis=1, how='all')}")  # 丢掉有丢失数据的列,全部都是nan才丢

改数据

print(f"df.fillna_0: \n{df.fillna(value=0)}")  # 将丢失数据改为0
print(f"df.isnull(): \n{df.isnull()}")  # 值是否为丢失数据
print(f"np.any(df.isnull()): \n{np.any(df.isnull()) == True}")  # 是否有缺失值

pandas导入导出文件

import pandas as pd
import numpy as np

# 读取 read_XXX 读取XXX格式的文件
# 保存 to_XXX 保存为XXX格式的文件

data = pd.read_csv('dataname.csv')   # 读取数据文件

print(f"show data: \n{data}")

data.to_csv('data.csv')  # 保存数据文件

pandas合并concat

直接合并

import pandas as pd
import numpy as np

# concatennating
df1 = pd.DataFrame(np.ones((3, 4))*0, columns=['a', 'b', 'c', 'd'])
df2 = pd.DataFrame(np.ones((3, 4))*1, columns=['a', 'b', 'c', 'd'])
df3 = pd.DataFrame(np.ones((3, 4))*2, columns=['a', 'b', 'c', 'd'])

print(f"df1: \n{df1}")
print(f"df2: \n{df2}")
print(f"df3: \n{df3}")

res1 = pd.concat([df1, df2, df3], axis=0, ignore_index=True)  # 竖向合并三个数表,重新标号

print(f"res1: \n{res1}")

合并前裁剪

# join, ['inner', 'outer']

df4 = pd.DataFrame(np.ones((3, 4))*0, columns=['a', 'b', 'c', 'd'], index=[1, 2, 3])
df5 = pd.DataFrame(np.ones((3, 4))*1, columns=['b', 'c', 'd', 'e'], index=[2, 3, 4])

print(f"df4: \n{df4}")
print(f"df5: \n{df5}")

res2 = pd.concat([df4, df5], join='inner', ignore_index=True)  # 合并,裁剪不同部分
res3 = pd.concat([df4, df5], join='outer', ignore_index=True)  # 合并,不同部分为NaN
print(f"res2: \n{res2}")
print(f"res3: \n{res3}")

添加数据

# append
res5 = df4.append(df5, ignore_index=True)  # 将df5加到df4下面
print(f"res5: \n{res5}")

df6 = pd.DataFrame(np.ones((3, 4))*1, columns=['c', 'd', 'e', 'f'], index=[3, 4, 5])
res6 = df4.append([df5, df6], ignore_index=True)  # 将df5, df6加到df4下面
print(f"res6: \n{res6}")

s1 = pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])
res7 = df4.append(s1, ignore_index=True)  # 添加一行到最下面
print(f"res7: \n{res7}")

pandas合并merge

一个简单的例子

import pandas as pd
import numpy as np

# merging two df by key/keys.(may be used in database)
# simple example
left = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],
                     'A': ['A0', 'A1', 'A2', 'A3'],
                     'B': ['B0', 'B1', 'B2', 'B3']})

right = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],
                     'C': ['C0', 'C1', 'C2', 'C3'],
                     'D': ['D0', 'D1', 'D2', 'D3']})

print(f"left: \n{left}")
print(f"right: \n{right}")

res = pd.merge(left, right, on='key')  # 合并左右两个数表 基于指标为'key'的列合并

print(f"res: \n{res}")

考虑两个指标

# consider two keys
left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],
                     'key2': ['K0', 'K1', 'K0', 'K1'],
                     'A': ['A0', 'A1', 'A2', 'A3'],
                     'B': ['B0', 'B1', 'B2', 'B3']})

right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
                      'key2': ['K0', 'K0', 'K0', 'K0'],
                      'C': ['C0', 'C1', 'C2', 'C3'],
                      'D': ['D0', 'D1', 'D2', 'D3']})

res = pd.merge(left, right, on=['key1', 'key2'], how='left')  # 合并两个数表 索引为key的两列均考虑
                                                            # 基于左侧列的指标罗列 how=['left','right','outer','inner']

print(f"left: \n{left}")
print(f"right: \n{right}")
print(f"res: \n{res}")

显示合并信息

# indicator
df1 = pd.DataFrame({'col1': [0, 1], 'col_left': ['a', 'b']})
df2 = pd.DataFrame({'col1': [1, 2, 2], 'col_left': [2, 2, 2]})

res = pd.merge(df1, df2, on='col1', how='outer', indicator=True)  # 合并两个数表,考虑col1,没有的用NaN进行填充,显示合并信息

# give the indicator a custom name
res1 = pd.merge(df1, df2, on='col1', how='outer', indicator='indicator_column')   # 对信息列命名为indicator_column
print(f"df1: \n{df1}")
print(f"df2: \n{df2}")
print(f"res: \n{res}")
print(f"res1: \n{res1}")

根据指标合并

# merge by index
left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
                    'B': ['B0', 'B1', 'B2']},
                    index=['K0', 'K1', 'K2'])

right = pd.DataFrame({'C': ['C0', 'C1', 'C2'],
                    'D': ['D0', 'D1', 'D2']},
                    index=['K0', 'K2', 'K3'])

print(f"left: \n{left}")
print(f"right: \n{right}")

res = pd.merge(left, right, left_index=True, right_index=True, how='outer')  # 合并两个数表,考虑两个数表的index指标

print(f"res: \n{res}")

# handle overlapping
boys = pd.DataFrame({'k': ['K0', 'K1', 'K2'], 'age': [1, 2, 3]})
girls = pd.DataFrame({'k': ['K0', 'K0', 'K3'], 'age': [4, 5, 6]})

res = pd.merge(boys, girls, on='k', suffixes=['_boy', '_girl'], how='inner')  # 合并两个数表 同一指标改写法合并

print(f"boys: \n{boys}")
print(f"girls: \n{girls}")
print(f"res: \n{res}")

pandas plot画图

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# plot data

# Series
data = pd.Series(np.random.randn(1000), index=np.arange(1000))  # 生成数据
data = data.cumsum()  # 累加数据

# DataFrame
data = pd.DataFrame(np.random.randn(1000, 4),
                    index=np.arange(1000), columns=list("ABCD"))  # 四种类型的数据
data = data.cumsum()  # 累加数据
print(data.head(6))  # 打印前6个数据 默认为5


# data.plot()  # 生成图像

# 'bar', 'hist', 'box', 'kde', 'area', 'hexbin', 'pie'...
ax = data.plot.scatter(x='A', y='B', color='DarkBlue', label='Class 1')
data.plot.scatter(x='A', y='C',color='DarkGreen', label='Class 2', ax=ax)
plt.show()  # 显示图像

4. 参考资料


文章中的所有代码经测试均可成功编译运行,可直接复制。具有显然结果或简单结论的代码不展示运行结果。如有问题欢迎随时交流~