numpy能够帮助我们处理数值,但是pandas除了能处理数值之外(基于numpy),还能够帮助我们处理其他类型的数据
pandas技术文档:https://pandas.pydata.org/pandas-docs/stable/reference/index.html
pandas模块的基本使用
pandas常用的数据类型
pandas常用的数据类型有:
Series:一维,带标签的数组
DataFrame:二维,Series的容器
Series
创建Series
使用pandas.Series()
即可创建Series
import pandas as pd
# 不指定索引会自动生成,0、1、2、...
t1 = pd.Series([23, 34, 23, 54, 23])
print(type(t1)) # <class 'pandas.core.series.Series'>
# 指定索引,需要和数组的数量保持一致
t2 = pd.Series([23, 43, 23, 54, 3], index=list('abcde'))
# 使用字典创建Series,字典的键会作为索引/标签
temp_dict = {'name': 'lisi', 'age': 12, 'tel': 10086}
t3 = pd.Series(temp_dict)
# 通过dtype获取Series中数据的数据类型
print(t1.dtype) # int64
print(t2.dtype) # int64
print(t3.dtype) # object
# 和numpy一样,通过astype修改数据类型
t4 = t1.astype('float')
print(t4.dtype) # float64
Series的切片和索引
切片:直接传入start
、end
、step
即可
索引:一个的时候直接传入序号或者标签,多个的时候传入序号或者标签的列表
Series的索引和值
Series
对象本质上是由两个数组构成,一个数组构成对象的键(索引/标签),一个数组构成对象的值
ndarray(numpy)
上的很多方法都适用于Series
类型,如:argmax()
、clip()
等,但是Series
的where()
方法返回的结果却是不同的
DataFrame
创建DataFrame
import pandas as pd
import numpy as np
# 不指定索引会自动生成
t1 = pd.DataFrame(np.arange(12).reshape((3, 4)))
# 指定索引,index指定行索引,columns指定列索引
t2 = pd.DataFrame(np.arange(12).reshape((3, 4)), index=list('abc'), columns=list('WXYZ'))
# 使用字典创建DataFrame,字典的键会作为列索引
d1 = {'name': ['lisi', 'caocao'], 'age': [12, 23], 'tel': ['10086', '10010']}
t3 = pd.DataFrame(d1)
d2 = [{'name': 'lisi', 'age': 12, 'tel': '10000'}, {'name': 'caocao', 'age': 23}, {'name': 'lvbu', 'tel': '10086'}]
t4 = pd.DataFrame(d2) # 缺失的值会显示为NaN
DataFrame对象既有行索引,又有列索引
行索引,表明不同行,横向索引,叫index
,0轴,axis=0
列索引,表名不同列,纵向索引,叫columns
,1轴,axis=1
DataFrame的属性
import pandas as pd
temp_dict = [
{'name': 'caocao', 'age': 23, 'tel': '10086'},
{'name': 'liubei', 'tel': '10010'},
{'name': 'guanyu', 'age': 12}
]
t = pd.DataFrame(temp_dict)
print(t.shape) # 形状,行数和列数 -> (3, 3)
print(t.ndim) # 数据维度 -> 2
print(t.index) # 行索引 -> RangeIndex(start=0, stop=3, step=1)
print(t.columns) # 列索引 -> Index(['name', 'age', 'tel'], dtype='object')
print(t.values) # 值,是一个二维的ndarray数组
print(t.dtypes) # 每一列的数据类型
DataFrame方法
df.head(2)
:显示前几行,默认显示5行
df.tail(2)
:显示末尾几行,默认显示5行
df.info()
:相关信息概览:行数、列数、列索引、列非空值个数、行类型、列类型、内存占用
df.describe()
:快速综合统计结果:计数、均值、标准差、最大值、最小值、四分位数
df.sort_values()
:DataFrame的排序,by
设置排序的依据;ascending
设置排序的方式,默认是升序,False
表示降序
DataFrame取行或取列
-
通过切片和列索引获取
[]
写数字,表示取行,对行进行操作
[]
写列索引,表示通过通过列索引对列进行操作print(df[:20]) # 取前20行 print(df['Row_Labels']) # 取Row_Labels那一列 print(df[:20]['Row_Labels']) # 同时取行和列 print(df[10:100:5]['Row_Labels']) # 取10-100行,步长为5
-
DataFrame的loc属性
df.loc[]
:通过标签获取数据,每个维度之间用,
分隔,,
前面表示行,后面表示列import pandas as pd import numpy as np t = pd.DataFrame(np.arange(24).reshape((4, 6)), index=list('abcd'), columns=list('UVWXYZ')) # `,`前面表示行,后面表示列 print(t.loc["a","W"]) # 取a行W列相交的值 -> 2 print(t.loc['a']) # 取a那一行 print(t.loc['a', :]) # 同上,取a那一行,`:`可以省略 print(t.loc[:, 'W']) # 取W那一列,`:`不能省略 print(t.loc[['a', 'c'], ['W', 'Y']]) # 取间隔的多行多列 print(t.loc['a':'c', 'V':'X']) # 取连续的多行多列,其中`:`在loc()中是左右都闭合的 print(t.loc['a':'c', ['W', 'Z']])
注:
:
在df.loc[]
中左右都是闭合的,即左右两边也都能取到 -
DataFrame的iloc属性
df.iloc[]
:通过位置获取数据,每个维度之间用,
分隔,,
前面表示行,后面表示列。使用方法和df.loc[]
相同,不同的是需要将字符串索引换成数字索引print(t.iloc[0]) # 取第1行 print(t.iloc[1,3]) # 取2行4列相交的值 -> 9 print(t.iloc[1:3, [2, 3]]) print(t.iloc[[1, 3], [4, 2]]) print(t.iloc[:, [1, 3]])
DataFrame的布尔索引
DataFrame中的布尔索引可以写多个条件,每个条件用()
括起来,表示并且使用&
连接,表示或使用|
连接,示例如下:
# 获取count大于800的数据
df[df['count'] > 800]
# 获取count大于800,小于1000的数据
df[(df['count'] > 800) & (df['count'] < 1000)]
# 获取name长度大于5,或者count大于800的数据
df[(df['name'].str.len() > 5) | (df['count'] > 800)]
不能使用连续的比较,如下面的使用就是错误的:
df[800 < df['count'] < 1000] # 错误使用
pandas读取数据
读取CSV文件
pandas本身提供了读取CSV文件的方法read_csv()
import pandas as pd
# 读取CSV文件
df = pd.read_csv('aaaa.csv')
除此之外还提供了其他文件的读取方法,如:pd.read_excel()
、
pd.read_json()
、
pd.read_html()
、
pd.read_sql()
、
pd.read_sql_query()
、
pd.read_sql_table()
、
pd.read_clipboard()
等
读取MongoDB数据库
from pymongo import MongoClient
import pandas as pd
client = MongoClient() # 创建客户端
collection = client['db_name']['collection_name'] # 选择数据库和集合
mongo_data = collection.find() # 获取所有数据
# 使用Series读取一条数据
t = pd.Series(mongo_data[0]) # 读取第一条数据
# 使用DataFrame读取多条数据
t2 = pd.DataFrame(mongo_data) # 读取全部数据
pandas中的字符串处理方法
语法:df.str.function()
或 series.str.function()
方法会作用到每一行或每一列上的每个数据上
常用的处理方法如下:
pandas中缺失数据的处理
判断是否为NaN
pd.isna(df)
、pd.isnull(df)
:为NaN
的位置返回True
,其他返回False
pd.notna(df)
、pd.notnull(df)
:不为NaN
的位置返回True
,其他返回False
删除NaN所在的行或列
语法:df.dropna(axis=0, how='any', inplace=False)
1> axis
表示删除行还是删除列,值有0
或'index'
,1
或'columns'
,默认为0
2> how
表示删除的方式,默认为'any'
表示只要行或列中存在NaN
就删除该行或列;'all'
表示只有行或列中全部为NaN
时才删除该行或列
3> inplace
表示是否在原数据上进行修改,默认为False
表示不在原数据上进行修改,而会返回一个修改后的新数据,原数据不变;True
表示在原数据上修改,不返回任何内容
注:在不方便删除NaN
的时候也可以通过布尔索引等方式筛选出不含NaN
的数据
填充数据
df.fillna(df.mean())
:使用均值进行填充
df.fillna(df.median())
:使用中位数进行填充
df.fillna(0)
:使用0
进行填充
df['W'] = df['W'].fillna(df['W'].mean())
:只填充特定列
处理为0
的数据:t[t == 0] = np.nan
当然并不是每次为0
的数据都需要处理,这个要视情况而定
注:在pandas中计算均值等情况时,NaN
是不会参与计算的,但是0
会参与计算,所以将0
替换为NaN
之后,得到的计算结果会更准确,同时也更方便后续的数据处理
数组合并
join()方法合并数据
df1.join(df2)
:默认情况下把行索引相同的数据合并到一起,以df1
为基准
import pandas as pd
import numpy as np
df1 = pd.DataFrame(np.zeros((2, 4)), index=['A', 'B'], columns=list('abcd'))
df2 = pd.DataFrame(np.ones((3, 3)), index=['A', 'B', 'C'], columns=list('xyz'))
df3 = df1.join(df2) # 以df1为基准,结果只有两行
df4 = df2.join(df1) # 以外df2为基准,结果为三行,不够的用NaN补齐
merge()方法合并数据
通过列索引进行合并
pandas的分组和聚合
分组
语法:df.groupby(by="columns_name")
groupby()
方法的返回值是一个DataFrameGroupBy
对象,这个对象是可迭代的,其中的每个元素都是一个元组,元组的构成是(分组的依据, 分组依据对应的DataFrame)
;同时DataFrameGroupBy
对象也可以调用聚合方法
- 使用多个条件进行分组
- 先分组再取列,或者只分组不对列进行操作时,分组条件写在
by
参数后的列表中即可,也可以使用df[]
的方式设置分组条件,示例如下:# 一个条件 grouped_df1 = df.groupby(by='Country') grouped_df2 = df.groupby(by=df['Country']) # 多个条件 grouped_df3 = df.groupby(by=['Country', 'State/Province']) grouped_df4 = df.groupby(by=[df['Country'], df['State/Province']])
- 先取列再分组时,无论是否是使用多个条件分组,分组时都需要在
by
参数中使用df[]
的方式设置分组条件,示例如下:# 一个条件 grouped_df1 = df['Brand'].groupby(by=df['Country']) # 多个条件 grouped_df2 = df['Brand'].groupby(by=[df['Country'], df['State/Province']])
- 先分组再取列,或者只分组不对列进行操作时,分组条件写在
聚合
常用的聚合方法:
示例如下:
grouped_count_df1 = df.groupby(by='Country').count()
grouped_count_df2 = df.groupby(by='Country')['Brand'].count()
下面三行代码得到的结果相同,同时也都是采用获取多列的方式(两层[]
)获取的列,所以类型也都是<class 'pandas.core.series.Series'>
:
grouped_count_df3 = df[['Brand']].groupby(by=df['Country']).count()
grouped_count_df4 = df.groupby(by=df['Country'])[['Brand']].count()
grouped_count_df5 = df.groupby(by=df['Country']).count()[['Brand']]
索引和复合索引
简单的索引操作
1> df.index
:获取索引
2> df.index = ['a', 'b', 'c']
:指定新的索引
3> df.reindex(list('abmn'))
:重新设置索引,返回一个新的DataFrame
,
设置的索引和原索引相同的部分,则使用原DataFrame
的数据;
设置的索引和原索引不同的部分,则用NaN
补齐不足的数据
4> df.set_index('W')
:将某一列作为索引,返回一个新的DataFrame
,
默认会删除作为索引的列,可设置drop=False
保留该列,如:df.set_index('W', drop=False)
5> df.index.unique()
:获取index
的唯一值,去除重复的indx
6> len(df.index)
:获取index
的长度
7> list(df.index)
:将index
转换成列表
复合索引
对于复合索引,可以使用swaplevel()
方法交换索引的位置
-
Series的复合索引取值
通过Series
的复合索引取值,直接在[]
写索引就可以了import pandas as pd df = pd.DataFrame({'a': range(7),'b': range(7, 0, -1),'c': ['one','one','one','two','two','two', 'two'],'d': list("hjklmno")}) s1 = df.set_index(['c', 'd'])['a'] # 拥有复合索引的Series # 取值 print(s1['one', 'k']) # 2 print(s1['one']['k']) # 2 # 通过一个索引取值只能写前面的索引 # print(s1['k']) # 报错 print(s1['one']) # 正常运行 # 想要通过后面的索引取值,可以使用swaplevel()方法交换索引的位置 s2 = s1.swaplevel() print(s2['k']) # 交换索引位置后正常运行
-
DataFrame的复合索引取值
通过DataFrame
的复合索引取值需要使用df.loc[]
属性import pandas as pd df = pd.DataFrame({'a': range(7),'b': range(7, 0, -1),'c': ['one','one','one','two','two','two', 'two'],'d': list("hjklmno")}) df1 = df.set_index(['c', 'd']) # 取值 print(df1.loc['one']) print(df1.loc['one'].loc['j']) print(df1.loc['one'].loc['j']['b']) # 6 print(df1.loc['one'].loc['j'].loc['b']) # 6 # 同样可以使用swaplevel()方法交换索引的位置 df2 = df1.swaplevel() print(df2.loc['j'])
pandas的时间序列
时间序列
-
生成一段时间范围
语法:pd.date_range(start=None, end=None, periods=None, freq='D')
start
参数表示开始日期
end
参数表示结束日期
periods
参数表示生成的个数,periods
和end
同时只用一个,否则报错
freq
参数表示时间的频率间隔,天、月、小时等,可选内容如下:
-
将字符串转化为时间序列
语法:pd.to_datetime(df["timeStamp"], format="")
format
参数表示采用何种方式对字符串进行格式化,很少使用,一般只有在字符串不规范,无法被识别时才进行设置 -
将多个字段组合成时间序列
可以使用pd.PeriodIndex()
方法将多个字段的内容组合成一个时间序列# 把分开的多个字段组合成一个时间序列,并添加到df中 period = pd.PeriodIndex(year=df['year'], month=df['month'], day=df['day'], hour=df['hour'], freq='H') df['datetime'] = period # 把datetime设置为df的索引 df.set_index('datetime', inplace=True)
pandas重采样
重采样:指的是将时间序列从一个频率转化为另一个频率进行处理的过程,将高频率数据转化为低频率数据为降采样,低频率转化为高频率为升采样
pandas提供了一个df.resample()
方法来实现频率转化,示例如下: