data_analysis
numpy
numpy中的数组的数据类型必须全部一致
1.使用np.array创建数组
a = np.array([1, 2, 3, 4])
2.使用np.arange创建数组
b = np.arange(0, 10)
3.np.random.random创建数组
c = np.random.random() # 返回0~1之间的随机数
c = np.random.random((2, 2)) # 2行2列
c = np.random.randint(0, 10, size=(4, 4))
4.使用函数生成特殊的数组
d = np.zeros((3, 3))
d = np.ones((4, 4))
d = np.full((2, 3), 9)
d = np.eye(3)
数组的数据类型
查看数据类型
a.dtype
指定数据类型
b = np.array([1, 2, 3], dtype=np.int8)
改变数据类型
a.astype(np.float64)
多维数组简单操作
获取维度
arr.nidm
获取几行几列
arr.shape
形状变形
arr.reshape((3, 4))
扁平化,无论什么都转成一维
arr.flatten()
获取数组中的元素个数
arr.size
获取每个元素占字节的大小(1个字节=8位)
arr.itemsize
数组的索引和切片
一维数组
a[4]
a[4:6]
a[::2]
a[-1]
多维数组(只给一个数就是取行。逗号分割行和列)
a[0]
a[1:3] # 第1行~第2行
a[[0, 2, 3]] # 获取第0行、第2行、第3行
a[2, 1] # 第2行第1列数据
a[[1, 2], [4, 5]] # 获取第1行第4列,第2行第5列的数据
a[1:3, 4:6] # 获取连续数据
a[:, 1] # 获取第1列数据
布尔索引
取出小于10的数据
a[a < 10]
取出小于5或者大于10的数据
a[(a < 5) | (a > 10)]
数组值的替换
直接赋值
a[1] = 0
a[1] = np.array([1, 2, 3])
小于3的替换为1
a[a < 3] = 1
小于5的替换为0,否则替换为1
np.where(a < 5, 0, 1)
数组的广播机制
每个数都变为原来的2倍
a1 * 2
对应位置相加
a1 + a2
能进行广播运算原则
1.最后位相同
2.或者有一方最后位是1
数组形状操作
reshape和resize
reshape不会修改原数组,而resize是在原数组上进行修改
a1.reshape((2, 6))
a1.resize((3, 4))
flatten和ravel
flatten:将原数组转为一维后,进行拷贝,将拷贝返回
ravel:将原数组转为一维后,将视图(引用)返回,对返回值修改会影响原数组
数组的叠加
vstack垂直方向叠加
np.vstack([v1, v2])
hstack水平方向叠加
np.hstack([h1, h2])
concatenate叠加
np.concatenate([v1, v2], axis=0) 同vstack
np.concatenate([h1, h2], axis=1) 同hstack
axis=None时,先进行叠加,再转换成一维数组
数组切割
按列切
np.hsplit(hs1, 平均分成份数)
np.hsplit(hs1, (1, 2)) # 在索引1切一刀,在2切一刀
按行切
np.vsplit(vs1, 平均分成份数)
数组转置
t1.T
t1.transpose()
transpose()返回的是一个视图(引用)
矩阵相乘
t1.dot(t1.T)
数组的深拷贝和浅拷贝
浅拷贝
c = a.view() # 修改c,a也会变
深拷贝
d = a.copy() # 修改d,a不会变
不拷贝:直接赋值,那么栈区没有拷贝,只是用同一个栈区定义不同的名称
浅拷贝:只拷贝栈区,栈区所指向的堆区并没有拷贝
深拷贝:栈区和堆区都拷贝
csv操作
保存csv(不能存储三维数组)
np.savetxt(frame, array, delimiter=",", header="英语,数学", comments="", fmt="%d")
comments为空字符串,才不会有#号
fmt="%d"保存数据为int
读取csv
np.loadtxt(frame, dtype=np.int, delimiter=",", skiprows=1)
skiprows=1:跳过第一行
np独有的存储
存储,会生成.npy或.npz结尾的文件,.npz会对文件进行压缩,可以存储三维数组
np.save(frame, array)
读取
np.load(frame)
python内置的csv模块
import csv
读取csv
with open("xxx.csv", "r") as f:
reader = csv.reader(f) # reader对象是一个迭代器
next(reader) # 如果要跳过第0行,就加这条语句,可以从第1行开始往下读
for x in reader:
print(x)
像字典那样获取数据的读取,此时reader对象不会包含标题那行数据
with open("xxx.csv", "r") as f:
reader = csv.DictReader(f)
for x in reader:
print(x)
写入csv
headers = ["username", "age", "height"]
values = [("张三", 20, 170), ("李四", 19, 175), ("王五", 18, 180)]
with open("xxx.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f)
writer.writerow(headers)
writer.writerows(values)
字典方式写入
headers = ["username", "age", "height"]
values = [{"username":"张三", "age":18, "height":180}, {"username":"小红", "age":18, "height":160}]
with open("xxx.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.DictWriter(f, headers)
# 表头信息只能调用writeheader()方法写入
writer.writeheader()
writer.writerows(values)
空值处理
NAN:Not A Number不是一个数字,属于浮点类型
INF:Infinity无穷大,一个数/0时,会出现INF
把数值设置为NAN
data[0, 1] = np.nan或np.NAN
NAN跟任何数进行运算,结果都是NAN
删除NAN
方法1
data[~np.isnan(data)] # 因为删除nan,数据变得不完整,所以会变成一维数组
方法2
lines = np.where(np.isnan(data))[0] # 所有包含nan的行
np.delete(data, lines, axis=0) # axis=0是删除行,axis=1是删除列
其他值替换NAN
data[np.isnan(data)] = 0
random模块
np.random.seed(1) # 之后每次生成的随机数都一样
产生一个0~1之间随机数
np.random.rand()
np.random.rand(2, 3) # 也可以指定形状
标准正太分布随机数
np.random.randn(2, 3)
产生指定区间的整型随机数
np.random.randint(0, 10, size=(3, 4))
在某个数组或列表中随机选择数字
np.random.choice(data, size=(2, 3))
np.random.choice(data, 3) # 随机选择3个数字组成一维数组
np.random.choice(10, 3) # 0~10(不包含10)之间随机取3个值组成数组
把原数组中的值打乱
np.random.shuffle(data)
通用函数
求绝对值
np.abs(a)
求开根号
np.sqrt(a)
求平方
np.square(a)
求指数(e*x)
np.exp(a)
求对数
np.log(a)
数组的值标签化,大于0的变成1,等于0的变成0,小于0的变成-1
np.sign(a)
朝着正无穷大的方向取整
np.ceil(a)
朝着负无穷大的方向取整
np.floor(a)
四舍五入保留整数
np.rint(a)
四舍五入精确到小数
np.round(a, 2) # 精确到小数点后2位
将小数和整数部分分割开,组成两个数组
np.modf(a)
三角函数
np.sin(a)
加
np.add(a, 1) # a + 1
np.add(a1, a2)
所有数前面加负号
np.negative(a)
&的函数表达式
np.logical_and(a > 0, a < 5)
聚合函数,任何聚合函数前加nan就可以忽略NAN进行聚合
np.sum()
np.nansum()
布尔判断函数
np.any(a == 0) # 判断数组中只要有一个元素等于0就返回True,也可以写成(a == 0).any()
np.all(a > 0) # 判断数组中是否所有数都大于0
排序
np.sort(a, axis=0) # 不会修改原数组,默认按axis=1排序
a.sort(axis=1) # 会影响原数组
np.argsort(a, axis=0) # 获取排序完后的下标
倒序排序
方法1
-np.sort(-a, axis=0)
方法2
index = np.argsort(-a)
np.take(a, index)
沿着轴操作的函数
def get_mean(x):
y = x[logical_add(x != x.max(), x != x.min())].mean() # 去除最大值和最小值之后的运算结果
return y
np.apply_along_axis(get_mean, axis=1, arr=c)
指定区间的值平均分成多少份
np.linspace(0, 10, 10) # 0~10平均分成10份
返回数组中的唯一值
np.unique(a, return_counts=Ture)
pandas
import pandas as pd
Series
通过列表创建
s1 = pd.Series([1, 2, 3, 4, 5])
通过数组创建
arr = np.arange(1, 6)
s1 = pd.Series(arr)
指定索引
s1 = pd.Series(arr, index=["a", "b", "c", "d", "e"])
查看索引和值
s1.index
s1.values
通过字典创建
dic = {"name":"张三", "age":19, "class":"3班"}
s1 = pd.Series(dic, index=["name", "age", "class"])
检查缺失值
s1.isnull() # 判断是否为空,空就是True
s1.notnull() # 判断是否不为空,非空就是True
通过索引获取数值
s1[1]
通过标签名取数据
s1["age"]
选取多个
s1[[1, 3]]
s1[["name", "age"]]
切片取值
s1[1: 3] # 取不到末端数据
s1["name":"class"] # 包含末端数据
布尔索引取值
s1[s1 > 3]
取前几行,默认取前5行
s1.head(3)
取后几个
s1.tail()
DataFrame
取消科学计数法显示
pd.set_option("display.float_format", lambda x: "%.2f" % x)
中文显示
pd.rcParams["font.sans-serif"] = "SimHei"
列表、元组、字典创建DataFrame
dic = {"a":[1, 2, 3, 4], "b":(5, 6, 7, 8), "c":np.arange(9, 13)}
df = pd.DataFrame(dic)
查看行索引和列索引
df.index
df.columns
查看值
df.values
指定行索引index
df = pd.DataFrame(data, index=["A", "B", "C", "D"])
指定列索引columns
df = pd.DataFrame(data, index=["A", "B", "C", "D"], columns=["a", "b", "c", "d"])
DataFrame转置
df.T
查看一列
df["列名"]
新增列
df["新列名"] = 10
删除列
del df["列名"]
DataFrame的索引操作
重新排列行索引
df.reindex(["b", "a", "c"])
重新排列列索引
df.reindex(columns=["B", "C", "A"])
插入一列
df.insert(0, "E", [9, 99, 999])
增加行
df.loc["d"] = [1, 2, 3, 4, 5]
添加到最后一行
df1.append(df2, ignore_index=True)
drop删除轴上数据
df.drop("行标签名") # 返回删除后的df
df.drop(["行1", "行2"]) # 删除多行
df.drop("列名", axis=1) # 删除列,或者df.drop("列名", axis="columns")
加inplace=True参数,可以在原对象上删除
修改
df["列名"] = 100 # 修改列
df.loc["a"] = 777 # 修改行
df.loc["a", "A"] = 888 # 修改某一行某一列的数据
查询
df[["A", "C"]] # 取多列
df["A"]["a"] # 取单个值
df[:2] # 取前2行
loc标签索引
df.loc["a":"b", "A":"C"] # 取a到b行(包括b行)且A到C列的数据
iloc位置索引
df.iloc[0:2, 0: 3] # 取0到2行(不包括2)且0到3列(不包括3)的数据
算术运算时遇到NAN处理
s1.add(s2, fill_value=0) # 两个Series相加结果为NAN时,填充0
算术运算翻转参数
df.rdiv(1) # 相当于1 / df
apply和applymap函数
通过apply将函数应用到列或行
df.apply(lambda x: x.max(), axis=1) # 默认axis=0
通过applymap将函数应用到每个数据
df.applymap(lambda x: "%.2f" % x) # 对每个数据四舍五入保留2位小数
排序
索引排序
df.sort_index(ascending=False) # ascending=True默认升序
df.sort_index(axis=1) # 按照列标签排序
按值排序(缺失值默认排最后)
df.sort_values(by="列名", ascending=False)
df.sort_values(by=["列1", "列2"], ascending=[False, True])
唯一值和成员属性
查看唯一值
s.unique() # 返回一个数组
计算每个值出现的个数
s.value_counts()
成员属性
s.isin([8]) # 判断8是否存在,返回一个布尔Series
s.isin([8, 2]) # 判断多个值是否存在
处理缺失数据
判断是否存在缺失值
df.isnull()
删除缺失值
df.dropna() # 默认删除行,axis=1就是删除有缺失值的列
填充缺失数据
df.fillna(-10.) # 用-10填充
统计计算和描述
df.sum() # 可以设置axis=1
df.idxmax() # 返回最大值的行索引
读写文本格式文件
读取csv文件
df = pd.read_csv("xxx.csv", header=None)
df = pd.read_csv("xxx.csv", names=["a", "b", "c", "d"]) # 自定义列名
df = pd.read_csv("xxx.csv", names=["a", "b", "c", "d", "message"], index_col="message") # 指定message列为行索引
写入csv
df.to_csv("xxx.csv", index=False)
读取JSON
import json
res = json.load(obj) # 读取JSON格式
res1 = json.dumps(res) # 转储为JSON格式
df = pd.DataFrame(res1["siblings"], columns=["name", "age"])
分块读取大文件
方法1
agg1 = pd.read_csv("xxx.csv", chunksize=10) # 返回一个可迭代对象
agg1.get_chunk() # 得到一个DataFrame,每运行一次get_chunk()就会得到10行数据
方法2
agg1 = pd.read_csv("xxx.csv", iterator=True)
agg1.get_chunk(5) # 得到一个DataFrame,更美观
Web交互
import requests
url = "http://xxxx"
resp = requests.get(url)
data = resp.json() # 响应对象的json方法返回一个包含解析过的json字典
pd.DataFrame(data, columns=[""])
数据库交互
from sqlalchemy import create_engine
查询数据
# 初始化数据库连接
conn = create_engine("mysql+pymysql://root:@localhost:3306/db2")
# 查询语句
sql = """select * from class;"""
df = pd.read_sql(sql, conn)
写入数据
conn = create_engine("mysql+pymysql://root:password@localhost:3306/dbname")
df.to_sql("表名", conn, index=False)
数据清洗
滤除缺失值
data[data.notnull()]
删除缺失值
data.dropna(how="all") # 丢弃全为NAN的行
data.dropna(axis=1, how="all") # 删除全是NAN的列
填充数据
df.fillna(0)
df.fillna({"列名1":0.9, "列名2":1})
df.fillna(method="ffill") # 用上一个值填充
df.fillna(method="ffill", limit=2) # 只填充2个
删除重复值
检查重复值
df.duplicated() # 重复为True
删除重复值
df.drop_duplicates()
df.drop_duplicates(["列名"]) # 根据列删除重复值
df.drop_duplicates(["列名"], keep="last") # 保留最后一个
利用映射或函数转换数据
映射,需求:添加一列,要求根据水果进行分类
group = {"apple":"fruit", "orange":"fruit", "tomato":"vegetable"}
df["class"] = df["fruit"].map(group)
把某列值转为小写
df["fruit"].str.lower()
所以转为小写后映射还可以真写
df["fruit"].map(lambda x: group[x.lower()])
替换值
df.replace(-999, np.nan)
df.replace([-999, -1000], [np.nan, 0])
df.replace({-999:np.nan, -1000:0})
重命名轴索引
df.index.map(lambda x: x[:4].upper()) # 行索引取前4个字符并大写
df.rename(index=str.title, columns=str.upper) # 行索引首字母大写,列索引全大写
df.rename(index={"Tokyo":"东京"}, columns={"three":"第三年"}) # 对部分列名更新
就地修改可以添加inplace参数
离散化和面元划分(分阶段)
手动分阶段
ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32] # 数据
bins = [18, 25, 35, 60, 100] # 阶段
names = ["少年", "青年", "中年", "老年"]
cats = pd.cut(ages, bins, right=False, labels=names) # right为左闭右开,labels可以打标签
pd.value_counts(cats) # 返回每个阶段的个数
自动分阶段
pd.cut(data, 4, precision=2) # 4是分4个阶段,precision是保留小数点后2位
qcut函数,可以均匀分阶段
cats = pd.qcut(data, 4)
重新随机排列
sam = pd.random.permutation(5) # 返回一个0~4的随机顺序数组
df.take(sam) # 返回排列后的df
sample方法
df.sample(n=3) # 从df中随机选择3行
df.sample(n=10, replace=True) # 可以重复选择(有放回抽样)
字符串对象方法
分割字符串
str1.split(",") # 字符串按照逗号分割,返回一个列表
去除首位空白格(包括\n)
[x.strip() for x in str1.split(",")]
连接字符串
p = ["a", "b", "c"]
"::".join(p) # 返回"a::b::c"
成员操作
"c" in str1
返回字符串中字符的索引
str1.index("a")
查找,找到的话返回索引,没找到返回-1
str1.find("a")
替换
str1.replace(",", "::") # 逗号替换为冒号
正则表达式
import re
拆分空格、制表符
re.split("\s+", text) # re是正则库,text是字符串
方法2
res = re.compile("\s+") # 编译
res.split(text) 或者 re.split(res, text)
查找
re.findall(res, text) # 查找所有
re.match(res, text) # 只查找起始位置
re.search(res, text) # 查找到就返回,后面的就不找了
矢量化字符串函数
s1是series
s1.str.split("@")
总结
查看哪些列有缺失值
(df.isnull()).sum()
删除缺失值
df.dropna(subset=["yuanjia"], inplace=True) # 设置删除指定列上的缺失值
删除不需要的行
df.drop([行索引1, 行索引2], inplace=True)
删除重复值
df.duplicated().sum() # 检测重复值
df.drop_duplicates(inplace=True)
数据类型转换
df["shoujia"].str.map(lambda x: x.replace("万", "")).astype("float")
设置行索引
df.set_index(["c", "d"], drop=False) # drop=False会保留原列
重置索引
df.reset_index()
数据连接merge
按照列连接
pd.merge(left, right, on="列名", how="inner")
按索引连接
pd.merge(left, right, left_on="左边的列名", right_index=True) # 右边按照行索引
数据连接join
join按照索引进行合并,要求没有重叠的列
df1.join(df2, how="outer")
数据合并concat
注意指定轴方向,默认axis=0
join指定合并方式,默认outer
pd.concat([df1, df2])
合并时指定层级
pd.concat([df1, df2], keys=["data1", "data2"]) # 结果返回Series
重塑
重塑层次化索引
r = df.stack() # DataFrame->Series
r.unstack("列名") # Series->DataFrame
分组和聚合
根据水果求价格的平均值
df.groupby("fruit")["price"].mean()
语法糖(另一种写法,效果一样)
df["price"].groupby(df["fruit"]).mean()
as_index参数,返回DataFrame,取消行索引
df.groupby("fruit", as_index=False)["price"].mean()
计算每种水果的差值
先自定义函数
def diff(arr):
return arr.max() - arr.min()
df.groupby("fruit")["price"].agg(diff)
时间序列
日期和时间数据类型及工具
from datetime import datetime
获取当前时间
now = datetime.now()
now.year # 获取年
now.day # 日
字符串和datetime相互转换
时间->字符串
stamp = datetime(2011, 1, 3)
str(stamp)
格式化
stamp.strftime("%Y-%m-%d")
字符串->时间
v = "2011-12-3"
datetime.strptime(v, "%Y-%m-%d")
解析各种日期格式
from dateutil.parser import parse
parse("6/12/2011", dayfirst=True)
pandas处理时间
pd.to_datetime(d)
创建时间序列的Series
s = pd.Series(np.random.randn(1000), index=pd.date_range("2000-01-01", periods=1000))
s["2001"] # 获取2011年数据
s["2001-05"] # 获取2011年5月数据
s[datetime(2011, 1, 7):] # 2011-01-07之后的数据(包含7号)
s["2001-01-01":"2011-02-18"] # 时间序列切片
查看时间序列是否有重复序列
df.index.is_unique # 返回False说明有重复值
当时间序列为行索引时分组
df.groupby(level=0).mean()
生成日期范围
pd.date_range("2020-04-01", "2020-06-30")
pd.date_range("2020-04-01", periods=20) # periods生成多少个
pd.date_range(end="2020-04-01", periods=20) # 往上取20个
pd.date_range("2020-01-01", "2020-12-31", freq="BM") # freq是频率,BM每个月的最后一个工作日
移动数据
ts.shift(2) # values会被往下移
ts.shift(-2) # values会被往上移
seaborn
import seaborn as sns
关系绘图relplot
散点图(默认)
sns.relplot(x="列名1", y="列名2", data=df, hue="列名3", col="列名4", row="列名5", col_wray=3)
hue:控制颜色,可以传入一个列名
col:可以传入一个列名,画出多个维度
row:跟col一样,只不过是上下排列
col_wrap:换行,碰到第三个就换行
也可以写成sns.scatterplot(),参数都一样
折线图
sns.relplot(x="列名1", y="列名2", data=df, ci=None, kind="line", hue="列名3", col="列名4", style="列名3", hue_order=["值1", "值2"])
ci:设置为None时,就是不显示置信区间
hue:控制颜色,绘制多根线,传入列名
col:根据列,分割成多个图
style:控制线型
hue_order:指定线条颜色
也可以写成sns.lineplot()
分类图catplot
stripplot散点图(默认)
sns.catplot(x="列名1", y="列名2", data=df, hue="列名3")
swarmplot蜂群散点图(点不会重叠,不适合数据量大的)
sns.swarmplot(x="列名1", y="列名2", data=df, hue="列名3")
放大图
plt.figure(figsize=(20, 5))
箱线图
sns.boxplot(x="国家", y="身高", data=df, hue="性别")
也可以写成sns.catplot(kind="box")
小提琴图
sns.violinplot(x="day", y="total_bill", data=df, inner="box", hue="sex", split=True)
inner:中间显示的图,默认box箱线图,可选:quartile四分位、point点图,stick线图
split:是否分割
也可以写成sns.catplot(kind="violin")
分布直方图
sns.distplot(the_titanic["age"], kde=True, bins=30, rug=True, hist=False)
kde:是否设置kde曲线
bins:直方个数
rug:添加下方竖线,观察数据集中情况
hist:是否设置直方图
二变量分布绘图
sns.jointplot(x="total_bill", y="tip", data=tips, kind="reg")
kind:设置reg,添加回归线
sns.jointplot(x="Height", y="Weight", data=athlete_china, kind="hex", gridsize=20, color="r", height=10)
kind:设置hex,添加六边形图。gridsize设置六边形大小
- 1.x,y,data:绘制图的数据
- 2.kind:scatter、reg、resid、kde、hex
- 3.color:绘制元素的颜色
- 4.height:图的大小,图会是一个正方形
- 5.ratio:主图和副图的比例,只能为一个整型
- 6.space:主图和副图的间距
- 7.dropna:是否需要删除x或y值中出现了NAN的值
- 8.marginal_kws:副图的一些属性,比如设置bins、rug等
pairplot分类绘图
sns.pairplot(iris) # 把数值列字段挑选出来,两两绘图
sns.pairplot(tips, vars=["total_bill", "tip"]) # 指定两列绘图
sns.pairplot(iris, vars=["sepal_length", "sepal_width", "petal_length"], diag_kind="kde", kind="reg")
diag_kind:默认hist、kde曲线
kind:默认scatter、reg回归线
线性回归图
sns.lmplot(x="total_bill", y="tip", data=tips)
sns.regplot(x="total_bill", y="tip", data=tips)
浙公网安备 33010602011771号