视频教程
1.pandas的常用数据类型 1.Series 一维,带标签数组
2.DataFrame 二维,Series容器
2.pandas之Series创建
3.pandas之Series切片和索引
4.pandas之Series的索引和值
5.pandas之读取外部数据 我们的这组数据存在csv中,我们直接使用pd. read_csv即可
和我们想象的有些差别,我们以为他会是一个Series类型,但是他是一个DataFrame,那么接下来我们就来了解这种数据类型
==小示例:==
现在假设我们有一个组关于狗的名字的统计数据,那么为了观察这组数据的情况,我们应该怎么做呢?
1 2 3 import pandas as pd df = pd.read_csv('./dogNames2.csv') print(df)
==效果展示==
6.pandas之DataFrame
DataFrame对象既有行索引,又有列索引
行索引,表明不同行,横向索引,叫index,0轴,axis=0
列索引,表名不同列,纵向索引,叫columns,1轴,axis=1
那么回到之前我们读取的狗名字统计的数据上,我们尝试一下刚刚的方法
那么问题来了:
很多同学肯定想知道使用次数最高的前几个名字是什么呢?
df.sort_values(by="Count_AnimalName",ascending=*False*)
==dataframe排序==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import pandas as pd df = pd.read_csv('./dogNames2.csv') # print(df) # print('*'*100) # print(df.head()) # print('*'*100) # print(df.info()) # print('*'*100) # print(df.describe()) # 以Count_AnimalName来排序(默认升序) # df = df.sort_values(by='Count_AnimalName') # ascending=True 为升序,False为倒序 df = df.sort_values(by='Count_AnimalName',ascending=False) print(df.head(10))
7.pandas之取行或者列 刚刚我们知道了如何给数据按照某一行或者列排序,那么现在我们想单独研究使用次数前100的数据,应该如何做?
df_sorted = df.sort_values(by="Count_AnimalName")
df_sorted[:100]
那么问题来了:
我们具体要选择某一列该怎么选择呢?df[" Count_AnimalName "]
我们要同时选择行和列改怎么办?df[:100][" Count_AnimalName "]
8.pandas之loc 还有更多的经过pandas优化过的选择方式:
1.df.loc 通过标签 索引行数据
2.df.iloc 通过位置 获取行数据
9.pandas之布尔索引 回到之前狗的名字的问题上,假如我们想找到所有的使用次数超过800的狗的名字,应该怎么选择?
回到之前狗的名字的问题上,假如我们想找到所有的使用次数超过700并且名字的字符串的长度大于4的狗的名字,应该怎么选择?
10.pandas之字符串方法
11.缺失数据的处理 观察下面这组数据
我们的数据缺失通常有两种情况:
一种就是空,None等,在pandas是NaN(和np.nan一样)另一种是我们让其为0,蓝色框中
对于NaN的数据,在numpy中我们是如何处理的?
在pandas中我们处理起来非常容易
判断数据是否为NaN:pd.isnull(df),pd.notnull(df)
处理方式1:删除NaN所在的行列dropna (axis=0, how='any', inplace=False)
处理方式2:填充数据,t.fillna(t.mean()),t.fiallna(t.median()),t.fillna(0)
处理为0的数据:t[t==0]=np.nan
当然并不是每次为0的数据都需要处理
计算平均值等情况,nan是不参与计算的,但是0会
==示例==
假设现在我们有一组从2006年到2016年1000部最流行的电影数据,我们想知道这些电影数据中评分的平均分,导演的人数等信息,我们应该怎么获取?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import pandas as pd, numpy as np from matplotlib import pyplot as plt df = pd.read_csv('IMDB-Movie-Data.csv') print(type(df)) print(df.info()) print(df.head()) print(df['Rating'].values) print(df['Rating'].describe()) # df['Rating'].mean()为numpy类型的数据,不能使用字符串拼接,需要先转换为字符串 # 电影评分平均值 print('电影平均分:' + str(df['Rating'].mean())) # 导演的人数 # df['Director'].tolist() # python tolist()方法:将数组或者矩阵转换成列表 # set(df['Director'].tolist()) # 使用set() 将数组去重并转换为set集合,集合是一个无序的不重复元素序列 print('导演人数:', len(set(df['Director'].tolist()))) # 别一种方法:df['Director'].unique()可以将df['Director']去重,并返回 print('导演人数:', len(df['Director'].unique())) # 由于每一部电影的演员有多人,所以先使用split(',')以逗号分隔,让每组数据的字符串重组为数组 print('所有演员二维数据:') print(df['Actors'].str.split(',').tolist()) temp_list = df['Actors'].str.split(',').tolist() # 将二维数组展开 nums = [i for j in temp_list for i in j] print('所有演员一维数组:') print(nums) # 数组去重,并取总数 actors = len(set(nums)) # 使用set集合的特点去重 actors2 = len(pd.Series(nums).unique()) # 使用pandas的unique方法去重 print('去重后演员的总人数:', actors, actors2) # 电影时长的最大最小值: max_runtime = df['Runtime (Minutes)'].max() max_runtime_index = df['Runtime (Minutes)'].argmax() min_runtime = df['Runtime (Minutes)'].min() min_runtime_index = df['Runtime (Minutes)'].argmin() runtime_median = df['Runtime (Minutes)'].median()
==示例==
对于这一组电影数据,如果我们希望统计电影分类(genre)的情况,应该如何处理数据?
思路:重新构造一个全为0的数组,列名为分类,如果某一条数据中分类出现过,就让0变为1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 from matplotlib import pyplot as plt import numpy as np import pandas as pd df = pd.read_csv('IMDB-Movie-Data.csv') print(df['Genre']) temp_list = df['Genre'].str.split(',').tolist() print(temp_list) # 利用set展开二维列表并去重 genre_list = list(set([i for j in temp_list for i in j])) print(genre_list) # 构造全为0的DataFrame:df一样的行数,分类总数的列数,索引为分类数据genre_list # np.zeros((a,b))里面传的是元组 zeros_df = pd.DataFrame(np.zeros((df.shape[0], len(genre_list))), columns=genre_list) print(zeros_df) for i in range(df.shape[0]): zeros_df.loc[i, temp_list[i]] = 1 # 显示所有列 pd.set_option('display.max_columns', None) # 显示所有列 # pd.set_option('display.max_columns', None) # #显示所有行 # pd.set_option('display.max_rows', None) # #设置value的显示长度为100,默认为50 # pd.set_option('max_colwidth',100) print(zeros_df.head(1)) # 统计每个分类的电影的数量和 genre_count = zeros_df.sum(axis=0) print(genre_count) # 排序 genre_count = genre_count.sort_values() # 画柱状图 _x = genre_count.index _y = genre_count.values plt.figure(figsize=(20, 8), dpi=80) plt.bar(range(len(_x)), _y) plt.xticks(range(len(_x)), _x) plt.show()
12.数据合并之join join:默认情况下他是把行索引相同的数据合并到一起
13.数据合并之merge merge:按照指定的列把数据按照一定的方式合并到一起
==示例:==
现在我们有一组关于全球星巴克店铺的统计数据,如果我想知道美国的星巴克数量和中国的哪个多,或者我想知道中国每个省份星巴克的数量的情况,那么应该怎么办?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 import numpy as np import pandas as pd df = pd.read_csv('starbucks_store_worldwide.csv') # print(df) # print(df.info()) # df_country = df.groupby('Country') # 生成一个DataFrameGroupBy object # print(df_country) # # 显示所有列 # pd.set_option('display.max_columns', None) # # 遍历 # # for i in df_country: # # print(i) # 遍历后的每一个数据都是一个元组 # # # 由于遍历后的每一个值都是元组,所以还可以这样遍历 # for i, j in df_country: # print(i, j, type(j)) # i为国家信息,j为一个DataFrame,其中所有的country字段均为i # print('*' * 100) # # # 调用聚合方法 # print(df_country.count()) # count()可以统计每个字段的总数 # print(df_country['City'].count()) # 单独统计一个字段的总数 # # """ 平均值,中位数等方法也可以使用,但这里使用没有意义,因为都是字符串 count:分组中非NA值的数量 sum:非NA的和 mean:非NA值的平均值 median:非NA值的算术中位数 std、var: 无偏(分母为n-a)标准差和方差 min,max:非NA值的最小值和最大值 """ # country_count = df_country['City'].count() # # 美国和中国的星巴克店铺数量 # print('美国:', country_count['US']) # print('中国:', country_count['CN']) # 统计中国每个省份的星巴克 china_data = df[df['Country'] == 'CN'] # 取出中国的星巴克数据,这里可以不需要分组,直接取数据 # print(china_data) # print(china_data.info()) # province_data = china_data.groupby('State/Province').count()['Brand'] # print(province_data) # groupby可以传入多个条件来分组 print(df['Brand']) china_data_group = df.groupby( by=[df['Country'], df['State/Province']]).count() # 返回一个Series,列索引有两个,一个是country,一个是State/Province print(china_data_group) print(china_data_group['Brand']) # 以下三种写法,结果相同 group1 = df.groupby(by=[df['Country'], df['State/Province']]).count()['Brand'] group2 = df['Brand'].groupby(by=[df['Country'], df['State/Province']]).count() group3 = df.groupby(by=[df['Country'], df['State/Province']])['Brand'].count() print(group1, type(group1)) print('*' * 100) print(group2, type(group2)) print('*' * 100) print(group3, type(group3)) # 取值可以为DataFrame,需要使用一个小技巧 group4 = df[['Brand']].groupby(by=[df['Country'], df['State/Province']]).count() print('*' * 100) print(group4, type(group4)) print(group1.index)
14.分组和聚合 grouped = df.groupby(by="columns_name")
grouped是一个DataFrameGroupBy对象,是可迭代的
grouped中的每一个元素是一个元组
元组里面是(索引(分组的值),分组之后的DataFrame)
DataFrameGroupBy对象有很多经过优化的方法
如果我们需要对国家和省份进行分组统计,应该怎么操作呢?
grouped = df.groupby(by=[df["Country"],df["State/Province"]])
很多时候我们只希望对获取分组之后的某一部分数据,或者说我们只希望对某几列数据进行分组,这个时候我们应该怎么办呢?
获取分组之后的某一部分数据:
df.groupby(by=["Country","State/Province"])["Country"].count()
对某几列数据进行分组:
df["Country"].groupby(by=[df["Country"],df["State/Province"]]).count()
观察结果,由于只选择了一列数据,所以结果是一个Series类型
如果我想返回一个DataFrame类型呢?
t1 = df[["Country"]].groupby(by=[df["Country"],df["State/Province"]]).count()
t2 = df.groupby(by=["Country","State/Province"])[["Country"]].count()
以上的两条命令结果一样
和之前的结果的区别在于当前返回的是一个DataFrame类型
简单的索引操作:
•获取index:df.index
•指定index :df.index = ['x','y']
•重新设置index : df.reindex(list("abcedf"))
•指定某一列作为index :df.set_index("Country",drop=False)
•返回index的唯一值:df.set_index("Country").index.unique()
15.Series复合索引
==示例==
现在我们有2015到2017年25万条911的紧急电话的数据,请统计出出这些数据中不同类型的紧急情况的次数,如果我们还想统计出不同月份不同类型紧急电话的次数的变化情况,应该怎么做呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import pandas as pd, numpy as np from matplotlib import pyplot as plt df = pd.read_csv('911.csv') # 显示所有列 pd.set_option('display.max_columns', None) # print(df.head()) # print(df.info()) # print(df['title'].str.split(':')) # print(df['title'].str.split(':')[0]) # 不能取到数据 # to_list()将序列转换为数组 temp_list = df['title'].str.split(':').to_list() # temp_list = df['title'].str.split(':').tolist() print(temp_list) # 遍历并取出第一项数据并去重 cate_list = list(set([i[0] for i in temp_list])) print(cate_list) # 构造一个DataFrame,三列,与df同行,数据全为0 zeros_df = pd.DataFrame(np.zeros((df.shape[0], len(cate_list))), columns=cate_list) print(zeros_df) # 由于df数据量太大,如果直接遍历,会消耗很长时间 # for i in range(df.shape[0]): # zeros_df.loc[i,temp_list[i][0]] = 1 # # print(zeros_df) # 遍历cate_list,只需要循环三次 for cate in cate_list: # df['title'].str.contains(cate)返回的是一个布尔型数组,行数与zeros_df相同,列数为三列, # 包含cate的那一列为True,具体可见5.62布尔索引章节 zeros_df[cate][df['title'].str.contains(cate)] = 1 # print(zeros_df) # 统计邮寄类型的数量 sum_ret = zeros_df.sum(axis=0) print(sum_ret)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import pandas as pd, numpy as np from matplotlib import pyplot as plt df = pd.read_csv('911.csv') # #显示所有行 pd.set_option('display.max_rows', None) print(df.head()) print(df.info()) # to_list()将序列转换为数组 temp_list = df['title'].str.split(':').to_list() # print(temp_list) # 遍历并取出第一项的分类 cate_list = [i[0] for i in temp_list] # print(cate_list) cate_df = pd.DataFrame(np.array(cate_list).reshape((df.shape[0]), 1), columns=['cate']) print(cate_df) # 添加一列,列索引为cate df['cate'] = cate_df # print(df['cate']) print(df.groupby(by='cate').count()['title'])
16.pandas中的时间序列 ==生成一段时间范围==
pd.date_range(start=None, end=None, periods=None, freq='D')
start和end以及freq配合能够生成start和end范围内以频率freq的一组时间索引
start和periods以及freq配合能够生成从start开始的频率为freq的periods个时间索引
==关于频率的更多缩写==
==在DataFrame中使用时间序列==
index=pd.date_range("20170101",periods=10)
df = pd.DataFrame(np.random.rand(10),index=index)
回到最开始的911数据的案例中,我们可以使用pandas提供的方法把时间字符串转化为时间序列
df["timeStamp"] = pd.to_datetime(df["timeStamp"],format="")
format参数大部分情况下可以不用写,但是对于pandas无法格式化的时间字符串,我们可以使用该参数,比如包含中文
那么问题来了:
我们现在要统计每个月或者每个季度的次数怎么办呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 from matplotlib import pyplot as plt import pandas as pd df = pd.read_csv('911.csv') #显示所有列 pd.set_option('display.max_columns', None) # #显示所有行 pd.set_option('display.max_rows', None) print(df.info()) print(df.head()) # 将时间字符串转换为时间类型数据datetime64,以便进一步处理 print(pd.to_datetime(df['timeStamp']).head()) # 重新赋值df['timeStamp'] df['timeStamp'] = pd.to_datetime(df['timeStamp']) # 将列timeStamp转换为行索引 df.set_index('timeStamp',inplace=True) print(df.head()) # 统计出911数据中不同月份电话次数 count_by_month = df.resample('M').count()['title'] print(count_by_month) _x = count_by_month.index _y = count_by_month.values print(_x) print(_y) _x = [i.strftime('%Y%m%d') for i in _x] plt.figure(figsize=(20,8), dpi=80) plt.plot(_x,_y) # plt.plot(range(len(_x)),_y) plt.xticks(_x,rotation=45) plt.show()
17.pandas重采样
==示例==
1.统计出911数据中不同月份电话次数的变化情况
2.统计出911数据中不同月份不同类型的电话的次数的变化情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 from matplotlib import pyplot as plt import pandas as pd,numpy as np df = pd.read_csv('911.csv') # 重新赋值df['timeStamp'] df['timeStamp'] = pd.to_datetime(df['timeStamp']) #添加列,表示分类 temp_list = df["title"].str.split(": ").tolist() cate_list = [i[0] for i in temp_list] # 创建列 df["cate"] = pd.DataFrame(np.array(cate_list).reshape((df.shape[0],1))) # 将时间列转化为索引 df.set_index("timeStamp",inplace=True) print(df.head(1)) dk = df.groupby('cate') print(dk) plt.figure(figsize=(20, 8), dpi=80) for group_name,group_data in dk: print(group_name,group_data) # 对不同的分类都进行绘图 count_by_month = group_data.resample("M").count()["title"] # 画图 _x = count_by_month.index print(_x) _y = count_by_month.values print(_y) _x = [i.strftime("%Y%m%d") for i in _x] plt.plot(range(len(_x)), _y, label=group_name) plt.xticks(range(len(_x)), _x, rotation=45) plt.legend(loc="best") plt.show()
现在我们有北上广、深圳、和沈阳5个城市空气质量数据,请绘制出5个城市的PM2.5随时间的变化情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 # coding=utf-8 import pandas as pd from matplotlib import pyplot as plt file_path = "./PM2.5/BeijingPM20100101_20151231.csv" df = pd.read_csv(file_path) print(df.head()) print(df.info()) # 把分开的时间字符串通过periodIndex的方法转化为pandas的时间类型 period = pd.PeriodIndex(year=df["year"], month=df["month"], day=df["day"], hour=df["hour"], freq="H") # 增加一列df["datetime"] df["datetime"] = period print(df.head(10)) # # 把datetime 设置为索引 df.set_index("datetime", inplace=True) # # 进行降采样,如果按日来排序,数据图不好看,按月份太稀疏,按日太绸 df = df.resample("7D").mean() print(df.head()) # 处理缺失数据,删除缺失数据 print(df["PM_US Post"]) # dropna()该函数主要用于滤除缺失数据。 # 如果是Series,则返回一个仅含非空数据和索引值的Series,默认丢弃含有缺失值的行。 # 美国数据 data = df["PM_US Post"].dropna() # 使用降采样后,会计算均值,这里再使用dropna()过滤空值意义不大 # 中国数据 data_china = df["PM_Nongzhanguan"] print(data_china.head(100)) #画图 _x = data.index _x = [i.strftime("%Y%m%d") for i in _x] # 取中国PM2.5数据 _x_china = [i.strftime("%Y%m%d") for i in data_china.index] print(len(_x_china),len(_x_china)) _y = data.values _y_china = data_china.values plt.figure(figsize=(20,8),dpi=80) plt.plot(range(len(_x)),_y,label="US_POST",alpha=0.7) plt.plot(range(len(_x_china)),_y_china,label="CN_POST",alpha=0.7) plt.xticks(range(0,len(_x_china),10),list(_x_china)[::10],rotation=45) plt.legend(loc="best") plt.show()