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)

posted @ 2020-03-24 11:37  echonick555  阅读(250)  评论(0)    收藏  举报