(博文体系参考:《Python数据分析与应用》课本)
任务数据如下:
读入csv文件时,encoding必须是正确的,常用的编码格式有:UTF-8 , UTF-16 , GBK , GB2312 , GB18030等。
如果和文件的编码格式不符合时,则会报错:
import pandas as pdpath = "D:/mystudy/大三上学期作业/PythonPython/chapter4/第4章任务数据/data/meal_order_info.csv"order1 = pd.read_csv(path,sep=',',encoding = 'utf-8') # 默认格式就是utf-8报错:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc3 in position 0: invalid continuation byte比较读入文件的sep参数不同时,读入文件的不同:
order1 = pd.read_csv(path,sep=',',encoding = 'gbk')order2 = pd.read_csv(path,sep=';',encoding = 'gbk')order3 = pd.read_csv(path,sep='"',encoding = 'gbk')
可以用os库中的os.listdir()函数来查看当前文件夹下的所有文件:
import osprint(os.listdir())type(os.listdir())输出:['meal_order_detail.xlsx','meal_order_detail1.sql','meal_order_detail2.sql','meal_order_detail3.sql','meal_order_info.csv','test.py','users.xlsx','数据特征说明.xlsx']list查看当前目录的子文件夹下的文件目录:(假设现在在“第四章任务数据”子文件夹下,绝对目录认为是本博文第一段代码中的path路径)
os.listdir('../data/')输出:(未实际运行,但理论上是这样?)['meal_order_detail.xlsx','meal_order_detail1.sql','meal_order_detail2.sql','meal_order_detail3.sql','meal_order_info.csv','test.py','users.xlsx','数据特征说明.xlsx']可以将数据以csv文件格式或者是xls文件格式(也就是Excel对应的)保存到本地。
关于pandas的重要部分:DataFrame
注意取元素的时候,尽量用index,而不是直接取行,因为数据可能被改变过了。
我们先来看一下order1读入的具体内容,并且查看一下order1的类型:
注意到,最左侧的列一定是行的索引,索引为0的行是标题(用.column获取),
注意:不论是DataFrame还是Series,访问索引的唯一方法只有: .index,没法用loc或者其他方法获取到!!!
print("查看order1的主要参数:")print("values:")print(order1.values)print("index:")print(order1.index)print("columns:")print(order1.columns)print("dtypes:")print(order1.dtypes)输出:查看order1的主要参数:values:[[417 1442 4 ... 1 18688880641 '苗宇怡'][301 1095 3 ... 1 18688880174 '赵颖'][413 1147 6 ... 1 18688880276 '徐毅凡']...[692 1155 8 ... 1 18688880327 '习一冰'][647 1094 4 ... 1 18688880207 '章春华'][570 1113 8 ... 1 18688880313 '唐雅嘉']]index:RangeIndex(start=0, stop=945, step=1)columns:Index(['info_id', 'emp_id', 'number_consumers', 'mode', 'dining_table_id','dining_table_name', 'expenditure', 'dishes_count', 'accounts_payable','use_start_time', 'check_closed', 'lock_time', 'cashier_id', 'pc_id','order_number', 'org_id', 'print_doc_bill_num', 'lock_table_info','order_status', 'phone', 'name'],dtype='object')dtypes:info_id int64emp_id int64number_consumers int64mode float64dining_table_id int64dining_table_name int64expenditure int64dishes_count int64accounts_payable int64use_start_time objectcheck_closed float64lock_time objectcashier_id float64pc_id float64order_number float64org_id int64print_doc_bill_num float64lock_table_info float64order_status int64phone int64name objectdtype: object.
注意,DataFrame可以转置!有了转置操作的加持,许多需求就变得简单了。
.
注意,DataFrame可以做运算!(比如乘法运算) 输入:(注意!两个int类型的Series是可以做乘法的!)order1['info_id']*order1['emp_id']Out[87]: 0 6013141 3295952 4737113 4838904 428848940 701895941 731808942 799260943 707818944 634410Length: 945, dtype: int64
.
1.查看DataFrame中数据
使用命令:order1['info_id'] # 当成字典去访问,要加单引号或:order1.info_id # 当成dataframe中的属性去访问,不需要加单引号输出:0 4171 3012 4133 4154 392...940 641941 672942 692943 647944 570Name: info_id, Length: 945, dtype: int64虽然都可以访问,但是推荐第一种,因为避免和关键字重名或是列名为'123'这样的数字字符串等,容易引起混淆
注意,将DataFrame转置后,则不能这样用上述方法数据了!
下面来学习取出一列,多列,所有列的元素。
但是要注意一个区别,这里的第一个中括号代表的不是行索引!!而是属性列!
想要访问索引的唯一方法就是调用.index函数!
同时还有两个函数送上:.head(x),.tail(x) ,分别用来访问前x个,后x个。(不传参数则默认为5)
当然,还有访问操作更加灵活的.loc[]和.iloc[]函数(注意是中括号!!!这个后面再说)
请取出‘info_id’这一个Series中的前三个元素 输入:order1['info_id'][0:3]Out[43]: 0 4171 3012 413Name: info_id, dtype: int64输入:order1['info_id'].shapeOut[45]: (945,)输入:type(order1['info_id'])Out[46]: pandas.core.series.Series 请取出'info_id'和'emp_id'这两列的前三个元素: 输入:order1[['info_id','emp_id']].shape #注意别忘了里面这一层中括号!他需要传入一个listOut[48]: (945, 2)输入:order1[['info_id','emp_id']][0:3]Out[49]: info_id emp_id0 417 14421 301 10952 413 1147输入order1[['info_id','emp_id']].head(3) #不传参数则默认为5列Out[53]: info_id emp_id0 417 14421 301 10952 413 1147取出所有列的前三个元素: 输入:order1[:][0:3]Out[50]: info_id emp_id number_consumers ... order_status phone name0 417 1442 4 ... 1 18688880641 苗宇怡1 301 1095 3 ... 1 18688880174 赵颖2 413 1147 6 ... 1 18688880276 徐毅凡[3 rows x 21 columns]输入:order1[:][0:3].shapeOut[51]: (3, 21)
下面来介绍兄弟函数loc[]和iloc[]函数(其实就是和array几乎一样的多维访问方式了),这两个函数的区别仅在对参数的要求有部分区别。(当然,也有交叉重叠的部分)
注意:loc[]函数传入的行索引是前闭后闭区间,iloc[]函数传入的行索引和列索引都是前闭后开
报错系列:order1.iloc[0:3,'info_id']order1.loc[0:3,0:3]无错系列:order1.loc[0:3,'info_id']order1.loc[0:3,:]order1.iloc[0:3,0:3]order1.iloc[0:3,:]例子:(前两个例子的输出一致)输入1:order1.iloc[0:3,[0,1,2]]Out[65]: info_id emp_id number_consumers0 417 1442 41 301 1095 32 413 1147 6输入2:order1.iloc[0:3,0:3]Out[62]: info_id emp_id number_consumers0 417 1442 41 301 1095 32 413 1147 6输入3:(我也不知道为啥标签变成行了....求大佬告知)order1.iloc[3,[0,1,2]]Out[66]: info_id 415emp_id 1166number_consumers 4Name: 3, dtype: object输入4:(loc极其灵活,第一维可以传入表达式来筛选行,就和数据库的select语句一样灵活!iloc却不行,根本原因在于表达式语句返回一个bool类型的Series,而iloc可接收的数据类型不包括Series!但非要使用iloc也是可以的,比较麻烦,在返回的Series中取其value,让他变成一个bool类型的array即可。)order1.loc[order1['number_consumers']==5,['number_consumers','info_id']]Out[72]: number_consumers info_id38 5 68843 5 31771 5 83197 5 266126 5 712.. ... ...852 5 1017858 5 1025870 5 1104896 5 1300911 5 588[71 rows x 2 columns]其实还有一种ix[]方法,但是效率低于loc和iloc,所以在此不做介绍。
2.修改DataFrame中数据
注意修改前先备份原文件!order2 = order1.copy()
尽量使用loc[]或者iloc[]而不是用属性去访问,原因不详,反正会有warning(有懂的大神欢迎讨论区讨论)
(目前思考:原因和二维array中取数,不能直接[x][y]而应该[x , y]是一个道理,对于array:你直接[][]相当于对得到的第一个一维数组再去取值,所以速度会慢很多,而且这样不是标准写法。对于这里,warning表示的是你对一个slice的一个切片,相当于是一个临时变量副本?然后你再对他进行操作,所以他给了你一个提示?所以这样取数字的时候不会给你这个warning,但是当你改变值的时候,就给你这样一个警示,让你检查一下语法是否正确?所以对于DataFrame一般来说这样二维操作,取数没有问题,对于一维的运算也没有任何问题,可以任意使用,但是对于二维问题的赋值操作需要谨慎?所以一般还是用loc[]比较常见?以上仅时个人意见,不具有权威性。反正对于下面用到的order1['use_start_time'] = pd.to_datetime(order1['use_start_time'])这一句对一维的赋值操作,是不会有任何问题的,也就是说按照属性直接取值是可以的,但是对于[][]这样的二维切片操作就要注意了)
输入;order1['info_id'][0] = 400警告:__main__:1: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrameSee the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy输入:order1.loc[0,'info_id'] = 417无警告3.增添DataFrame中数据
新增一列:
输入1:(前面提到了,两个int类型的Series是可以做乘法的!)order1['hahaha']=order1['info_id']*10order1['hahaha']Out[84]: 0 41701 30102 41303 41504 3920940 6410941 6720942 6920943 6470944 57003.删除DataFrame中数据 输入1:(注意,可以一口气删多列)order1.drop(labels=['order_status','lock_table_info'],axis=1) #当labels是列标的时候,axis=1Out[29]: info_id emp_id number_consumers ... print_doc_bill_num phone name0 417 1442 4 ... NaN 18688880641 苗宇怡1 301 1095 3 ... NaN 18688880174 赵颖2 413 1147 6 ... NaN 18688880276 徐毅凡3 415 1166 4 ... NaN 18688880231 张大鹏4 392 1094 10 ... NaN 18688880173 孙熙凯.. ... ... ... ... ... ... ...940 641 1095 8 ... NaN 18688880307 李靖941 672 1089 6 ... NaN 18688880305 莫言942 692 1155 8 ... NaN 18688880327 习一冰943 647 1094 4 ... NaN 18688880207 章春华944 570 1113 8 ... NaN 18688880313 唐雅嘉[945 rows x 19 columns]输入2:(删除第0行)order1.drop(labels=0,axis=0)Out[30]: info_id emp_id number_consumers ... order_status phone name1 301 1095 3 ... 1 18688880174 赵颖2 413 1147 6 ... 1 18688880276 徐毅凡3 415 1166 4 ... 1 18688880231 张大鹏4 392 1094 10 ... 1 18688880173 孙熙凯5 381 1243 4 ... 1 18688880441 沈晓雯.. ... ... ... ... ... ... ...940 641 1095 8 ... 1 18688880307 李靖941 672 1089 6 ... 1 18688880305 莫言942 692 1155 8 ... 1 18688880327 习一冰943 647 1094 4 ... 1 18688880207 章春华944 570 1113 8 ... 1 18688880313 唐雅嘉[944 rows x 21 columns]
关于时间模块 将字符串时间转换成标准时间
注意那些有趣的函数都是来自datatime库的而不是numpy库!有兴趣的同学可以学一下datatime库!!
以上类型,概念上理解分成两类,一类代表时间点,一类代表时间段。
字符串转换成标准时间分成三类: 1.直接转化成Timestamp格式将字符串转换成标准时间的代码十分简短,这里提供两种方式(其实本质上是一种,只不过一种是以属性形式去访问,另一种是loc[]去访问)
order1.loc[:,'lock_time'] = pd.to_datetime(order1.loc[:,'lock_time'])order1['use_start_time'] = pd.to_datetime(order1['use_start_time'])Timestamp类型时间,代表时间点可以进行减法,比如用终止时间减去起始时间,取出那个min,如果这个min小于0,那么肯定是异常值了,也就是说这是处理异常值的一个方法。
2.直接转化成 DatatimeIndex类型不常用,不介绍
3.直接转化成PeriodIndex类型不常用,不介绍
提取时间序列数据信息样例代码:
yy = [item.year for item in order1['lock_time']]输出会是一个list 加减时间数据,学习Timedelta类!
对于时间,可以做加法也可以做减法。但是作为Timestamp类型,一定要注意加完或减完的范围一定要在 1677-09-21 到 2262-04-11 之间
加减时间数据练习及加深理解:
在对话框中按照顺序输入下面代码:输入1:df_Update['ListingInfo1']Out[74]: 0 2014-03-051 2014-03-052 2014-03-053 2014-03-054 2014-03-05372458 2014-03-05372459 2014-03-05372460 2014-03-05372461 2014-03-05372462 2014-03-05Name: ListingInfo1, Length: 372463, dtype: timedelta64[ns]输入2:df_Update['ListingInfo1'] = df_Update['ListingInfo1'] + pd.to_datetime('2014-03-05 11:22:33')报错输入3:df_Update['ListingInfo1'] = df_Update['ListingInfo1'] - pd.to_datetime('2014-03-05 11:22:33')df_Update['ListingInfo1']Out[77]: 0 -1 days +12:37:271 -1 days +12:37:272 -1 days +12:37:273 -1 days +12:37:274 -1 days +12:37:27372458 -1 days +12:37:27372459 -1 days +12:37:27372460 -1 days +12:37:27372461 -1 days +12:37:27372462 -1 days +12:37:27Name: ListingInfo1, Length: 372463, dtype: timedelta64[ns]输入4:df_Update['ListingInfo1'] = df_Update['ListingInfo1'] + pd.to_datetime('2014-03-05 11:22:33')df_Update['ListingInfo1']Out[79]: 0 2014-03-051 2014-03-052 2014-03-053 2014-03-054 2014-03-05372458 2014-03-05372459 2014-03-05372460 2014-03-05372461 2014-03-05372462 2014-03-05Name: ListingInfo1, Length: 372463, dtype: datetime64[ns]输入5:df_Update['ListingInfo1'] = df_Update['ListingInfo1'] + pd.Timedelta(seconds = 1)df_Update['ListingInfo1']Out[81]: 0 2014-03-05 00:00:011 2014-03-05 00:00:012 2014-03-05 00:00:013 2014-03-05 00:00:014 2014-03-05 00:00:01372458 2014-03-05 00:00:01372459 2014-03-05 00:00:01372460 2014-03-05 00:00:01372461 2014-03-05 00:00:01372462 2014-03-05 00:00:01Name: ListingInfo1, Length: 372463, dtype: datetime64[ns]输入6:df_Update['ListingInfo1'][0] = df_Update['ListingInfo1'][0] - pd.Timedelta(seconds = 1)报warning:(但是依旧可以执行)__main__:1: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrameSee the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy输入7:df_Update['ListingInfo1']Out[84]: 0 2014-03-04 23:59:591 2014-03-05 00:00:002 2014-03-05 00:00:003 2014-03-05 00:00:004 2014-03-05 00:00:00372458 2014-03-05 00:00:00372459 2014-03-05 00:00:00372460 2014-03-05 00:00:00372461 2014-03-05 00:00:00372462 2014-03-05 00:00:00Name: ListingInfo1, Length: 372463, dtype: datetime64[ns]
对于求访问数据类型的几种方法:
要么就是直接用DataFrame的dtypes函数(别落下了s!!)
要么就是单独取出一个数据出来type()(或者直接输出,一般也会给出对应的类型)
但是为什么
会不一样?百思不得其解
答:可能是Console的原因吧,我print一下就好了
end