数据分析基础


目录
  • 一.matplotlib
    • 1.1 matplotlib基本命令
      • 1.1.1实现一个简单的matplotlib画图
      • 1.1.2 拓展知识
    • 1.2 折线图
      • 1.2.1 折线图绘制和保存图片
      • 1.2.2 完善原始折线图(辅助显示层)
      • 1.2.3 字体问题
      • 1.2.4 完善原始折线图(图像层)
      • 1.2.5 多个坐标系显示
      • 1.2.6 绘制数学图像
    • 1.3 散点图
      • 1.3.1常见图形种类和意义
      • 1.3.2
    • 1.4 柱状图
      • 1.4.1 柱状图的绘制
    • 1.5 直方图
      • 1.5.1 直方图绘制
    • 1.6 饼图
      • 1.6.1 饼图绘制
  • 二.numpy
    • 2.1 numpy的优势
      • 2.1.1 numpy测试
      • 2.1.2 numpy优势
    • 2.2 认识n维数组-ndarry属性
      • 2.2.1 ndarray常用属性
      • 2.2.2 ndarray形状
      • 2.2.3 ndarray类型
    • 2.3 基本操作
      • 2.3.1 生成数组的方法
      • 2.3.2 数组的索引和切片
      • 2.3.3 形状修改
      • 2.3.4 类型修改
      • 2.3.5 数组的去重
    • 2.4 ndarray运算
      • 2.4.1 逻辑运算
      • 2.4.2 通用判断函数
      • 2.4.3 np.where(三元运算符)
      • 2.4.4 统计运算
    • 2.5 数组间的运算
      • 2.5.1 数组与数的运算
      • 2.5.2 数组与数组的运算
      • 2.5.3 广播机制
      • 2.5.4 矩阵运算
    • 2.6 合并,分割
      • 2.6.1 合并
      • 2.6.2 分割
    • 2.7 IO操作与数据处理
  • 三.pandas
    • 3.1 基本数据操作
      • 3.1.1 DataFrame的属性和方法
      • 3.1.2 DataFrame的索引设置
      • 3.1.3 Multilndex 与 Panel
      • 3.1.4 Series
      • 3.1.5 索引操作
      • 3.1.6 赋值操作
      • 3.1.7 排序
    • 3.2 DataFrame运算
      • 3.2.1 算术运算
      • 3.2.2 逻辑运算
      • 3.2.3 逻辑运算函数
      • 3.2.4 统计运算
      • 3.2.5 统计函数
      • 3.2.6 自定义运算
    • 3.3 pandas画图
    • 3.4 文件读取与存储
      • 3.4.1 CSV
      • 3.4.2 HDF5
      • 3.4.3 json
    • 3.5 高级处理-缺失值处理
    • 3.6 高级处理-合并
      • 3.6.1 pd.concat实现合并
      • 3.6.2 pd.merge实现合并
    • 3.7 高级处理-数据离散化
    • 3.8 高级处理-交叉表和透视表
    • 3.9 分组与联合

一.matplotlib

1.1 matplotlib基本命令

1.1.1实现一个简单的matplotlib画图

import matplotlib.pyplot as plt
plt.figure()
plt.plot([1, 0, 9], [4, 5, 6])
plt.show()

1.1.2 拓展知识

  • canvas位于最顶层,用户一般接触不到
  • figure 建立在canvas之上
  • axes 建立在figure之上
  • 坐标轴(axis),图例(legend)等辅助显示层都是建立在axes

1.2 折线图

1.2.1 折线图绘制和保存图片

import matplotlib.pyplot as plt
# 创建画布
plt.figure(figsize=(20, 8), dpi=80)
#绘制图像
plt.plot(range(10), range(10))
#保存图片
plt.savefig('test.png')
#显示图例
plt.show()
#plt.show()会释放资源,如果在显示图像之后再进行保存,只能保存空图片

1.2.2 完善原始折线图(辅助显示层)

#需求:画出某城市11点到12 点的温度变化情况,温度范围在15~18
#准备数据
x = range(60)
y_shanghai = [random.uniform(15, 18) for i in x]
#创建画布
plt.figure(figsize=(20, 8), api = 80)
#绘制图像
plt.plot(x, y)
#显示图像
plt.show()
#添加x,y的刻度
plt.yticks(range(40, 5))
x_label = ['11点{}分'.format(i) for i in x]
plt.xticks(x[::5], x_label[::5])
#添加网格
plt.grid(True, linestyle='--', alpha=0.5)
#添加描述信息
plt.xlabel('时间变化')
plt.ylabel("温度变化")
plt.title("某城市11点到12点每分钟的温度变化情况")

1.2.3 字体问题

1)安装字体

2)删除matplotllib缓存文件

3)修改配置文件 matplotlibrc

1.2.4 完善原始折线图(图像层)

#需求,在上面的基础上,再添加北京的温度变化情况
y_beijing = [random.uniform(1, 3) for i in x]
y_shanghai = [random.uniform(15, 18) for i in x]

plt.figure(figsize=(20, 8), dpi=80)
plt.plot(x, y_shanghai, color='r')
plt.plot(x, y_beijing, color='g')

plt.legend()

#添加x,y的刻度
plt.yticks(range(40, 5))
x_label = ['11点{}分'.format(i) for i in x]
plt.xticks(x[::5], x_label[::5])
#添加网格
plt.grid(True, linestyle='--', alpha=0.5)
#添加描述信息
plt.xlabel('时间变化')
plt.ylabel("温度变化")
plt.title("某城市11点到12点每分钟的温度变化情况")

plt.show

1.2.5 多个坐标系显示

plt.函数名()相当于面向过程的画图方法,axes.set_方法名()相当于面向对象的画图方法

y_beijing = [random.uniform(1, 3) for i in x]
y_shanghai = [random.uniform(15, 18) for i in x]
#创建画布
figure, axes = plt.subplots(nrows=1, ncols=2, figsize=(20, 8), dpi=80)

#绘制图像
axes[0].plot(x, y_shanghai, color='r', linestyle='-', label='上海')
axes[1].plot(x, y_beijing, color='b', label='北京')

axes[0].legend()
axes[1].legend()

#添加x,y的刻度
axes[0].set_yticks(range(40, 5))
x_label = ['11点{}分'.format(i) for i in x]
axes[1].set_xticks(x[::5], x_label[::5])
#添加网格
axes[0].grid(True, linestyle='--', alpha=0.5)
axes[1].grid(True, alpha=0.5)
#添加描述信息
axes[0].set_xlabel('时间变化')
axes[0].set_ylabel("温度变化")
axes[1].set_xlabel("时间变化")
axes[1].set_ylabel("温度变化")
axes[0].set_title("某城市11点到12点每分钟的温度变化情况")

plt.show()

1.2.6 绘制数学图像

import numpy as np
#准备数据
x = np.linespace(-10, 10, 1000)
y = np.sin(x)

#创建画布
plt.figure(figsize=(20, 8), dpi=80)

#绘制函数图像
plt.plot(x, y)

#添加网格
plt.grid(linestyle='-', alpha=0.5)
#显示图像
plt.show()

1.3 散点图

1.3.1常见图形种类和意义

  • 折线图:plot
  • 散点图:scatter:关系/规律
  • 柱状图:bar:统计/对比
  • 直方图:histogram:分布状况
  • 饼图:占比

1.3.2

x = linespace(-100, 100, 1000)
y = linespace(100, 200, 1000)

#创建画布
plt.figure(figsize=(20, 8), dpi=80)

#绘制图像
plt.scatter(x, y)

#显示图像
plt.show()

1.4 柱状图

1.4.1 柱状图的绘制

需求一:对比每部电影的票房收入

#对比每部电影的票房收入
#准备数据
movie_names = ['电影%d'%x for x in range(1, 11)]
tickets =[random.uniform(70000, 80000) for i in range(10)]

#创建画布
plt.figure(figsize=(20, 8), dpi=80)

#绘制柱状图
plt.bar(range(len(movie_names)), tickets, color = [np.random.uniform(['r', 'g', 'b', 'w']) for i in range(10)])

#修改x刻度
plt.xticks(range(len(movie_names)), movie_names)

#添加标题
plt.title("电影票房收入对比")

#添加网格
plt.grid(linestyle='--', alpha=0.5)

#显示图像
plt.show()

需求二:如何对比点引发票房收入才更加有说服力

#按照上映的时间对比票房
#准备数据
movie_names = ['电影%d'%x for x in range(1, 5)]

first_day = [np.random.uniform(1000, 10000) for i in range(4)]
second_day = [np.random.uniform(1000, 10000)]

#创建画布
plt.figure(figsize(20, 8), dpi=80)

#绘制柱状图
plt.bar(range(4), first_day, width=0.2, label="首日票房")
plt.bar([0.2, 1.2, 2.2, 3.2], second_day, width=0.2, label="首周票房")

#添加图例
plt.legend()

#修改刻度
plt.xticks([0.1, 1.1, 2.1, 3.1], movie_names)
#显示图像
plt.show()

1.5 直方图

1.5.1 直方图绘制

#电影时长分布状况
#准备数据
time = [random.randint(90, 140) for i in range(30)]
#创建画布
plt.figure(figsize(20, 8), dpi=80)
#绘制直方图
#bins表示组,bin = (max(time) - min(time))  // 组距
distance = 2
goup_num = int((max(time) - min(time)) // distance)
#density=True表示纵坐标表示的是频率
plt.hist(time, bins = goup_num, density=True)

#修改x轴刻度
plt.xticks(range(min(time), max(time, distance))
#显示图像
plt.show()     

1.6 饼图

1.6.1 饼图绘制

#准备数据
movie_names = ['电影%d'%x for x in range(1, 11)]
place_count =[random.randint(7000, 8000) for i in range(10)]

#创建画布
plt.figure(figsize=(20, 8), dpi=80)

#绘制图像
plt.pie(place_count, labels=movie_names, color = [np.random.uniform(['r', 'g', 'b', 'w']) for i in range(10)])

#为了显示的饼图保持圆形,需要添加axes保证长宽一样
plt.axis('equal')

#显示图像
plt.show()

二.numpy

2.1 numpy的优势

2.1.1 numpy测试

存储的是类型一致的数据

import numpy as np
#创建ndarray
score = np.array([np.random.randint(80, 100) for i in range(5)], [np.random.randint(80, 100) for i in range(5)])


2.1.2 numpy优势

import random
import time
import numpy as np
a = []
for i in range(1000000):
    a.append(random.random())
t1 = time.time()
sum1 = sum(a)
t2 = time.time()

b = np.array(a)
t4 = time.time()
sum3 = np.sum(b)
t5 = time.time()

print(t2 - t1, t5 - t4)

2.2 认识n维数组-ndarry属性

2.2.1 ndarray常用属性

属性名字 属性解释
ndarray.shape 数组维度的元组
ndarray.ndim 数组维数
ndarray.size 数组中的元素数量
ndarray.itemsize 一个数组元素的 长度
ndarray.dtype 数组元素的类型

2.2.2 ndarray形状

a = np.array([1, 2, 3], [4, 5, 6])
b = np.array([1, 2, 3, 4])
c = np.array([[[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]]])
# a(2, 3)
# b(4, )
# c(2, 3, 3)
print(c.shape)

2.2.3 ndarray类型

a = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float32)
#等价于
a = np.array([[1, 2, 3], [4, 5, 6]], dtype='float32')
a.dtype
# 如果不指定,整数默认为int64,浮点数默认为float64

2.3 基本操作

2.3.1 生成数组的方法

  • 生成0和1
  • 从现有数组中生成
  • 生成固定范围的数组
  • 生成随机数组
import numpy as np
#生成0和1的数组
np.zeros(shape=(3, 4), dtype="float32")

np.ones(shape=(3, 4), dtype=np.int32)

#从现有数组生成
list = []
for i in range(10):
    for j in range(10):
        a = []
        a.append(i * j)
    list.append(a)
score = np.array(list)

data1 = np.asarray(score)

data2 = np.copy(score)

score[3, 1] = 10000

print(score)
print(data1)
print(data2)
# np.array() np.copy为深拷贝
# np.asarray()浅拷贝


#生成固定范围的数组
np.linspace(0, 10, 100) #生成从0 ~ 10 等距离的100个数
np.arange(0, 10, 2) #生成从0 ~ 10 步长为2 的数


#生成随机的数组
#均匀分布
data = np.random.uniform(low=-1, high=1, size=10000)
import matplotlib.pyplot as plt
plt.figure()
plt.hist(data, 1000)
plt.show()

#正态分布
data2 = np.random.normal(loc=1.75, scale=0.1, size = 10000)

2.3.2 数组的索引和切片

#随机生成8只股票两周的交易日涨幅数据
stock_change = np.random.normal(loc=0, scale=1, size=(8, 10))

#获取第一个股票的前三个交易日的涨跌幅数据
stock_change[0, :3]

#如何获取三维数组的信息
a1 = np.array([[[1, 2, 3], [4, 5, 6]],[[1, 2, 3], [4, 5, 6]] ]) #(2, 2, 3)三维数组有两个二维数组,二维数组有两个一维数组,一个一维数组由三个元素
#获取34
a1[1, 0, 2]

2.3.3 形状修改

#需求:进行转置
stock_change = np.random.normal(loc=0, scale=1, size=(8, 10))

#ndarray.reshape() 返回了新的ndarray
stock_changre.reshape((10, 8))
#ndarray.T
stock_change.T
#ndarray.resize在原始的ndarray进行修改
stock_change.resize((10, 8))

2.3.4 类型修改

#ndarray.astype(type)

#ndarray序列化到本地 ndarray.tostring()
stock_change.astype('int32')

2.3.5 数组的去重

temp= np.array([[1, 2, 3, 4], [3, 4, 5, 6]])
np.unique(temp)
set(temp.flatten())

2.4 ndarray运算

2.4.1 逻辑运算

stock_change = np.random.normal(0, 1, (8, 10))stock_change = stock_change(0:5, 0:5)stock_change > 0.5#bool赋值,将满足条件的设定为指定的值stock_change[stock_change > 0.5] = 1

2.4.2 通用判断函数

  • np.all
#判断stock_change[0:2,0:5]是否全是上涨的np.all(stock_change[0:2, 0:5] > 0)
  • np.any
#判断是否存在上涨np.any(stock_change[0:5, :] > 0)

2.4.3 np.where(三元运算符)

通过np.where可以进行更加复杂的运算

  • np.where
#判断前四只股票前四天中涨幅大于0的赋值为1,否则为0temp = stock_change[:4, :4]np.where(temp > 0, 1, 0)
  • 复合逻辑运算要结合np.logical_and 和np.logical_or使用
#判断前四个股票前四天的涨跌幅大于0.5但是小于1的换为1,否则为0#判断前四个股票前四天涨跌幅大于0.5或者小于-0.5 的换为1 , 否则为0np.where(np.logical_and(temp>0.5, temp<1), 1, 0)np.where(np.logical_or(temp>0.5, temp < -0.5, 1, 0)

2.4.4 统计运算

在这里,axis0代表列,axis1代表行

stock_change = np.random.normal(0, 1, (8, 10))temp = stock_change[:4, :4]#前四只股票前四天的最大涨幅temp.max()np.max(temp)#前四只股票每一天的最大值temp.max(axis=1)

统计出哪一只股票在某个交易日的涨幅最大或者最小

  • np.argmax(temp, axis=)
  • np.argmin(temp, axis=)
np.argmax(temp, axis=1)

2.5 数组间的运算

2.5.1 数组与数的运算

arr = np.array([[1, 2, 3, 4 ,5], [5, 6, 7, 8, 9]])arr + 1

2.5.2 数组与数组的运算

arr1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])arr2 = np.array([[1, 2, 3, 4 ,5, 1], [2, 3, 4, 5 ,6, 4]])#不可以进行运算

2.5.3 广播机制

可以进行运算的数组,要么形状相等,要么shape( 其中相对应的一个地方为1)

2.5.4 矩阵运算

  • np.mat() 将数组转化为矩阵
  • np.matmul() 乘法
  • np.dot()
a = np.array([[80, 98], [34, 45]])
b = np.mat(a)

#矩阵乘法

2.6 合并,分割

2.6.1 合并

  • np.hstack() 水平
  • np.vstack() 垂直
  • np.concatenate(, axis =)
# np.hstack()
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
np.hstack(a, b)

#np.vstack()
np.vstack(a, b)

#np.concatenate()
a = np.array([[1, 2], [3, 4]])
b = np.array([5, 6])
np.concatenate(a, b.T, axis=1) #水平
np.concatenate(a, b, axis=0) #垂直

2.6.2 分割

x = np.arange(9)np.split(x, 3)x = np.arange(8)np.split(x, [3, 5, 6, 10])

2.7 IO操作与数据处理

#numpy读取data = np.genfromtxt('test.csv', delimiter=',')type(data[2,2]) # np.nan为numpy.float64#缺失值处理 用pandas比较方便

三.pandas

3.1 基本数据操作

3.1.1 DataFrame的属性和方法

import numpy as npimport pandas as pdstock_change = np.random.normal(0, 1, (10, 5))pd.DataFrame(stock_change)#添加行索引stock = ['股票{}'.format(i) for i in range(10)]data = pd.DateFrame(stock_change, index=stock)#添加列索引date = pd.date_range(start="20180101", periods=5, freq='B')data = pd.DataFrame(stock_change, index=stock, columns=date)#DataFrame的属性print(data.index)print(data.T)print(data.shape)#DataFrame的方法data.head() #默认前五行data.tail() #默认后五行

3.1.2 DataFrame的索引设置

  • 修改行列索引值
#错误的修改方式data.index[3] = '股票_3'#正确的方式stock_code = ['股票_' + str(i) for i in range(stock_change.shape)]#必须整体修改data.index = stock_code
  • 重设索引
    • reset_index(drop=True)
      • 设置新的下标索引
      • drop:默认为False,不删除原来的索引,如果为True,删除原来的索引值
data.reset_index()
  • 设置新的索引
    • set_index(keys, drop=True)
      • keys:列索引名或者列索引名称的列表
      • drop:boolean, default True,当做新的索引,删除原来的列
df = pd.DataFrame({'month':[1, 4, 7, 10],
'year':[2012, 2014, 2015, 2016]},
'sale':[23,45, 453, 21])
# 重设新的索引
df.set_index(month)
new_df = df.set_index(['year', 'month'])

3.1.3 Multilndex 与 Panel

  • Multilndex
# 多级或分层索引对象
# index属性
#	names:levels的名称
#	levels:每个levels的元组值

new_df.names
new_df.levels
  • Panel
p = pd.Panel(np.arange(24), reshape(4, 3, 2),            items=list('abcd'),            major_axis=pd.date_range('20130101', periods=3),            minor_axis=['first', 'second'])p['a']p.major_xs('2013-01-01')

3.1.4 Series

Series只有行索引

sr = data.iloc[1, :]print(sr)sr.indexsr.valuespd.Series(np.arange(3, 9, 2), index = ['a', 'b', 'c'])

3.1.5 索引操作

  • 直接索引
  • 按名字索引
  • 按数字索引
  • 组合索引

image-20211105155005160

#不可以直接进行数字索引#直接索引(必须先列后行)data['open']['2018-02-26']#按名字进行索引data.loc['2018-02-26']['open'] data.loc['2018-02-26', 'open'] #按照数字索引data.iloc(1, 0)#获取从第一天到第四天,['open', 'close', 'high', 'low']这个四个指标的结果data.ix[:4, ['open', 'close', 'high', 'low']]

3.1.6 赋值操作

data.open = 100data.iloc[1, 0] = 222

3.1.7 排序

  • df.sort_values(key=, ascending=)
    • 单个键或者多个键进行排序,默认升序
    • ascending=False 降序
    • ascending=True升序
data = data.sort_values(by='p_change')
  • df.sort_index对索引进行排序

3.2 DataFrame运算

3.2.1 算术运算

  • add(other)
data['open'] + 3
data['open'].add(3).head()

  • sub(other)
data['close'].sub(data['open'])

3.2.2 逻辑运算

data['p_change'] > 2
data[data['p_change'] > 2].head()
(data['p_change'] > 2) & (data['low'] > 15)

3.2.3 逻辑运算函数

  • query(expr)
    • expr:查询字符串
data.query('p_change > 2 & turnover > 15')
  • isin(values)
data[data['turnover'].isin([4.19, 2.39])]

3.2.4 统计运算

  • describe()
data.describe()

image-20211105161322232

3.2.5 统计函数

  • max(axis=)
  • min(axis=)
  • std()
  • var()
  • median()
  • idxmax()
  • isxmin()
  • cumsum()

3.2.6 自定义运算

  • apply(func, axis=0)
data[['open', 'close']].apply(lambda x:x.max() - x.min(), axis = 0)

3.3 pandas画图

image-20211105161936505

data.plot(x='p_change', y='turnover', kind='scatter')

3.4 文件读取与存储

3.4.1 CSV

  • pandas.read_csv(filepath, sep='', delimeter=None, ues_cols=[])
  • DataFrame.to_csv(filepath, sep='', columns=None, header=True,index=True,index_label=None,mode='w',encoding=None)

3.4.2 HDF5

  • pandas.read_hdf(path, key=None , **kwargs)

hdf5文件的读取和存储都需要指定一个键,值为要存储的DataFrame

day_close = pd.read_hdf("文件路径")
day_close.to_hdf("文件路径", key="close") # 不指定key无法存取

pd.read_hdf("test.h5", key="close").head() #不指定键值也可以进行读取

#当有多个键值得情况下,必须带着key,否则无法读取

3.4.3 json

  • read_json(path)
sa = pd.read_json("文件路径", orient='records', lines=True) 
sa.to_json("文件路径", orient="records")

3.5 高级处理-缺失值处理

  • 缺失值处理思路:

    • 删除含有缺失值的样本
    • 替换缺失值
  • 判断数据是否为nan

    • pd.isnull(df)
    • pd.notnull(df)
  • 存在缺失值nan,并且是 np.nan

    • 删除存在缺失值的:dropna(axis='rows', inplace=False)
    • 替换缺失值:fillna(value, inplace=True)
  • 不是缺失值但是有默认的标记

    • 替换为np.nan
      • df.replace(to_replace=, value=)
        • to_replace 为替换前的值
        • value 为替换后得值
    • 按照处理np.nan的步骤
import pandas as pd
import numpy as np
movie = pd.read_csv('文件路径')
pd.isnull(movie) # 返回True or False
np.any(pd.isnull(movie))
pd.isnull(movie).any() #判断每个字段是否存在缺失值的情况


#不是缺失值但是有默认的标记
#如果源文件没有标题,默认会将第一行当做标题,我们可以添加name属性,为其添加标题
pd.read_csv("文件路径")
data_new = data.replace(to_replace='?', value=np.nan)
data_new.dropna(inplace=True)
data_new.isnull()

3.6 高级处理-合并

3.6.1 pd.concat实现合并

  • pd.concat([data1, data2], axis= 1)

3.6.2 pd.merge实现合并

  • pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False,sort=True,suffixes=('__x', '__y')

  • merge_method

    • inner
    • left
    • right
    • outer

3.7 高级处理-数据离散化

  • 对数据进行分组
    • 自动分组:pd.qcut(data, bins)
    • 自定义分组:pd.cut(data, bins)
    • 对数据进行分组将数据分组 一般会与value_counts搭配使用,统计每组的个数
      • series.value_counts():统计分组次数
  • 对分好组的数据求哑变量
    • panfas.get_dummies(data, prefix=None)
      • data:array-like, Series, or DataFrame
      • prefix:分组名字
 #准备数据
data = pd.Series([np.random.randint(150, 200) for i in range(8)])
#分组
#自动分组
SR = pd.qcut(data, 3)
type(SR)
#转化为one-hot编码
pd.get_dummies(SR, prrfix='height')
#看到每个区间有多少个人
pd.value_counts()


# 自定义分组
bins = [150, 165, 180, 195]
sr = pd.cut(data, bins)
pd.get_dummies(sr, prefix='身高')

3.8 高级处理-交叉表和透视表

https://blog.csdn.net/u012735708/article/details/86504489

3.9 分组与联合

  • DataFrame.groupby(ley, as_index=False)
    • key:分组的列依据,可以多个

col = pd.DataFrame({'color':['white', 'red', 'green', 'red', 'green'], 'object':['pen', 'pencial', 'pencil', 'ashtray', 'pen'], 'price1':[5.12, 435.23, 23.12, 23.3, 2.1],'price2':[3.2, 2.34, 12.23, 23.213, 2.1]})
# 进行分组,对颜色分组,pricel进行聚合
# 用DataFrame的方法进行分组
col.groupby(by="col")
col.groupby(by='color')['pricel'].max()
col