pandas常用操作

文章目录

  • 安装包镜像地址
    • 豆瓣镜像
    • 清华镜像
  • 获取数据
    • table、mysql、csv
    • to_excel/to_csv
    • 选取数据
    • 修改列名
    • 序号编码
    • One_Hot编码
    • df.query方法
    • 新增数据列
  • 数据处理类
    • pandas按区间进行切分数据
    • 分列
    • 汇总类统计
    • 唯一去重和按值计数
    • 重复值
    • 缺失值
    • 数据排序
  • 字符串操作
    • Pandas的字符串处理:
    • 格式化字符串操作:按照统一的规则输出字符串
  • pandas对axis和index的理解
    • pandas的axis参数的理解
    • pandas的索引index用途
  • 实现DataFrame的merge,concat
    • merge
    • concat语法
    • append语法
  • group by 语法
  • 多层索引 和reset_index,set_index(),stack,unstack
    • 多层索引(MultiIndex)
    • reset_index()
    • set_index()
    • unstack()和stack()
  • 数据透视表(pivot_table)
  • apply,applymap,map,以及apply应用在groupby上
    • map
    • apply
    • applymap
    • 对分组groupby后的数据使用apply
  • 时间函数
  • Matplotlib

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn.datasets import load_boston
import seaborn as sns
plt.rcParams['font.sans-serif'] = ['SimHei'] # 替换sans-serif字体
plt.rcParams['axes.unicode_minus'] = False  # 解决坐标轴负数的负号显示问题

#刻度的大小
plt.rcParams['axes.labelsize'] = 16

#线的粗细
plt.rcParams['lines.linewidth'] = 2

#x轴的大小
plt.rcParams['xtick.labelsize'] = 14
#y轴的大小
plt.rcParams['ytick.labelsize'] = 14

#图例大小
plt.rcParams['legend.fontsize'] = 14

#图的大小
plt.rcParams['figure.figsize'] = [12,8]

安装包镜像地址

豆瓣镜像

pip install -i https://pypi.douban.com/simple xlrd

清华镜像

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple xlrd

获取数据

table、mysql、csv

#read_table函数
#功能:从文件、URL、文件型对象中加载带分隔符的数据,默认分隔符为制表符("\t")。
#data.txt的内容还是不变,我们可以通过指定read_table的sep参数来修改默认的分隔符。
data = pd.read_table("data.txt",sep=",")
# read_excel函数
data1=pd.read_excel(r'C:\Users\admin\Desktop\satisfaction.xlsx')
data1=pd.read_excel(r'C:\Users\admin\Desktop\satisfaction.xlsx',sheet_name='Sheet1')
# 列表:指定多个需要读取的Sheet,列表的元素可以使索引,也可以是字符串,
# 例如[0, 1, 'Sheet3']表示读取第一张、第二张和名为Sheet3的3张Sheet,返回的数据是以列表元素为键包含数据的DataFrame对象为值的字典。
data = pd.read_excel('data.xlsx', sheet_name=[0, 1, 'Sheet3'])
# pip install -i https://pypi.douban.com/simple pymysql
import pandas as pd
import pymysql
 
conn = pymysql.connect(host="localhost",user='chb', password='123456', db="test",charset="utf8")
sql = 'select * from student'
df = pd.read_sql(sql, conn)
print(df)
conn.close()
# read_csv函数
#功能:从文件、URL、文件新对象中加载带有分隔符的数据,默认分隔符是逗号。
#encoding :编码,字符型,通常为'utf-8',如果中文读取不正常,可以将encoding设为’gbk‘。
# 读取csv文件
#默认将第一行作为标题
data = pd.read_csv("data.txt",encoding='gbk')
#设置header参数,读取文件的时候没有标题
data1 = pd.read_csv("data.txt",header=None)
#设置names参数,来设置文件的标题
data2 = pd.read_csv("data.txt",names=["a","b","c","d","name"])
#设置names参数,来设置文件的标题,设置index_col参数来设置列索引
data2 = pd.read_csv("data.txt",names=["a","b","c","d","name"],index_col="name")
df = pd.read_csv(
    "./datas/movielens-1m/ratings.dat", 
    sep="::",
    engine='python', 
    names="UserID::MovieID::Rating::Timestamp".split("::")
)
df.head(1)

to_excel/to_csv

选取数据

python数据分析之pandas数据选取:df[] df.loc[] df.iloc[] df.ix[] df.at[] df.iat[]
  在Dataframe中选取数据大抵包括3中情况:

1)行(列)选取(单维度选取):df[]。这种情况一次只能选取行或者列,即一次选取中,只能为行或者列设置筛选条件(只能为一个维度设置筛选条件)。

2)区域选取(多维选取):df.loc[],df.iloc[],df.ix[]。这种方式可以同时为多个维度设置筛选条件。

3)单元格选取(点选取):df.at[],df.iat[]。准确定位一个单元格。

data = {
     'name': ['Joe', 'Mike', 'Jack', 'Rose', 'David', 'Marry', 'Wansi', 'Sidy', 'Jason', 'Even'],

        'age': [25, 32, 18, np.nan, 15, 20, 41, np.nan, 37, 32],

        'gender': [1, 0, 1, 1, 0, 1, 0, 0, 1, 0],

        'isMarried': ['yes', 'yes', 'no', 'yes', 'no', 'no', 'no', 'yes', 'no', 'no']}
labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
df = pd.DataFrame(data, index=labels)

选取行\

选取行的方式包括三种:整数索引切片、标签索引切片和布尔数组。

df[0:2]
name age gender isMarried
a Joe 25.0 1 yes
b Mike 32.0 0 yes
df[df['age']>30]
name age gender isMarried
b Mike 32.0 0 yes
g Wansi 41.0 0 no
i Jason 37.0 1 no
j Even 32.0 0 no
df[(df['age']>30) & (df['isMarried']=='no')]
name age gender isMarried
g Wansi 41.0 0 no
i Jason 37.0 1 no
j Even 32.0 0 no
df[(df['age']==20) |(df['age']==32)]
name age gender isMarried
b Mike 32.0 0 yes
f Marry 20.0 1 no
j Even 32.0 0 no

注意:像上面这种通过多个布尔条件判断的情况,多个条件最好(一定)用括号括起来,否则非常容易出错。

列选取\

列选取方式也有三种:标签索引、标签列表、Callable对象

df[['name','age']]
name age
a Joe 25.0
b Mike 32.0
c Jack 18.0
d Rose NaN
e David 15.0
f Marry 20.0
g Wansi 41.0
h Sidy NaN
i Jason 37.0
j Even 32.0
df[lambda df:df.columns[0]]
a      Joe
b     Mike
c     Jack
d     Rose
e    David
f    Marry
g    Wansi
h     Sidy
i    Jason
j     Even
Name: name, dtype: object
df.loc[df['age']>30,['name','age']]
name age
b Mike 32.0
g Wansi 41.0
i Jason 37.0
j Even 32.0
df.loc[(df['name']=='Mike') |(df['name']=='Marry'),['name','age']]
name age
b Mike 32.0
f Marry 20.0
#选取第2行的第1列、第3列、第4列
df.iloc[1, [0,2,3]]
name         Mike
gender          0
isMarried     yes
Name: b, dtype: object
#直接写lambda表达式
df.loc[lambda df : (df['age']<=30) & (df['gender']==1), :].head(1)
name age gender isMarried
a Joe 25.0 1 yes
# 编写自己的函数
#def 函数名(参数列表):
#    函数体
    

修改列名

Pandas中DateFrame修改列名
将a表A、B、C列名更改为a,b,c
1、暴力方法 但是缺点是必须写三个,要不报错
a.columns = [‘a’,‘b’,‘c’]
2、a.rename(columns={‘A’:‘a’, ‘B’:‘b’, ‘C’:‘c’}, inplace = True),可随意更改个数
如:a.rename(columns={‘A’:‘a’, ‘C’:‘c’}, inplace = True)\

data.rename(columns={
     
    'Class': '舱位',
    'Gender': '性别',
    'Customer Type': '客户类型',
    'Type of Travel': '出行类型',
    'Age': '年龄',
    'Flight Distance': '飞行距离',
    'Seat comfort': '座椅舒适度',
    'Departure/Arrival time convenient': 'OD时间便捷程度',
    'Food and drink': '餐饮',
    'Gate location': '登机门位置',
    'Inflight wifi service': '机上WiFi服务',
    'Inflight entertainment': '机上娱乐',
    'On-board service': '机上服务',
    'Ease of Online booking': '轻松在线预订',
    'Online support': '网络支持',
    'Leg room service': '腿部客房服务',
    'Baggage handling': '行李搬运',
    'Checkin service': '登机服务',
    'Cleanliness': '清洁度',
    'Online boarding': '在线登机',
    'Departure Delay in Minutes': '出发延迟分钟',
    'Arrival Delay in Minutes': '到达延迟分钟',
    'satisfaction_v2': '满意度'
},
            inplace=True)

序号编码

1、使用replace实现:y_label = y_label[‘gender’].replace([‘male’, ‘female’], [1.0, 0.0])
2、使用map实现:
gender = {‘male’: 1.0, ‘female’: 0.0}
x_data[‘gender’] = x_data[‘gender’].map(gender)\

One_Hot编码

1、pandas 实现
将数据读入到 pandas 中,使用 get_dummies 方法即可。不过有时候转换后会出现数值错误,保险起见可将元素类型转换为 float
x_data = pd.get_dummies(x_data).astype(‘float’)
2、sklearn 实现
将数据读入到 pandas 中,使用 sklearn.preprocessing 中的 OneHotEncoder() 即可.
from sklearn import preprocessing as pp\

ohe = pp.OneHotEncoder()
gender = x_data[‘video_type’].values.reshape((-1, 1))
gender = ohe.fit_transform(gender).toarray()\

df.query方法

方式1:使用df[(df[‘a’]>3)&(df[‘b’]<5)]
方式2:使用 df.query(“a”>3 & “b”<5)
性能对比:
当数据量小时,使用方式1更快
当数据量大时,因为方法2直接使用C语言实现,节省方法1的临时多组的多次复制,方法2更快
data[(data[‘送达时长’]0)|(data[‘顾客配送评分’]1)]
等价于data.query('送达时长
0’ or '顾客配送评分
1’)

新增数据列

# 注意,df["bWendu"]其实是一个Series,后面的减法返回的是Series
df.loc[:, "wencha"] = df["bWendu"] - df["yWendu"]
def get_wendu_type(x):
    if x["bWendu"] > 33:
        return '高温'
    if x["yWendu"] < -10:
        return '低温'
    return '常温'

# 注意需要设置axis==1,这是series的index是columns
df.loc[:, "wendu_type"] = df.apply(get_wendu_type, axis=1)
# 可以同时添加多个新的列
df.assign(
    yWendu_huashi = lambda x : x["yWendu"] * 9 / 5 + 32,
    # 摄氏度转华氏度
    bWendu_huashi = lambda x : x["bWendu"] * 9 / 5 + 32).head(1)
# 先创建空列(这是第一种创建新列的方法)
df['wencha_type'] = ''
df.loc[df["bWendu"]-df["yWendu"]>10, "wencha_type"] = "温差大"
df.loc[df["bWendu"]-df["yWendu"]<=10, "wencha_type"] = "温差正常"
df["wencha_type"].value_counts()

数据处理类

pandas按区间进行切分数据

#设置切分区域
listBins = [0, 10, 20, 30, 40, 50, 60, 1000000]
 
#设置切分后对应标签
listLabels = ['0_10','11_20','21_30','31_40','41_50','51_60','61及以上']
 
#利用pd.cut进行数据离散化切分
"""
pandas.cut(x,bins,right=True,labels=None,retbins=False,precision=3,include_lowest=False)
x:需要切分的数据
bins:切分区域
right : 是否包含右端点默认True,包含
labels:对应标签,用标记来代替返回的bins,若不在该序列中,则返回NaN
retbins:是否返回间距bins
precision:精度
include_lowest:是否包含左端点,默认False,不包含
"""
df['fenzu'] = pd.cut(df['data'], bins=listBins, labels=listLabels, include_lowest=True)

分列

rsplit和split()的用法类似,一个从右边开始,一个从左边开始。
如果直接用某一列和split()来分列是不行的,因为Series数据类型是没有split()的,所以需要先用.str将这一列转换为类似字符串的格式,就能够使用split()了。\

str.split()有三个参数:第一个参数就是引号里的内容:就是分列的依据,可以是空格,符号,字符串等等。
第二个参数就是前面用到的expand=True,这个参数直接将分列后的结果转换成DataFrame。\

第三个参数的n=数字就是限制分列的次数。就是当用于分列的依据符号在有多个的话需要指定分列的次数(不指定的话就会根据符号有几个分列几次)。

data1=pd.merge(data,(data['顾客配送评价标签'].str.split('|',expand=True,n=3)),how='left',left_index=True,right_index=True)
data['顾客配送评价标签1']=data['顾客配送评价标签'].map(lambda x:x.split('|')[0])
data['顾客配送评价标签2']=data['顾客配送评价标签'].map(lambda x:x.split('|')[1])
data['顾客配送评价标签3']=data['顾客配送评价标签'].map(lambda x:x.split('|')[2])
#该解法要求列里的分隔符数量一致

汇总类统计

# 一下子提取所有数字列统计结果
df.describe()
# 对非数字列数据进行描述统计(并添加每个数据列缺失的比例)
df.select_dtypes(include=['O']).describe().T\
                .assign(missing_pct=df.apply(lambda x:(len(x)-x.count())/len(x)))

唯一去重和按值计数

# 唯一值去重 (一般不用于数值类型,而是枚举、分类型)
df["fengxiang"].unique()
pd.value_counts(
    values,
    sort=True,        #是否排序,默认是要排序
    ascending=False,     #默认降序排列
    normalize=False,     #标准化、转化成百分比形式
    bins=None,    #可以自定义分组区间,默认是没有,但也可以自定义区间
    dropna=True,   #是否删除nan,默认删除
)
常规用法:
pd.value_counts()
df.value_counts()
df['字段'].value_counts()
pandas 计数函数value_counts()
# 唯一值去重后得到的个数
df["fengxiang"].nunique()
# 去除重复值
#DataFrame.drop_duplicates(subset=None, keep='first', inplace=False)
df.drop_duplicates(subset=['tianqi','fengxiang'],keep='first',inplace=False).head(1)

重复值

drop_duplicates参数说明:
参数subset
subset用来指定特定的列,默认所有列
参数keep
keep可以为first和last,表示是选择最前一项还是最后一项保留,默认first
参数inplace
inplace是直接在原来数据上修改还是保留一个副本,默认为False
示例:
df.drop_duplicates(subset = [‘ID’,‘Name’],keep=‘last’,inplace=True)\

缺失值

数据源质量比较高,缺失值不到1%,直接删除缺失值即可。
1.删除所有缺失值所在行:data=data.dropna()
2.指定删除某列的缺失值所在行:data.dropna(subset=[‘age’]
3.删除缺失值所在的列:data=data.dropna(axis=1)
如果缺失的比较多,可以使用均值或众数等填充:data[‘age’]=data[‘age’].fillna(data[‘age’].mean())
也可使用插值函数来填写数字的缺失值。比如取数据框中缺失值上下的数字平均值,data[‘age’]=data[‘age’].fillna(data[‘age’].interpolate())
或者data.fillna(axis=1,method=‘ffill’)来横向(axis=1)/纵向(axis=0)用缺失值前面的值替换缺失值\

处理非标准缺失值,比如age列本应该是数字,但是却出现两个并不是数字也不是nan的异常值
可以通过使用replace函数先将其转换为NaN来处理此问题,然后根据需要,使用上面的方法处理缺失值。
data=data.replace([‘N岁’,’-’],np.nan)
对缺失值的处理
Pandas使用这些函数处理缺失值:
isnull和notnull:检测是否是空值,可用于df和series
dropna:丢弃、删除缺失值
axis : 删除行还是列,{0 or ‘index’, 1 or ‘columns’}, default 0
how : 如果等于any则任何值为空都删除,如果等于all则所有值都为空才删除
inplace : 如果为True则修改当前df,否则返回新的df
fillna:填充空值
value:用于填充的值,可以是单个值,或者字典(key是列名,value是值)
method : 等于ffill使用前一个不为空的值填充forword fill;等于bfill使用后一个不为空的值填充backword fill
axis : 按行还是列填充,{0 or ‘index’, 1 or ‘columns’}
inplace : 如果为True则修改当前df,否则返回新的df

# 缺失值处理
df.isnull().sum()
# 或者data.info()
name         0
age          2
gender       0
isMarried    0
dtype: int64

1、np.isnan() 只有数组数值运算时可使用
注意:numpy模块的isnan方法仅支持对数值进行判断,因此传入的如果时字符串类型会报错。
如:筛选出客户满意度不为空的数据
df = data[np.isnan(data[‘qingjie’])==False] 可以正常运行,因为清洁列是数值型。
np.isnan(data[‘f_alarm_name’]) 就会报错,因为预警名称是字符串类型。
对于字符串类型的数据可以使用df = data[pd.isnull(data[‘f_alarm_name’])==False] 筛选
isnull () 主要判断字符型是不是有值,严格来说 isnull () 可以判断所有的空值,
但是python的数值字段比如int float 为空的时候默认是Nan,取不为空的数据:df[df.qingjie.notnull()]。
2、2、pd.iana()和pd.isnull() 功能一摸一样。
简单说呢就是:
numpy里边查找NaN值的话,就用np.isnan()。
pandas里边查找NaN值的话,要么.isna(),要么.isnull()

数据排序

Series的排序:
Series.sort_values(ascending=True, inplace=False)
参数说明:\

ascending:默认为True升序排序,为False降序排序
inplace:是否修改原始Series
DataFrame的排序:
DataFrame.sort_values(by, ascending=True, inplace=False)
参数说明:\

by:字符串或者List<字符串>,单列排序或者多列排序
ascending:bool或者List,升序还是降序,如果是list对应by的多列
inplace:是否修改原始DataFrame

# 分别指定升序和降序
df.sort_values(by=["aqiLevel", "bWendu"], ascending=[True, False]).head(1)

字符串操作

https://blog.csdn.net/qq_40678222/article/details/83032178
\

Pandas的字符串处理:

使用方法:先获取Series的str属性,然后在属性上调用函数;
只能在字符串列上使用,不能数字列上使用;
Dataframe上没有str属性和处理方法
Series.str并不是Python原生字符串,而是自己的一套方法,不过大部分和原生str很相似;

# 字符串替换函数
df["bWendu"].str.replace("℃", "").head(1)
# 判断是不是数字
df["bWendu"].str.isnumeric().head(1)
#使用str的startswith、contains等得到bool的Series可以做条件查询
df[df['ymd'].str.startswith('2018-03')].head(1)
#需要多次str处理的链式操作
#怎样提取201803这样的数字月份?
#df["ymd"].str.replace("-", "").str.slice(0, 6)
# slice就是切片语法,可以直接用
df["ymd"].str.replace("-", "").str[0:6]

格式化字符串操作:按照统一的规则输出字符串

(1) format方法: 相对基本格式化输出采用‘%’的方法,format()功能更强大, 该函数把字符串当成一个模板,通过传入的参数进行格式化,并且使用大括号‘{}’作为特殊字符代替‘%’\

位置参数:"{} love {} “.format(‘wo’,‘ni’) :'wo love ni ’
关键字参数:”{a} love {b} “.format(b=‘wo’,a=‘ni’) : ‘ni love wo ’
两者混用时,未知参数一定写在关键字参数之前:
特殊:’{:.1f}{}’.format(20.56,‘GB’) :‘20.6GB’ (“:”冒号是格式化符号的开始,”.1"表示保留一位小数,"f"定点数) (2)%方法:字符串格式化符号含义\ https://www.cnblogs.com/qinchao0317/p/10699717.html

pandas对axis和index的理解

pandas的axis参数的理解

axis=0或者"index":
如果是单行操作,就指的是某一行
如果是聚合操作,指的是跨行cross rows
axis=1或者"columns":
如果是单列操作,就指的是某一列
如果是聚合操作,指的是跨列cross columns
按哪个axis,就是这个axis要动起来(类似被for遍历),其它的axis保持不动

pandas的索引index用途

index的用途总结:\

更方便的数据查询;
使用index可以获得性能提升;
自动的数据对齐功能;
更多更强大的数据结构支持;
如果index是唯一的,Pandas会使用哈希表优化,查询性能为O(1);
如果index不是唯一的,但是有序,Pandas会使用二分查找算法,查询性能为O(logN);
如果index是完全随机的,那么每次查询都要扫描全表,查询性能为O(N);

实现DataFrame的merge,concat

https://blog.csdn.net/weixin_42782150/article/details/89546357

merge

Pandas的Merge,相当于Sql的Join,将不同的表按key关联到一个表\

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’), copy=True, indicator=False, validate=None)\

left,right:要merge的dataframe或者有name的Series
how:join类型,‘left’, ‘right’, ‘outer’, ‘inner’
on:join的key,left和right都需要有这个key
left_on:左侧DataFrame中用于连接键的列名,这个参数在左右列名不同但代表的含义相同时非常有用
right_on:right的df或者seires的key
left_index,right_index:使用左/右侧DataFrame中的行索引作为连接键( 但是这种情况下最好用JOIN)。除了指定字段作为主键以外,还可以考虑用索引作为拼接的主键,leftindex和rightindex默认为False,就是不以索引作为主键,调整为True就可以了
suffixes:两个元素的后缀,如果列有重名,自动添加后缀,默认是(’_x’, ‘_y’)
copy:默认为True,总是将数据复制到数据结构中,设置为False可以提高性能
理解merge时数量的对齐关系 以下关系要正确理解:

one-to-one:一对一关系,关联的key都是唯一的
比如(学号,姓名) merge (学号,年龄)
结果条数为:11
one-to-many:一对多关系,左边唯一key,右边不唯一key
比如(学号,姓名) merge (学号,[语文成绩、数学成绩、英语成绩])
结果条数为:1
N
many-to-many:多对多关系,左边右边都不是唯一的
比如(学号,[语文成绩、数学成绩、英语成绩]) merge (学号,[篮球、足球、乒乓球])
结果条数为:M*N

# a. 两张表df1和df2的列名有重叠,且重叠列的内容完全相同,直接用pd.merge(df1, df2)
#样集1
df1=pd.DataFrame(np.arange(12).reshape(3,4),columns=['a','b','c','d'])
#样集2
df2=pd.DataFrame({
     'b':[1,5],'d':[3,7],'a':[0,4]})
#两张表df1和df2的列名有重叠,且重叠列的内容完全相同,直接用pd.merge(df1, df2)
pd.merge(df1,df2)
a b c d
0 0 1 2 3
1 4 5 6 7
#b. 两张表df1和df2的列名有重叠,但重叠列的内容完全不同,须使用pd.merge(df1, df2, left_index=True, right_index=True, how='left')
#(备注: 如果直接用pd.merge(df1, df2),将会得到一张空表,故必须指定行索引参数left_index, right_index,)
#样集1
df1=pd.DataFrame(np.arange(12).reshape(3,4),columns=['a','b','c','d'])
#样集2
df2=pd.DataFrame({
     'b':[15,6],'d':[1,11],'a':[0,6]}) 
#b.	两张表df1和df2的列名有重叠,但重叠列的内容完全不同
pd.merge(df1, df2, left_index=True, right_index=True, how='left')
a_x b_x c d_x b_y d_y a_y
0 0 1 2 3 15.0 1.0 0.0
1 4 5 6 7 6.0 11.0 6.0
2 8 9 10 11 NaN NaN NaN

concat语法

使用场景: 批量合并相同格式的Excel、给DataFrame添加行、给DataFrame添加列\

一句话说明concat语法:
使用某种合并方式(inner/outer) 沿着某个轴向(axis=0/1) 把多个Pandas对象(DataFrame/Series)合并成一个。\

语法格式 pandas.concat(objs, axis=0, join=‘outer’, join_axes=None, ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, sort=None, copy=True)\

参数说明\

objs:series,dataframe或者是panel对象构成的序列lsit
axis:指明连接的轴向, {0/’index’(行), 1/’columns’(列)},默认为0
join:指明连接方式 , {‘inner’(交集), ‘outer(并集)’},默认为outer
join_axes:自定义的索引。指明用其他n-1条轴的索引进行拼接, 而非默认join =’ inner’或’outer’方式拼接
keys:创建层次化索引。可以是任意值的列表或数组、元组数组、数组列表(如果将levels设置成多级数组的话)
ignore_index=True:重建索引

append语法

append只有按行合并,没有按列合并,相当于concat按行的简写形式\

other:单个dataframe、series、dict,或者列表
ignore_index:是否忽略掉原来的数据索引

df1 = pd.DataFrame({
     'A': ['A0', 'A1', 'A2', 'A3'],
                    'B': ['B0', 'B1', 'B2', 'B3'],
                    'C': ['C0', 'C1', 'C2', 'C3'],
                    'D': ['D0', 'D1', 'D2', 'D3'],
                    'E': ['E0', 'E1', 'E2', 'E3']
                   })
df2 = pd.DataFrame({
      'A': ['A4', 'A5', 'A6', 'A7'],
                     'B': ['B4', 'B5', 'B6', 'B7'],
                     'C': ['C4', 'C5', 'C6', 'C7'],
                     'D': ['D4', 'D5', 'D6', 'D7'],
                     'F': ['F4', 'F5', 'F6', 'F7']
                   })
# 使用ignore_index=True可以忽略原来的索引
pd.concat([df1,df2], ignore_index=True)
A B C D E F
0 A0 B0 C0 D0 E0 NaN
1 A1 B1 C1 D1 E1 NaN
2 A2 B2 C2 D2 E2 NaN
3 A3 B3 C3 D3 E3 NaN
4 A4 B4 C4 D4 NaN F4
5 A5 B5 C5 D5 NaN F5
6 A6 B6 C6 D6 NaN F6
7 A7 B7 C7 D7 NaN F7
# 使用join=inner过滤掉不匹配的列
pd.concat([df1,df2], ignore_index=True, join="inner")
A B C D
0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
3 A3 B3 C3 D3
4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7
# 使用axis=1相当于添加新列
s1 = pd.Series(list(range(4)), name="F")
pd.concat([df1,s1], axis=1)
A B C D E F
0 A0 B0 C0 D0 E0 0
1 A1 B1 C1 D1 E1 1
2 A2 B2 C2 D2 E2 2
3 A3 B3 C3 D3 E3 3
# 使用DataFrame.append按行合并数据
df1 = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB'))
df2 = pd.DataFrame([[5, 6], [7, 8]], columns=list('AB'))
#忽略原来的索引ignore_index=True
df1.append(df2, ignore_index=True)
A B
0 1 2
1 3 4
2 5 6
3 7 8

group by 语法

1.基本语法
(1):df.groupby(‘以什么分组’)[‘以哪一些聚合’].sum( )
注意:如果是经过筛选的后的df,那么聚合列也应该是筛选后的
(2)于是否选择分组列作为索引
df.groupby([‘A’,‘B’]).mean()-----A、B是双层索引
df.groupby([‘A’,‘B’]).mean().reset_index() -----A、B不是双层索引
df.groupby([‘A’,‘B’], as_index=False).mean()-----------A、B不是双层索引
(3)同时查看多种数据统计
df.groupby(‘A’).agg([np.sum, np.mean, np.std])
(4) 查看单列的结果数据统计
方法1:预过滤,性能更好
df.groupby(‘A’)[‘C’].agg([np.sum, np.mean, np.std])
(5)不同列使用不同的聚合函数
df.groupby(‘A’).agg({“C”:np.sum, “D”:np.mean})
2.高级使用方法
电影评分数据集(UserID,MovieID,Rating,Timestamp)\

聚合后单列-单指标统计:每个MovieID的平均评分
df.groupby(“MovieID”)[“Rating”].mean()\

聚合后单列-多指标统计:每个MoiveID的最高评分、最低评分、平均评分
df.groupby(“MovieID”)[“Rating”].agg(mean=“mean”, max=“max”, min=np.min)
df.groupby(“MovieID”).agg({“Rating”:[‘mean’, ‘max’, np.min]})\

聚合后多列-多指标统计:每个MoiveID的评分人数,最高评分、最低评分、平均评分
df.groupby(“MovieID”).agg( rating_mean=(“Rating”, “mean”), user_count=(“UserID”, lambda x : x.nunique())
df.groupby(“MovieID”).agg( {“Rating”: [‘mean’, ‘min’, ‘max’], “UserID”: lambda x :x.nunique()})
df.groupby(“MovieID”).apply( lambda x: pd.Series( {“min”: x[“Rating”].min(), “mean”: x[“Rating”].mean()}))\

记忆:agg(新列名=函数)、agg(新列名=(原列名,函数))、agg({“原列名”:函数/列表})
agg函数的两种形式,等号代表“把结果赋值给新列”,字典/元组代表“对这个列运用这些函数”

#聚合后单列-单指标
df.groupby('MovieID')['Rating'].mean().head(1)
# 聚合后单列-多指标统计
# 方法1:agg函数传入多个结果列名=函数名形式
df.groupby('MovieID')['Rating'].agg(mean='mean',max='max',min=np.min).head(1)
#方法2:agg函数传入字典,key是column名,value是函数列表
df.groupby('MovieID').agg({
     'Rating':['mean','max','min']})\
                .rename(columns={
     'mean':'age_mean','max':'age_max','min':'age_min'}).head(1)
#聚合后多列多指标统计
#方法1:agg函数传入字典,key是原列名,value是原列名和函数元组
df.groupby('MovieID').agg(
                    rating_mean=('Rating','mean'),
                    rating_min=('Rating','min'),
                    rating_max=('Rating','max'),
                    user_count=('UserID',lambda x :x.nunique())).head(1)
# 方法3:使用groupby之后apply对每个子df单独统计
def agg_func(x):
    """注意,这个x是子DF"""
    
    # 这个Series会变成一行,字典KEY是列名
    return pd.Series({
     
        "rating_mean": x["Rating"].mean(),
        "rating_min": x["Rating"].min(),
        "rating_max": x["Rating"].max(),
        "user_count": x["UserID"].nunique()
    })

result = df.groupby("MovieID").apply(agg_func)
result.head(1)

多层索引 和reset_index,set_index(),stack,unstack

多层索引(MultiIndex)

分层索引:在一个轴向上拥有多个索引层级,可以表达更高维度数据的形式;
可以更方便的进行数据筛选,如果有序则性能更好;
groupby等操作的结果,如果是多KEY,结果是分层索引,需要会使用
一般不需要自己创建分层索引(MultiIndex有构造函数但一般不用)
Series: 有多层索引MultiIndex怎样筛选数据?
经过groupby 之后得到的都是series\

ser = stocks.groupby(['公司', '日期'])['收盘'].mean()
ser.head()
ser.loc['BIDU']
# 多层索引,可以用元组的形式筛选
ser.loc[('BIDU', '2019-10-02')]

DataFrame:多层索引MultiIndex
在选择数据时:\

元组(key1,key2)代表筛选多层索引,其中key1是索引第一级,key2是第二级,比如key1=JD, key2=2019-10-02
列表[key1,key2]代表同一层的多个KEY,其中key1和key2是并列的同级索引,比如key1=JD, key2=BIDU

stocks.set_index(['公司', '日期'], inplace=True)
stocks.head(1)
stocks.loc[('BIDU', '2019-10-02'), :]
stocks.loc[(['BIDU', 'JD'], '2019-10-03'), :]
stocks.loc[('BIDU', ['2019-10-02', '2019-10-03']), '收盘']

reset_index()

(注:reset_index还原分为两种类型,第一种是对原DataFrame进行reset,第二种是对使用过set_index()函数的DataFrame进行reset)
DataFrame.reset_index(level=None, drop=False, inplace=False, col_level=0, col_fill=”)\

level:int、str、tuple或list,默认无,仅从索引中删除给定级别。默认情况下移除所有级别。控制了具体要还原的那个等级的索引
drop:索引被还原成普通列后,是否删掉列。默认为False,为False时则索引列会被还原为普通列,否则被还原后的的列又会被瞬间删掉;
inplace:默认为false,适当修改DataFrame(不要创建新对象);
col_level:int或str,默认值为0,如果列有多个级别,则确定将标签插入到哪个级别。默认情况下,它将插入到第一级;
col_fill:对象,默认‘’,如果列有多个级别,则确定其他级别的命名方式。如果没有,则重复索引名;\

set_index()

格式:DataFrame.set_index(keys, drop=True, append=False, inplace=False, verify_integrity=False)\

keys:列标签或列标签/数组列表,需要设置为索引的普通列
drop:是否删除原普通列,默认为True,删除用作新索引的原普通列;
append:是否变成复合索引,默认为False,即覆盖原索引,单索引;
inplace:默认为False,适当修改DataFrame(不要创建新对象);
verify_integrity:默认为false,检查新索引的副本。否则,请将检查推迟到必要时进行。将其设置为false将提高该方法的性能。\

unstack()和stack()

stack:DataFrame.stack(level=-1, dropna=True),将column变成index,类似把横放的书籍变成竖放(脱帽)\

level=-1代表多层索引的最内层,可以通过==0、1、2指定多层索引的对应层
unstack:DataFrame.unstack(level=-1, fill_value=None),将index变成column,类似把竖放的书籍变成横放(戴帽)\

数据透视表(pivot_table)

df.pivot_table(values=None, index=None, columns=None, aggfunc=‘mean’, fill_value=None, margins=False, dropna=True, margins_name=‘All’)
index :相当于行索引,如果赋值时列表,那么从左到右依次聚合,会自动合并第一列相同的值。

pd.pivot_table(df,index=['manager','status'],columns=['product'],values=['quantity','price'], aggfunc={
     'quantity':len,'price':np.sum},fill_value=0)

apply,applymap,map,以及apply应用在groupby上

数据转换函数对比:map、apply、applymap:

stocks = pd.read_excel('./datas/stocks/互联网公司股票.xlsx')
# 公司股票代码到中文的映射,注意这里是小写
dict_company_names = {
     
    "bidu": "百度",
    "baba": "阿里巴巴",
    "iq": "爱奇艺", 
    "jd": "京东"
}

map

只用于Series,实现每个值->值的映射-series.map(dict) or series.map(function)传入字典/函数均可;

# 方法1:Series.map(dict) 传入字典
stocks["公司中文1"] = stocks["公司"].str.lower().map(dict_company_names)
# 方法2:Series.map(function) 传入函数
stocks["公司中文2"] = stocks["公司"].map(lambda x : dict_company_names[x.lower()])

apply

用于Series和DataFrame的转换
不管用在series还是df上,第一个参数都是函数

Series.apply(function), 函数的参数是每个值
DataFrame.apply(function), 函数的参数是Series
apply:用于Series实现每个值的处理,用于Dataframe实现某个轴的Series的处理;

#  Series.apply(function) function的参数是Series的每个值
stocks["公司中文3"] = stocks["公司"].apply(
    lambda x : dict_company_names[x.lower()])
# DataFrame.apply(function)  function的参数是对应轴的Series
stocks["公司中文4"] = stocks.apply(
    lambda x : dict_company_names[x["公司"].lower()], 
    axis=1)

注意这个代码:
1、apply是在stocks这个DataFrame上调用;
2、lambda x的x是一个Series,因为指定了axis=1所以Seires的key是列名,可以用x[‘公司’]获取

applymap

只能用于DataFrame,用于处理该DataFrame的每个元素;

# 直接修改原df的这几列
sub_df = stocks[['收盘', '开盘', '高', '低', '交易量']]
stocks.loc[:, ['收盘', '开盘', '高', '低', '交易量']] = sub_df.applymap(lambda x : int(x))

对分组groupby后的数据使用apply

知识:Pandas的GroupBy遵从split、apply、combine模式 。 这里的split指的是pandas的groupby,我们自己实现apply函数,apply返回的结果由pandas进行combine得到结果\

GroupBy.apply(function)\

function的第一个参数是dataframe
function的返回结果,可是dataframe、series、单个值,甚至和输入dataframe完全没关系
例1:演示:用户对电影评分的归一化\

每个用户的评分不同,有的乐观派评分高,有的悲观派评分低,按用户做归一化

# 实现按照用户ID分组,然后对其中一列归一化
def ratings_norm(df):
    """
    @param df:每个用户分组的dataframe
    """
    min_value = df["Rating"].min()# 每个分组后DF的Min
    max_value = df["Rating"].max()# 每个分组后DF的Max
    df["Rating_norm"] = df["Rating"].apply(
        lambda x: (x-min_value)/(max_value-min_value))
    return df

ratings = ratings.groupby("UserID").apply(ratings_norm)
ratings[ratings["UserID"]==1].head()
# 怎样取每个分组的TOPN数据? 获取2018年每个月温度最高的2天数据
fpath = "./datas/beijing_tianqi/beijing_tianqi_2018.csv"
df = pd.read_csv(fpath)
# 替换掉温度的后缀℃
df.loc[:, "bWendu"] = df["bWendu"].str.replace("℃", "").astype('int32')
df.loc[:, "yWendu"] = df["yWendu"].str.replace("℃", "").astype('int32')
# 新增一列为月份
df['month'] = df['ymd'].str[:7]
def getWenduTopN(df, topn):
    """
    这里的df,是每个月份分组group的df
    """
    return df.sort_values(by="bWendu")[["ymd", "bWendu"]][-topn:]

df.groupby("month").apply(getWenduTopN, topn=1).head()

时间函数

Pandas日期处理的作用:将2018-01-01、1/1/2018等多种日期格式映射成统一的格式对象,在该对象上提供强大的功能支持\

几个概念:

pd.to_datetime:pandas的一个函数,能将字符串、列表、series变成日期形式
Timestamp:pandas表示日期的对象形式
DatetimeIndex:pandas表示日期的对象列表形式
其中:

DatetimeIndex是Timestamp的列表形式
pd.to_datetime对单个日期字符串处理会得到Timestamp
pd.to_datetime对日期字符串列表处理会得到DatetimeIndex

df.reset_index(inplace=True)
# 转变为标准的时间格式
df['day'] = pd.to_datetime(d2.loc[:,'ymd'],format='%Y/%m/%d ')
df2['day'] = df2['day'].values.astype('datetime64[D]')
df['month'] = df['day'].values.astype('datetime64[M]'
df2['opendays'] = (df2.day-df2.f_work_start_time)/np.timedelta64(1,'D')
# Timestamp、DatetimeIndex支持大量的属性可以获取日期分量(周数字、月数字、季度数字):
df['week_number']=df['day'].dt.week
df['month_number'] = df['day'].dt.month
df['quarter_mumber'] = df['day'].dt.quarter
# 通常把标准日期格式设置为索引,方便后续操作
df1.set_index('day',drop=True,inplace=True)
# 周数字列表
df.index.week   ----- 和df['day'].dt.week 一样的效果
# 月数字列表
df.index.month
# 季度数字列表
df.index.quarter

Matplotlib

1、设置图片大小
2、保存本地
3、描述信息,比如x轴y轴表示什么,这个图表示什么
4、调整x或者y的刻度的间距
5、线条的样式
6、标记出特殊的点
7、给图片添加一个水印

#设置图片大小
fig = plt.figure(figsize=(20,8),dpi=80)
x = range(2,26,2)
y = [15,13,14.5,17,20,25,26,26,24,22,18,15]
#绘图
plt.plot(x,y)
#设置x轴的刻度。通过改变x的步长可以调整x轴刻度的密集程度
# plt.xticks(x) 直接设置
# 如果设置的更密集一点。但是步长最小是1,不能是0。5
_xtick_labels = [i/2 for i in range(4,49)]
plt.xticks(_xtick_labels)
#设置y轴的刻度
plt.yticks(range(min(y),max(y)+1))
#展示图形
plt.show()
#问题1:如果列表a表示10点到12点的每一分钟的气温,如何绘制折线图观察每分钟气温的变化情况?
plt.figure(figsize=(20,8),dpi=80)
y=[random.randint(20,35) for i in range(120)]
x= range(0,120)
plt.plot(x,y)
#调整x轴的刻度(将整数换成字符串)
#_x = list(x)[::3]#强行将变量x转为列表,并每隔10个数字去一个值。方便坐标轴显示.或者直接在plt.xticks设置
_xtick_lables = ["10点{}分".format(i) for i in range(60)]
_xtick_lables += ["11点{}分".format(i) for i in range(60)]
# 取步长,数字和字符串一一对应,数据的长度一样
plt.xticks(list(x)[::3],_xtick_lables[::3],rotation=45)#旋转的度数
'''
1、让列表x中的数据和_xtick_lables的数据都传入,最终会在x轴上一一对应的显示出来
2、两组数据的长度必须一样,否则不能完全覆盖整个轴
3、使用列表的切片,每隔3个选一个数据进行显示
4、为了让字符串不会覆盖,使用rotation让字符串进行旋转

'''
#添加描述信息
plt.xlabel("时间")
plt.ylabel("温度/c")
plt.title("10点到12点每分钟气温变化的情况")

plt.show()
#练习题:假设大家在30岁的时候根据自己的实际情况,统计出来了从11岁到30岁每年交的那男女朋友的数量如列表a,
#请绘制出该数据的折线图以便分析数量走势。a=[1,0,1,1,2,4,3,2,3,4,4,5,6,5,4,3,3,1,1,1]要求:x轴表示岁数,如11岁。  y轴表示个数
plt.figure(figsize=(15,5),dpi=400)
y=[1,0,1,1,2,4,3,2,3,4,4,5,6,5,4,3,3,1,1,1]
x=list(range(11,31))
plt.plot(x,y)
#设置x轴坐标显示
_xtick_lables = ["{}岁".format(i)  for i in x]
plt.xticks(x[::2],_xtick_lables[::2])
plt.yticks(range(0,9))
#添加描述信息
plt.xlabel("岁数")
plt.ylabel("朋友个数")
plt.title("11-30岁交往的朋友个数")
plt.grid(alpha=0.4)#显示网格
plt.show()
plt.figure(figsize=(15,5),dpi=80)
y1=[1,0,1,1,2,4,3,2,3,4,4,5,6,5,4,3,3,1,1,1]
y2=[1,0,3,1,2,2,3,3,2,1,1,1,1,1,1,1,1,1,1,1]
x=list(range(11,31))
plt.plot(x,y1,label="自己",color='red',marker = 'o')
plt.plot(x,y2,label="同桌",color='cyan',linestyle=":")
#设置x轴坐标显示
_xtick_lables = ["{}岁".format(i)  for i in x]
plt.xticks(x[::2],_xtick_lables[::2])
#plt.yticks(range(0,9))
#添加描述信息
plt.xlabel("岁数")
plt.ylabel("朋友个数")
plt.title("11-30岁交往的朋友个数")
plt.grid(alpha=0.4)#显示网格
plt.legend(loc='upper left')#显示图例
plt.show()






你可能感兴趣的:(pandas常用操作)