先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Python全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Python知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024c (备注Python)
正文
- read_excel()默认读取当前py文件所在同目录下的文件,若文件不存在,则会报错,若需要读取不同目录下的文件,则需要在文件名前增加对应的路径,此时可以封装一个如下函数来读取某个路径下某个文件名的excel文件
def read_data(algo_path, file_name):
‘’’
读取指定路径下的excel文件,并返回dataframe
:param algo_path:文件所在的路径
:param file_name:文件名称
:return:
‘’’
store_path = os.path.join(algo_path, file_name) # 将路径和文件名相连,形成读取路径入参
df = pd.read_excel(store_path) # 读取对应路径下的对应文件
return df
Note:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 1)执行带有to_excel()的程序时,在导出路径下,与导出对象同名称的.xlsx文件不能开着。
- 2)执行read_excel()函数时,对源文件不作修改的情况下,调试时打开文件不影响程序执行。
三、数据概要信息
将excel中的信息转化为dataframe数据结构后,我们可以使用如下的方法来快速获得该数据列表的相关摘要信息。
data = pd.read_excel(“input_data.xlsx”) # 读取excel数据
data.head() # 查看数据框的前几行,默认为5行,括号中为查看数据的行数
data.tail() # 查看数据框的后几行,默认为5行,括号中为查看数据的行数
data.shape # 获取数据框的行数和列数,得到一个包含行数和列数的元组
data.shape[0] # 获取该表的总行数,不包括列头的那一行
data.shape[1] # 获取该表的总列数,不包括行索引的那一列
data.describe() # 生成数据的统计摘要信息
data.info() # 显示数据框的基本信息
四、数据清洗和预处理
为甲方开发智能决策系统时,算法的输入数据往往来自于客户业务系统的数据库,其中不免存在一些“脏数据”:譬如某一列的字段数据类型与预期不一致,某一列必填字段存在缺失值,这些脏数据的存在很有可能会导致后续的代码运行报错,因此最好在算法开发之前,建立数据清洗的预处理模块,将导入的源数据(raw_data)转变为算法开发过程中便于检索的基础数据(basic_data)。此外为方便算法开发,往往也需要修改导入数据的列名,或截取其中的部分列名字段即可(譬如笔者拿到的基础视图有将近上百列业务字段,但实际可能只需要其中二十多列的字段)。
针对上述应用背景,笔者在数据清洗和预处理环节主要用到的一些函数和使用方法如下,供读者参考~
4.1 修改某列的数据类型并处理缺失值
- 利用.astype()方法统一某一列字段的数据类型,防止后续出现数据类型报错
- 转化为float后,可以将空值替换为’0’或者空字符串,可作为缺失值处理的一种简便方式
- 若不进行上述方式处理时,当dataframe是由.xlsx文件导入时,空值将被dataframe默认处理为"nan/NAN",极有可能对后续的数据统计和处理带来影响
示例一:
temp_data[‘columnA’]= temp_data[‘columnA’].astype(float) # 将对应的列均专转化float格式
temp_data[‘columnA’]= temp_data[‘columnA’].str.replace(’ ', “0”) # 将空值转化为字符串“0”
示例二:
temp_data[‘备注’] = temp_data[‘备注’].astype(str).fillna(‘’)
4.2 删除列/行数据
(1)根据自定义条件删除对应的行数据
- 删除A列值=T1,B列值=SG4的行向量数据
- 为了让原表发生更改,下文的代码将删除后的结果重新赋值给原表。如果不希望改变原表,可以将删除后的结果赋值给一个新的变量
- 使用.drop()函数时,不改变源对象(只是生成一个副本对象,不进行原地修改)
data = data.drop(data2[(data2[‘A’] == “T1”) & (data2[‘B’] == “SG4”)].index)
(2)根据列名删除列数据
- 删除原来dataframe对象中,列名=columnA的那列数据
- 删除列数据时,需要指定axis=1,表示对列向量进行删除
df = df.drop(‘columnA’, axis=1)
4.3 判断某一列是否存在缺省值
- 使用.isnull()/.isna()与.any()函数来快速判断某一列是否存在空值
import pandas as pd
创建一个DataFrame
data = {‘A’: [1, 2, 3, None, 5],
‘B’: [‘a’, ‘b’, ‘c’, ‘d’, ‘e’]}
df = pd.DataFrame(data)
判断列’A’是否存在空值,或采用df[‘A’].isna().any()
if df[‘A’].isnull().any():
print(“列’A’存在空值”)
else:
print(“列’A’不存在空值”)
4.4 预处理列数据字段,并修改某一列的所在位置
(1)读取指定列的数据并作列名转换
- 由于业务系统中源data的列名字段过多,当我们开发算法过程中发现仅需要提取其中某些列的数据时,可采用如下方式进行指定列的提取和列名字段的映射转换:
- 笔者建议new_columns这类涉及到业务字段与算法开发字段进行字段名映射关系的内容,可以单独写到一个json文件中进行维护,方便对接接口开发的同事参考或自己进行日常维护改动。
name_list = [‘A’,‘B’,‘C’,‘D’,‘E’,‘F’]
temp_data = temp_data[name_list] # 只提取指定列
new_columns = {‘A’:“姓名”,‘B’:“年龄”,‘C’:“性别”,‘D’:“身高”,‘E’:“体重”,‘F’:“学历”}
temp_data.rename(columns=new_columns, inplace=True) # 进行列名字段的转换
(2)修改某一列的排序位置
- 作为一名强迫症患者,笔者在数据处理过程中,偶尔希望某个字段排在某个字段前/后,方便在输出该dataframe时,易于人工审查算法的求解结果,故笔者封装了如下的函数特用于某一列的位置转变,供小伙伴们参考~
- Note:如果想一开始就对源列表的字段名排列顺序,只需要在上文的name_list中将需要用到的列名按照指定的顺序进行排列即可
def change_column_location(input_data,change_demand):
‘’’
改变给定dataframe中,某一列数据的所在位置,将指定列插入到第change_idx之前
:param input_data: 给定的原始数据
:param change_demand: 传入一个dict,key为需要改变的列名字段,value为插入的列索引
:return:
‘’’
for column_name,change_idx in change_demand.items():
first_column = input_data.pop(column_name)
input_data.insert(change_idx, column_name, first_column)
return input_data
五、dict、series以及dataframe三者之间的转换
笔者在使用pandas库对数据进行预处理、分析、统计、排序等操作的过程中,各类操作返回的对象或需要生成的对象基本在dict、series以及dataframe这类对象直接进行转换,刚开始按照算法设计框架进行数据处理和代码层面的问题抽象时,时常因搞混当前新赋值对象是什么类型而出bug,亦或将dict/series的对象合并到dataframe中而出错,在经历过一段时间的尝试和试错后,也有了一些理解和体会。
5.1 dict/series/dataframe的数据形式
为便于读者理解和区分三类数据对象,笔者将其特点总结如下:
- dict:以{key:value}形式存储的键-值对,可直接通过 对象[键值] 的方式来索引值
- series: 本质以[{key1:value1},{key2:value2},…] (附带属性name=column,代表该列值索引的内容) 的形式存储一系列的键值对,同样可通过 **对象[键]**来索引值,但与dict不同的是,series的键往往为行索引/行标签,属于一维数据。
- dataframe:本质上是将一系列的series进行拼接,按照相同的key值进行了组合,形成类似于[{key1:[value1,value2,…],{key2:[value11,value22,…]},{key3:[value111,value222,value333,…]},…],其中key1,key2,key3 可以视作一份excel中的列A,列B,列C,[value1,value2,…]即代表列A这一列的值
- 上述举例中,key和value均指代某一个元素的属性和对应的值,而单个key对应多个value值则指代一个行向量,即 key1:[value1,value2,…] 的形式
- 为了说明dict、series以及dataframe的数据区别和转化过程,笔者基于如下的例子进行示意
# dict格式对象,此时key为列名,value为列向量值
column1 = {‘A’: [1, 2, 3, 4, 5]}
column2 = {‘B’: [‘a’, ‘b’, ‘c’, ‘d’, ‘e’]}
column3 = {‘C’: [0.5,0.4,0.6,0.7,1.0]}
# dict格式对象,此时key为列名,value为向量值
test_dict = {‘姓名’:“nancy”,‘年龄’:26,“身高”:100,‘体重’:150,‘性别’:“男”,}
series格式对象
series1 = pd.Series([1, 2, 3, 4, 5], name=‘A’)
series2 = pd.Series([‘a’, ‘b’, ‘c’, ‘d’, ‘e’], name=‘B’)
series3 = pd.Series([0.5, 0.4, 0.6, 0.7, 1.0], name=‘C’)
test_ser = pd.Series(test_dict)
print(series1)
print(test_ser)
dataframe格式对象
c1 = pd.DataFrame(column1)
c2 = pd.DataFrame(column2)
c3 = pd.DataFrame(column3)
df = pd.concat([c1,c2,c3])
test_df = pd.DataFrame(test_ser).T
print(df)
print(test_df)
从dataframe取出其中第一行数据
temp_series1= df.iloc[0]
print(temp_series1)
从dataframe取出其中第一列数据
temp_series2 = df1.iloc[:,0] # 方法一获取第一列
temp_series2 = df1.loc[:, ‘A’] # 方法二获取第一列
print(temp_series2)
代码的运行结果如下,可以得出以下几点结论:
- series的行标签既可以为int类型,也可以为str(即列名的key值)
- 无论从dataframe获取一列还是一行的数据,返回对象均为series,但对应Name属性不相同
- 从dataframe获取一列数据时,需要用行的整数位置来索引对应的数据;而当获取一行数据时,则使用列名来索引对应的数据,此时用法等价于一个dict对象。
series格式输出
0 1
1 2
2 3
3 4
4 5
Name: A, dtype: int64 # 注意此时使用 series1[] 来索引值时,只能使用int类型的行索引来取值
姓名 nancy
年龄 26
身高 100
体重 150
性别 男
dtype: object # 此时使用 test_ser[] 来索引值时,可直接使用[key值]的方式来索引取值
dataframe格式输出
A B C
0 1 a 0.5
1 2 b 0.4
2 3 c 0.6
3 4 d 0.7
4 5 e 1.0
姓名 年龄 身高 体重 性别
0 nancy 26 100 150 男
从dataframe取出其中的第一行数据–series对象,Name=0(行索引),行标签为原来dataframe的列名
A 1
B a
C 0.5
Name: 0, dtype: object
从dataframe取出其中的第一列数据–series对象,Name=‘A’(列名),行标签为原来dataframe的行索引
0 1
1 2
2 3
3 4
4 5
Name: A, dtype: int64
5.2 三种类型之间的转换方式
(1)将多个dict,合并到一个dataframe对象中
column1 = {‘A’: [1, 2, 3, 4, 5]}
column2 = {‘B’: [‘a’, ‘b’, ‘c’, ‘d’, ‘e’]}
column3 = {‘C’: [0.5, 0.4, 0.6, 0.7, 1.0]}
方法一:dict单独转成dataframe后再进行合并
c1 = pd.DataFrame(column1)
c2 = pd.DataFrame(column2)
c3 = pd.DataFrame(column3)
df1 = pd.concat([c1, c2, c3], axis=1) # 按照列合并
print(“df1 如下:\n”, df1)
方法二:转换为series后,再置于list后进行集中转换
series1 = pd.Series(column1[‘A’], name=‘A’)
series2 = pd.Series(column2[‘B’], name=‘B’)
series3 = pd.Series(column3[‘C’], name=‘C’)
s_list = [series1,series2,series3]
info = []
for i in range(3):
info.append(s_list[i])
df = pd.DataFrame(info).T
print(“df 如下:\n”, df)
代码运行结果如下:
方法一输出结果>>>>>>>>>>>>>>>>
df1 如下:
A B C
0 1 a 0.5
1 2 b 0.4
2 3 c 0.6
3 4 d 0.7
4 5 e 1.0
方法二输出结果>>>>>>>>>>>>>>>>
df 如下:
A B C
0 1 a 0.5
1 2 b 0.4
2 3 c 0.6
3 4 d 0.7
4 5 e 1.0
(2)将一个dict/series对象合并到一个dataframe对象中(为data添加一行数据)
- add_row 为一个dict对象,key值与待合并的dataframe对象的列名相同
- 方法一种:index=[1]代表将给定的dict转化为一个dataframe,其中行向量的行索引属性为1 (可以为任意int值),此时列名为原dict的key值,第一行的数据为对应的value值
- 方法二中:to_frame()方法将Series对象转换为DataFrame对象,然后transpose()方法对该DataFrame对象进行转置操作,即将行和列进行互换。这样,原本作为Series对象中的数据将被转换为一个行向量,而列名将成为DataFrame的索引。
add_row = {“A”: 111, ‘B’: ‘f’, ‘C’: 0.9999}
方法一:dict直接转化为dataframe后进行合并
new_df = pd.DataFrame(add_row ,index=[1])
df1 = pd.concat([df1, new_df])
print(new_df)
print(df1)
方法二:dict转化为series后,再转化为dataframe进行合并
add_row = pd.Series(add_row)
print(add_row)
add_row = add_row.to_frame().transpose()
或者采用 add_row = add_row.to_frame().T
print(add_row)
df1 = pd.concat([df1, add_row])
print(df1)
代码结果如下:
- 很显然将dict转化为行数据添加到dataframe使用方法一更直接,此处笔者特意阐述方法二,旨在让读者同时也了解series合并到dataframe中的转换方式
方法一运行过程>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
dict直接转化一个dataframe对象
A B C
1 111 f 0.9999
将该行数据与原来的dataframe进行合并的结果
A B C
0 1 a 0.50
1 2 b 0.40
2 3 c 0.60
3 4 d 0.70
4 5 e 1.00
1 111 f 0.9999
方法二运行过程>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
# dict转化为series对象
A 111
B f
C 0.9999
dtype: object
series对象再转为dataframe对象
A B C
0 111 f 0.9999
最后进行dataframe合并
A B C
0 1 a 0.50
1 2 b 0.40
2 3 c 0.60
3 4 d 0.70
4 5 e 1.00
0 111 f 0.9999
(3)将dataframe转换为dict对象
- dataframe转换为dict对象本质为提取其中的某一行/或一列数据,其转换过程仍然是通过先得到series对象,再转换为dict对象
- 从dataframe提取行数据/列数据的方法和介绍详见第六节~
series_obj = df1.iloc[0] # 取dataframe中的第一行数据,得到的是series,行标签为列名
dict_obj = dict(series_obj) # series转化为dict,或者使用dict_obj = series_obj.to_dict()
print(dict_obj)
series_obj = df1.iloc[:,0] # 取dataframe中的第一列数据,得到的是series,行标签为int类型的索引位置
dict_obj = dict(series_obj) # series转化为dict,或者使用dict_obj = series_obj.to_dict()
print(dict_obj)
代码结果如下:
行向量转化为dict的结果,key为列名,value为值
{‘A’: 1, ‘B’: ‘a’, ‘C’: 0.5}
列向量转化为dict的结果,key为行索引,value为值
{0: 1, 1: 2, 2: 3, 3: 4, 4: 5}
六、数据提取、索引与筛选
使用pandas库筛选、分析数据的过程其实和使用office软件去处理excel数据是类似的,其区别主要在于前者将各种需要人工逐步点击的数据筛选、提取、过滤或者计算公式的操作全部通过代码实现了自动化处理。下文给出了笔者在进行数据提取或筛选时常用的一些方法和注意要点。
6.1 iloc[] 按照行/列位置索引获取数据
data.iloc[]常用于按照行/列索引来获取指定行、指定列的数据,得到一个新的dataframe对象或series对象,笔者常用的场景如下:
- 使用data.iloc[x,y]的方式即可获取dataframe中行索引为x行,列索引y列的某个值
- 使用data.iloc[x]的方式即可获取dataframe中行索引为x的行数据,返回的是series对象
- 使用data.iloc[:,y]的方式即可获取dataframe中第y列的列数据,返回的是series对象
- 使用data.iloc[x:y]的方式即可获取dataframe中行索引从x到y行的数据,返回的仍然为dataframe对象,这一点同列表的切片操作类似,是左闭右开的。
- 使用data.iloc[[x1,x2]:[y1,y2]]的方式即可获取dataframe中第x1x2行,y1y2列的数据,返回的仍然为dataframe对象,这一点同列表的切片操作类似,是左闭右开的。
注意>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 1)x和y均需要为int类型,否则会报错
- 2)x和y分别为dataframe中的行索引和列索引,但不完全等价于该数据在整个dataframe中的第x行和第y列(绝对位置),因为行索引index是可以修改的,故处理数据时,一定要注意整个列表的行索引是否是从0开始递增的,通常可以用data.reset_index(drop=True,inplace=True)来重置索引;其中当drop=False时,将自动生成一列(列名=index)用于记录重置索引前每一列数据的行索引
- 3)iloc[x,y]中的x和y必须是该dataframe内存在的行索引和列索引,否则会出现索引越界报错
data = pd.read_excel(“input_data.xlsx”) # 读取excel数据
item1 = data.iloc[0] # 取该DataFrame的第一行数据,返回对象为series格式,key为对应数据的列明,value为对应的值
item2 = data.iloc[-1] # 取该DataFrame的最后一行数据,返回对象为series格式,key为对应数据的列明,value为对应的值
item3 = data.iloc[0,0] # 取该DataFrame中第0行,第0列的数据(其中0行为除列名外的第一行)
data2 = data.iloc[1:5] # 取该DataFrame中第1行到第4行的数据,生成一份新的数据对应data2
6.2 loc[] 按照行/列标签索引来获取数据
data.loc[row_label,column_label] 方法常用于按照指定“标签”去提取数据,其中的row_label和column_label可以是单个标签、标签列表、布尔数组、切片等,分别用于指定行和指定列的位置;使用loc[]函数时,需要注意传入的行标签和列标签必须存在,否则会报错。具体的用法如下:
import pandas as pd
创建一个DataFrame
data = {‘Name’: [‘Alice’, ‘Bob’, ‘Charlie’, ‘David’],
‘Age’: [25, 30, 35, 40],
‘Gender’: [‘F’, ‘M’, ‘M’, ‘M’]}
df = pd.DataFrame(data)
使用loc[]提取指定行和列的数据
print(df.loc[1, ‘Name’]) # 提取第2行,Name列的数据,输出Bob
print(df.loc[1:2, [‘Name’, ‘Age’]]) # 提取第2行到第3行,Name和Age列的数据
笔者将自己使用loc[]提取数据的高频场景主要有以下两种,供小伙伴们参考:
1)用法一:批量修改某一字段下,符合指定条件的数据
- 当需要综合某一列/某几列的值,来改写另一列的值时,可通过如下方式进行批量修改:
根据"后工序"列的值,批量修改"集批后工序"列的值
底层逻辑为:利用loc[row_label,column_label]提取到对应的“单元格”,然后将其修改为“s1”
temp_data.loc[(temp_data[‘后工序’] == ‘S1’), ‘集批后工序’] = ‘s1’
根据"后工序"以及"镀层类型代码"列的值,批量修改"集批后工序"列的值
temp_data.loc[(temp_data[‘后工序’] == ‘D1’) & (temp_data[‘镀层类型代码’] == ‘ZF’), ‘集批后工序’] = ‘D1-ZF’
2)用法二:获取符合指定条件的行向量索引
- 当需要对比两份dataframe,相同元素的行索引是否一致时,可通过如下的方式进行判断:
def compare_sequence(self,algo_plan,formal_plan):
‘’’
对比algo_plan与formal_plan两份数据,判断其中相同MAT_NO的数据索引是否相同
‘’’
task_1 = algo_plan[algo_plan[‘MAT_NO’].isin(formal_plan[‘MAT_NO’])]
task_2 = formal_plan[formal_plan[‘MAT_NO’].isin(algo_plan[‘MAT_NO’])]
task_1.reset_index(drop=True,inplace=False)
task_2.reset_index(drop=True, inplace=False)
task1_list = list(task_1[‘MAT_NO’])
task2_list = list(task_2[‘MAT_NO’])
for i in range(task_1.shape[0]):
if task1_list[i] != task2_list[i]:
前提:每个元素(每一行数据)的MAT_NO标签是唯一的
indices = task_2.loc[task_2[‘MAT_NO’] == task1_list[i]].index[0]
if i < indices:
move = “>>>向后移动”
else:
move = “<<<向前移动”
- 需要注意的时,使用loc[]方法去提取数据时,通常返回一个dataframe对象,因此使用.index方法时,得到的为一个包含符合条件行的行索引列表(尽管可能只有1个元素),因此还需要用.index[0]的方式来取出所需的行索引
3)用法三:获取指定条件的行数据
- 用法三与用法二类似,均使用loc[]运算来提取满足指定条件下的dataframe对象
- 当我们需要基于某个唯一标识字段,去获取另一个dataframe对象中的行数据时,可采用如下的方法来获取到对应的一行数据(series格式)
- 在如下的代码中,通过data1.loc[]的方式,提取满足指定条件的dataframe对象,再利用iloc[0]的方式获得该dataframe中的首行数据,即可得到对应的series对象
- 使用该方法时,需要注意另一个被查询的dataframe对象中(data1),待查询标识(“MAT_NO”)必须是唯一的,否则可能无法取到唯一的那行期望数据
item_i = data1.loc[data1[‘MAT_NO’] == mat_no2].iloc[0] # 找到对应的行数据
6.3 使用[]运算符自定义筛选条件获取数据
- 使用[]方法提取指定条件的数据逻辑同我们使用excel中的“筛选”功能,并且更加的灵活和方便,代码如下:
ori_data为给定的源数据,假定该数据有“A”、“B”、“C”、“D”列
A列、B列为int格式,C列、D列为str格式
则通过下列语句可以筛选同时满足:1)A列值>=min_thick;2)B列值<=max_thick;3)C列值等于‘value’;4)D列的值属于require_material(列表)
temp_data = ori_data[(ori_data[‘A’] >= min_thick)
& (ori_data[‘B’] <= max_thick)
& (ori_data[‘C’] == ‘value’])
& (ori_data[‘D’].isin(require_materail))]
假如我们要提取data的第2、3行和从Price到Sales对应的列 (连续的列,用切片操作)
new_df = data[2:3,‘Price’:‘Sales’]
假如我们要选取所有的行和Fruits和Sales对应的列
new_df = data[:,‘Price’:‘Sales’]
注意>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- []中不同的条件表达式之间,表示“与”逻辑运算使用**“&”连接,表示“或”逻辑运算使用“|”**连接,若使用’and’或’or’会报错
- 使用data[‘column’].isin()的方法来筛选对应列中,值属于某几个枚举项的数据
- 切片操作与list的切片类似,但使用[]去提取对应行和列的数据时,为左闭右闭区间,同时列名“标签”之间必须是连续的
6.4 数据提取和筛选方法小结
- iloc[]利用行索引和列索引来提取指定数据,[]中只能为int类型,输入的行列索引之间用“,”分隔
- loc[]利用行标签和列标签来提取指定数据,[]中可以为标签/布尔判断语句
- 利用[]来自定义筛选数据的判断条件,并提取源数据的副本数据,且具有切片功能
- 提取数据和筛选数据可以灵活地结合上述三种方法来使用,但需要注意不同方法返回的对象格式,例如iloc[x]返回的是series,loc[“条件表达式”](仅对行数据进行筛选)返回的是dataframe对象,调试代码时建议多利用type()来确定自己真正得到了什么格式的对象
七、数据统计与排序
7.1 基础信息统计
pandas库中有内置函数可以帮助我们直接统计得到某一列数据的基础统计信息,以及对某列数据进行累计求和,非常便捷!
常用的统计方法如下:
data[‘columnA’].sum() # 求列名为‘columnA’的总和
data[‘columnB’].mean() # 求列名为‘columnB’的平均值
data[‘columnC’].max() # 求列名为‘columnC’的最大值
data[‘columnD’].max() # 求列名为‘columnD’的最小值
假若想要对某一列的数据进行累加求和,可使用cumsum()函数得到某一列值的累计求和值。并通过“[]”运算符对数据按照某个累计值进行截断处理,如下所示:
对某列数据进行累加求和统计,并按照指定值进行数据截断
temp_data[‘重量累计值’] = temp_data[‘重量’].cumsum()
temp_data[‘长度累计值’] = temp_data[‘长度’].cumsum()
temp_data = temp_data[(temp_data[‘重量累计值’] <= wt_max) & (temp_data[‘长度累计值’] <= km_max)]
7.2 自定义排序
pandas库中还有内置的排序函数,能够按照指定列,指定排序方式对数据进行快速排序,但需要注意的是,该排序函数分“拷贝排序”和“原地排序”两种情况,区别在于指定的inplace参数是否为True,具体用法如下所示:
- by=[]中填写的字段顺序代表了排序优先级,即下面代码中先根据x进行降序,在对x列相同值的行数据,按照y值进行降序排序
如下展示了两种对数据进行排序的方式,均实现了:将整个表格中的数据按照x,y列的值,进行降序、降序排序
第一种排序方式下,源数据并不会改变,而是生成了一个排序后的副本,将其重新赋值给了data
data = data.sort_values(by=[‘x’,‘y’],ascending=[False,False])
第二种排序方式下,源数据会发生改变,即进行了原地排序
data.sort_values(by=[‘x’,‘y’],ascending=[False,False],inplace=True)
注意:上述排序完毕后,数据的行索引也会跟着移动改变!
八、数据的聚类统计:groupby()函数的应用
在数据统计和分析过程中,聚类统计/提取数据往往是使用频率最高的处理方法,而pandas库中自带内置函数groupby(),可以帮助我们快速地对整个DataFrame按照某些字段和统计方法进行聚类分组统计,该函数的基础使用语法如下:
- data.groupby() 对dataframe对象进行分组,此时返回对象格式为“DataFrameGroupBy”
- 利用[]运算符对指定字段进行同组内的数值统计
- 当传入的分组标签唯一时,得到的结果为一个series对象,key为分组的枚举值,value为对应分组内的指标统计值;当传入的分组标签为一个[]时,得到的结果为一个dataframe对象
- 通过上述方式得到的分组统计结果,可使用iloc[]方式逐行进行遍历,但只能得到对应行的统计结果。若需要查询对应的分组标签和分组统计值,建议使用.reset_index()将其转换为dataframe对象,利用iloc[]获得各分组的series对象后,再查询对应的分组标签和分组统计量
将源数据根据列“A”进行分组
group_data = data.groupby(‘A’)
将源数据根据列“A”以及列“B”进行分组
group_data2 = data.groupby([‘A’,‘B’])
统计分组后C列数据之和
group_result1 = group_data[‘C’].sum() # group_result1为series对象,key为A列的值,value为根据A列字段分组后,不同分组的求和值
统计分组后D列数据的平均值
group_result2 = group_data[‘D’].mean() # group_result2为series对象,key为A列的值,value为根据A列字段分组后,不同分组的平均值
具体应用:根据集批后工序和排产小类将数据进行分组统计,并查询每一组的分组指标与对应统计量
data = pd.read_excel(“test_data.xlsx”)
group_df = data.groupby([‘集批后工序’,‘排产小类’])
print(group_df)
result_len = group_df [‘入口长’].max().reset_index()
for index,row in result_len .iterrows():
print(“index = {} 分组指标 = {} - {} 统计量 = {}”.format(index,row[‘集批后工序’],row[‘排产小类’],row[‘入口长’]))
利用groupby函数对数据进行分组统计后的结果查询和输出
使用上述方法进行聚类统计的局限性在于:1)只能使用dataframe自带的内置函数对数据进行统计;2)不能同时对不同列按照不同的统计逻辑进行分组处理;3)返回dataframe对象中只带有一组统计量的值。若要使用自定函数同时对多列数据按照不同的统计方法进行分组统计或处理, 可使用聚类统计更为灵活的.agg()方法,代码如下:
根据集批后工序字段进行聚类分组,并对“待排产量”列的值进行求和
data1 = data.groupby([‘集批后工序’]).agg({“待排产量”: sum})
根据集批后工序字段进行聚类分组,并对“小类”列的字段用;进行合并
data2 = data.groupby(‘集批后工序’).agg({‘小类’: lambda x: ‘;’.join(x)})
根据集批后工序与排产小类字段进行聚类分组,对“待排产量”的值进行统计求和,对焊接分组字段按照自定义函数group_set进行统计处理
data3 = data.groupby([‘集批后工序’,‘排产小类’]).agg({“待排产量”: sum,‘焊接分组’:group_set})
自定义的数据整合函数
def group_set(column):
class_big = ‘-’.join(set(list(column)))
return class_big
- groupby可以传入一个包含多字段名的[],即可根据不同列的字段进行分组
- agg的入参为字典对象,key为需要分组/统计分析的列名,value为对指定列进行数据统计/处理的函数
- agg()中传入自定义函数时,函数接收的默认传参为该列的数据,即series对象,key值默认为源数据中的行索引,values值即对应列的值
- 需要注意:通过上述方式返回的对象data1,data2和data3均为dataframe对象,其中行索引为分组的条件值,列索引为对应统计的指标,建议使用.reset_index()对dataframe进行索引转换,具体的差别如下:
- 此时再利用如下代码,即可得到指定分组下的指标统计值的字典对象(方便用key值索引):
group_info = dict(zip(data[‘集批后工序’], data[‘待排产量’])) # key值为分组枚举值,value为对应分组下的指标统计值
九、数据的自定义处理函数:apply()函数的应用
apply()函数主要用于对dataframe的数据按照自定义函数进行批量处理和筛选,其基本的用法如下,其中func为自定义的函数,也可以采用lambda x: func 的方式对对应的行数据或列数据应用自定的函数进行批量处理。
对每一列应用函数,生成副本dataframe对象后,赋值给data
data = df.apply(func, axis=0)
对每一行应用函数,生成副本dataframe对象后,赋值给data
data = df.apply(func, axis=1)
具体应用:根据每一行的数据(一个series对象)来定义每一行对应的物料是否属于紧急催货物料,其中check_in_urgent为自定义函数
temp_data[‘是否属于紧急催货物料’] = temp_data.apply(check_in_urgent,axis=1)
最后
🍅 硬核资料:关注即可领取PPT模板、简历模板、行业经典书籍PDF。
🍅 技术互助:技术群大佬指点迷津,你的问题可能不是问题,求资源在群里喊一声。
🍅 面试题库:由技术群里的小伙伴们共同投稿,热乎的大厂面试真题,持续更新中。
🍅 知识体系:含编程语言、算法、大数据生态圈组件(Mysql、Hive、Spark、Flink)、数据仓库、Python、前端等等。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注python)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
行批量处理。
对每一列应用函数,生成副本dataframe对象后,赋值给data
data = df.apply(func, axis=0)
对每一行应用函数,生成副本dataframe对象后,赋值给data
data = df.apply(func, axis=1)
具体应用:根据每一行的数据(一个series对象)来定义每一行对应的物料是否属于紧急催货物料,其中check_in_urgent为自定义函数
temp_data[‘是否属于紧急催货物料’] = temp_data.apply(check_in_urgent,axis=1)
最后
🍅 硬核资料:关注即可领取PPT模板、简历模板、行业经典书籍PDF。
🍅 技术互助:技术群大佬指点迷津,你的问题可能不是问题,求资源在群里喊一声。
🍅 面试题库:由技术群里的小伙伴们共同投稿,热乎的大厂面试真题,持续更新中。
🍅 知识体系:含编程语言、算法、大数据生态圈组件(Mysql、Hive、Spark、Flink)、数据仓库、Python、前端等等。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注python)
[外链图片转存中…(img-JL2FNsgI-1713711746189)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!