import pandas as pd
pd.read_csv(filepath_or_buffer, sep=',', delimiter=None, header='infer',
names=None, index_col=None, usecols=None, squeeze=False,
prefix=None, mangle_dupe_cols=True, dtype=None, engine=None,
converters=None, true_values=None, false_values=None,
skipinitialspace=False, skiprows=None, nrows=None,
na_values=None, keep_default_na=True, na_filter=True,
verbose=False, skip_blank_lines=True, parse_dates=False,
infer_datetime_format=False, keep_date_col=False,
date_parser=None, dayfirst=False, iterator=False, chunksize=None,
compression='infer', thousands=None, decimal=b'.',
lineterminator=None, quotechar='"', quoting=0, escapechar=None,
comment=None, encoding=None, dialect=None, tupleize_cols=None,
error_bad_lines=True, warn_bad_lines=True, skipfooter=0,
doublequote=True, delim_whitespace=False, low_memory=True,
memory_map=False, float_precision=None)
df=pd.read_csv('file.csv',encoding='utf')
如果文件名带中文,上述方法可能报初始化错误,使用以下方法:
f=open('文件.csv')
或wirh open('文件.csv') as f:
df = pd.read_csv(f)
with open('文件.csv',encoding='utf-8') as f:
df=pd.read_csv(f)
该方法其实有很多参数可以实现很多功能,比如在读取文件的时候设定参数na_value='值‘,就可以将该表中为该值的数据当做成np.nan,当然这些功能也可以在read之后实现。参考:pandas系列 read_csv 与 to_csv 方法各参数详解(全,中文版)
#first订单1-3.csv和其他以”订单“开头的表结构相同
df_orderpd.read_csv(r'first订单1-3.csv',dtype={'员工邀请码': 'str'})
#https://laowangblog.com/python-pandas-csv-dtypewarning-mixed-types.html
pat=re.compile('订单.*?')
for file_name in os.listdir(os.getcwd()):
if re.match(pat,file_name):
df_order=pd.concat([df_order,pd.read_csv(file_name,dtype={'员工邀请码': 'str'})])
pd.read_excel(file.xlsx')
df_order=pd.read_excel('file名.xlsx')
该方法接受文件名带中文
pd.read_excel(io, sheet_name=0, header=0, names=None, index_col=None,
usecols=None, squeeze=False, dtype=None, engine=None,
converters=None, true_values=None, false_values=None,
skiprows=None, nrows=None, na_values=None, parse_dates=False,
date_parser=None, thousands=None, comment=None, skipfooter=0,
convert_float=True, **kwds)
该方法有很多参数可以应对不同的情况,例如指定工作表等。
连接数据库参考:
[Python]第十三章 数据库支持
【Python小笔记】Python连接Oracle数据库——cx_Oracle
pandas.read_sql(sql, con, index_col=None, coerce_float=True, params=None,
parse_dates=None, columns=None, chunksize=None)
sqllite3
import pandas as pd
import sqllite3
with sqllite3.connect('country_stat.sqlite') as cons:
dfs = pd.read_sql('SELECT * FROM regional_gross_product WHERE year = 2015 ORDER BY gross_product DESC LIMIT 3', con = cons)
dfs.head()
mysql
没有自带__enter__() 和 __exit__() 方法,不能直接使用with上下文管理器,推荐阅读使用with语句优化pymysql的操作
import pymysql
conm=pymysql.connect('localhost','root','123456','mytest')
dfm=pandas.read_sql('SELECT * FROM EMPLOYEES',con=conm)
conm.close()
dfm.head()
oracle
import cx_Oracle
name='scott'
pwd='tiger'
add='localhost/orcl.16.2.133'
with cx_Oracle.connect(name,pwd,add) as cono:
dfo=pandas.read_sql('SELECT * FROM EMP WHERE DEPTNO=20',con=cono)
dfo.head()
pd.read_html(io, match='.+', flavor=None, header=None, index_col=None,
skiprows=None, attrs=None, parse_dates=False, tupleize_cols=None,
thousands=',', encoding=None, decimal='.', converters=None,
na_values=None, keep_default_na=True, displayed_only=True)
df.rename(mapper=None, index=None, columns=None, axis=None, copy=True, inplace=False, level=None)
df_order.rename(columns={'下单日期':'日期','下单小时':'小时'},inplace=True)
或
df_order.rename({'下单日期':'日期','下单小时':'小时'},axis='columns',inplace=True)
#inplace=True对原dataframe进行修改
该方法可以更改列名或行名或更改标签值类型
如果需要改的列名特别多,可以直接给df的columns属性赋值,修改全部列名
df.columns=['年','周','频道','性别','销售数量','销售金额']
df=pd.DataFrame([list('abc'),list('anf'),list('abc'),list('fgc'),list('rbc')])
df_p1=df[:2]
df_p2=df[2:]
df.append(other, ignore_index=False, verify_integrity=False, sort=None)
ser_m=pd.Series([44,55,66])
df_p1=df_p1.append(ser_m,ignore_index=True)
pd.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)
该方法不仅可以上下堆叠,还可以左右堆叠
df=df_p1.append(df_p2,ignore_index=True)
或
df=pd.concat([df_p1,df_p2],ignore_index=True]
append
方法可以快速在底部追加
df=df.append(ser_m,ignore_index=True)
df=df.append(df_new,ignore_index=True)
concat
不截断,就是默认在底部合并
df=pd.concat([df,df_new],ignore_index=True]
如果知道要添加的行的索引,直接赋值(注意如果索引号错误则会覆盖原df数据)
df.iloc[5]=ser_m
参考:【Python数据科学手册】Pandas——七、合并数据集:Concat和Append操作
df.insert(loc, column, value, allow_duplicates=False)
df.insert(7,'brand_supplier',brand_supplier)
插入的列除了源dataframe结构的序列,也可以是常量,或者空值np.nan
但是这种方法只能一次插入单列
如果不需要指定位置插入,直接单列赋值,如df['new']=11
,会在最后列添加’new’列
指定列方向,使用concat
方法也可以合并列,如果需要指定位置,可以插入后调整列序
pd.concat([df,df_new],axis=1)
(1). 先获取索引,再使用drop方法删除
获取索引的方法见下文<单列条件筛选记录>
df[条件序列].index
ser[条件序列].index
del_index=df[df['subcategory'].isin(list_type)].index
ser_nor[ser_nor>1].index
df.drop(labels=None, axis=0, index=None, columns=None, level=None, inplace=False, errors='raise')
其中:axis=0代表行,axis=1代表列
df=df.drop(del_index,axis=0,inplace=True)
(2). 如果条件不复杂,条件取反后赋值给原df
df=df.query('ID!=12123')
df
del df[列名]
df=df.drop(列名,1)
df.drop(列名,axis=1,inpalce=True)
df_house.drop('Brick',axis=1)
df_house.drop(['No','West','Brick','Neighborhood'],axis=1)
如果需要删除的列太多而要保留的列很少,或者只需要从原df中选取指定的某(几)列,可以列表选取后直接赋值
df=df[['列名1','列名2',...]]
当然列表中也可以只有一个元素,表示只有一列的dataframe,需要与df['列名']
这个Series区别
df=df[['列名']]
如果仅调整某列的位置,可以取出-删除-插入
df_id = df.id
df = df.drop('id',axis=1)
df.insert(0,'id',df_id)
如果要调整的列比较繁杂,可以直接定义好列序,赋值给原df即可
df=df[['姓名','年龄','工号']]
或者使用reindex
方法(reindex方法还可以插入空列)
df_sp=df_sp.reindex(columns=list('卫室厅厨'))
去除重复记录,可以用删除的一般方法,先用duplicated()找到重复数据的索引,再drop删除,也可以直接使用:
df.drop_duplicates(subset=None, keep='first', inplace=False)
df.drop_duplicates(subset=['姓名','性别'], keep='first', inplace=False)
df.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
axis:0删除行,1删除列
how:'any’表示一旦有缺失值就删除,'all’表示全部是缺失值才删除
thresh:设置缺失值个数的删除边界,一旦超过某值,就删除
subset:要删除的行或列的标签列表
inplace:是否更新到原df
#删除’作者ID‘列有空值的所在行
df_cont.dropna(axis=0,subset=['作者ID'],inplace=True)
merge操作类似于excel中vlookup的存在,在sql中效通join,一般会伴随这字段的新增或更改。
df.merge(right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=False, suffixes=('_x', '_y'), copy=True, indicator=False, validate=None)
df=df1.merge(right=df2,how='left',on=['店铺名称','日期','小时'])
df_A=df_A1.merge(right=df_A2,how='left',left_on=['公司名','业务主体'],right_on=['公司名','业务线'])
df.pivot_table(values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All')
df_pv_pivot=df_pv.pivot_table(index=['资讯ID','日期'],values='PV',aggfunc='sum')
参考:【Python数据科学手册】Pandas——十、数据透视表 df. pivot_table
df.sort_index()按索引排序
df.sort_value()按某列值排序
df.rank()排名
注意:通过axis参数可以指定行排序
df.sort_values(by='PV',ascending=False)
如果需要取topN,或者倒序取topN,可以先排序后切片
df.sort_values(by='销售',ascending=False).iloc[:5]
也可以使用df.nlargest()
和df.nsmallest()
直接取
df.nlargest(5,'销售')
对于分组取topN,可以使用以下函数,内涵也是先排序后切片
#分组df取topN
def func(x,N,asc):
return x.sort_values('population',ascending=asc)[:N]
df.groupby('continent').apply(func,N=3,asc=False)
get_dummies()
作为普通方法,将整个值内容提取作为新列
pd.get_dummies(df['朝向'])
作为str方法,按照特定符号提取字符作为新列
df['info'].str.get_dummies(',')
单列df[列名]
,多列可以使用df.filter()
,改方法也可筛选行
#取列名取列
df.filter(regex='.*销.*')
df.filter(items=['销售'])
df.filter(like='销')
#取索引名取行
df.set_index('客户').filter(like='华鼎',axis='index')
#先用set_index方法给每一行设置一个索引名作为行名,再去筛选这个行名
选取数据的方法有很多种,本节简单使用df[条件]
选取符合条件的行记录,列全部保留。
实际操作中使用索引器loc\iloc
可以灵活选取所需数据,包括列的选择,例如
df[df['ID']==12121].iloc[:,2:5]#df[条件].iloc[:,列号:列号]
等价于掩码操作
df.loc[df['ID']==12121,'标题':'编辑']#df.loc[条件,列名:列名]
也可以使用df.query()
方法取,适用于运算条件,例如:
df.query('ID==12121').loc[:,'标题':'编辑']#df.query(字符串表达式).loc[:,列名:列名]
参考 【Python数据科学手册】Pandas——三、数据取值与选择
参考 【Python数据科学手册】Pandas——十三、高性能的Pandas:eval()和query()
df[df[列名].str.contains(正则表达式)]
df[df['brand_supplier'].str.contains('.*华鼎.*')]
不等于:!=
df[df[列名]==值]
df[df[列名]!=值]
df[df['shop_name']=='XXXTRENTA']
df[df['shop_name']!='XXXTRENTA']
非:~
df[df[列名].isin(列表)]
df[~df[列名].isin(列表)]
list_type=['运动','美妆','男装','女装']
df[df['subcategory'].isin(list_type)]
df[~df['subcategory'].isin(list_type)]
(同样的记录第一次出现是非重复,之后又出现的都算重复)
df[df.duplicated(subset=None, keep='first')]
df[~df.duplicated(subset=None, keep='first')]
subset是列名或列名集合,用它来定义重复,缺失默认全字段重合的数据才是重复。
#重复的记录
df_passenger[df_passenger.duplicated('店铺名称')]
#非重复的记录
df_passenger[~df_passenger.duplicated('店铺名称')]
EXTEND:
如果要提取汇总项,除了上述方法找到非重复记录后取该列,
df_passenger[~df_passenger.duplicated('店铺名称')]['店铺名称']#pandas.core.series.Series
也可以用分组groupby
汇总项索引转列后提取使用
df_passenger.groupby(by='店铺名称').count().reset_index()['店铺名称']#pandas.core.series.Series
或者df[列名].unique()
——最快捷
df_passenger['店铺名称'].unique()#numpy.ndarray, len()得到非重复个数
甚至可以对汇总项快速计数df[列名].value_counts()
df_passenger['店铺名称'].value_counts()#pandas.core.series.Series
判断某行或者某列是否有空值
df.any()存在
df.all()全部
#查看全列
df.isnull()#返回一个dataframe,和原dataframe的结果一一对应
df.isnull().any()#得到一个序列对应每列的结果
df.isnull().values.any()#得到一个布尔值,反应整体的结果
df.isnull().sum()#加总布尔值True等价于1,合计每列有多少个缺失值
df.isnull().sum().sum()#将所有列的缺失值都加总
#或者仅查看某列
df['客户'].isnull()#得到一个序列对应改列每一个值的结果
df['客户'].isnull().any()#得到该列的整体结果
df['客户'].isnull().sum()#合计该列的缺失值数
空值记录:df[pd.isna(df[列名])]
等价于df[pd.isnull(df[列名])]
df[pd.isna(df['name'])]
非空值记录:df[pd.notna(df[列名])]
等价于df[pd.notnull(df[列名])]
与:df[(条件列筛选序列1)&(条件列筛选序列2)]
或:df[(条件列筛选序列1)|(条件列筛选序列2)]
异或:df[(条件列筛选序列1)^(条件列筛选序列2)]
df[(df['brand_supplier'].str.contains('.*华鼎.*'))&(df['shop_name']!='XXXTRENTA')]
df.fillna(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None, **kwargs)
单列填充空值df[列名].fillna(值)
全表填充空值df.fillna(值)
这里的value可以是scalar, dict, Series, or DataFrame,不能是list
df['subcategory'].fillna('其它')
df['age'].fillna(df['age'].mean())#填充平均值
df['age'].fillna(df.groupby('gender')['age'].transform('mean'))#填充分组平均值
transform参考:【Python数据科学手册】Pandas——九、累计与分组groupby
method:‘pad’、'ffill’向后填充(用上一位的值填空值),‘bfill’、'backfill’向前填充
limit:要填多少个值
df.fillna(method="bfill", limit = 2)
df2 = pd.DataFrame([[1, 870],\
[2, 900],\
[np.nan, np.nan],\
[4, 950],\
[5,1080],\
[6,1200]])
df2.columns = ['time', 'val']
df2.interpolate()
详细参考scipy库官方文档interpolate部分
df[列名]=值
这里的值可以是函数应用公式(见第七节),也可以是常量
df['channel']='淘宝'
如果原先没有该列,则会默认在dataframe的最后添加新列。
(1)单值替换
方法1:定位要替换的值后直接赋替换后的值:df.loc[df[列名]==被替换的值,列名]=值
df.loc[df['subcategory']=='关店','subcategory']='其它'
方法2:replace方法df.replace(to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad')
df['subcategory']=df['subcategory'].replace('关店','其它')
(2)批量替换
#方法一:使用列表,保证顺序对应
xlist=['A','B','C']
ylist=['a','b','c']
#for o,l in zip(xlist,ylist):
# df[列名]=df[列名].replace(o,l)
df[列名].replace(xlist,ylist,inplace=True)
#方法二:使用字典
mapdict={'A':'a','B':'b','C':'c'}
#for m in maplist:
# df[列名]=df[列名].replace(m,mapdict[m])
df[列名].replace(mapdict)
#条件查找,模糊替换
df.loc[pd.to_numeric(df_pp.loc[:,'年季'].str[0:2])<=17,'年季']='17年以前'
#确值替换
df['姓名'].replace(['张倩','张茜'],'张芊')
主要方法有:
astype(dtype, order='K', casting='unsafe', subok=True, copy=True)
对于形似日期的字符串数据,可以转换成真正的日期
from dateutil import parser
parser.parse(string)
from dateutil import parser
date=parser.parse('2020-6-1')
date
>>>datetime.datetime(2020, 6, 1, 0, 0)
pd.to_datetime(df[列名])
pd.to_datetime(df_order['日期'],format="%Y-%m-%d")#这里format是传入的格式
或者
df[列名].astype('M')
datetime64[ns]
date.strftime(样式)
date.strftime("%Y%m%d")
>>>'20200601'
#获取当天日期
import time
time.strftime('%Y%m%d')
#或者
import datetime
datetime.date.today().strftime('%Y%m%d')
#动态相对日期(两天前)
(datetime.date.today()-datetime.timedelta(2)).strftime('%Y-%m-%d')
datetime库参考:Python中datetime库的用法
时间相关资料:
[Python]第十章 开箱即用
【Python数据科学手册】Pandas——十二、处理时间序列
df[列名].apply(lambda x:x.strftime(指定格式))
pd.to_datetime(df_order['日期']).apply(lambda x:x.strftime("%Y%m%d"))
或者
def dtos(x):
return x.strftime("%Y%m%d")
pd.to_datetime(df_order['日期']).apply(dtos)
int(string)
即可pd.to_numeric(df[列名])
df_order['日期']=pd.to_numeric(pd.to_datetime(df_order['日期']).apply(lambda x:x.strftime("%Y%m%d")))
或者
df[列名].astype('int')
int32
str(number)
df_order['年龄'].apply(lambda x:str(x))
或者
df[列名].astype('str')
object
import datetime
d=datetime.datetime.now()
d
>>>datetime.datetime(2020, 8, 26, 10, 19, 25, 910701)
#年、月、日、时、分、秒、微秒
d.year,d.month,d.day,d.hour,d.minute,d.second,d.microsecond
(2020, 8, 26, 10, 19, 25, 910701)
#year年, month月, day日,date日期,hour小时
df['日期'].dt.date
(pd.to_datetime('2020-12-25',format='%Y-%m-%d')-df_rfm['ORDERDATE']).dt.days
这里是对字符串值的字符内容的处理,与字段内容处理不同,例如替换值,excel里面是ctrl+h,python里参考本文,可以用df[A].replace()
方法;
而本节是针对字符串内容的处理,在excel中替换字符用的是substitute函数,python里面需要df[A].str.replace()
。
大部分在python基础中学习的对字符串的方法,这里都能实现
df[A].str.cat(df[B])
brand_supplier=df['brand_name'].str.cat(df['supplier_name'])
如果两个字段是形同类型的字符串,也可以直接用加号
brand_supplier=df['brand_name']+df['supplier_name']
但是如果有字段不是字符类型,需要先将该字段转成字符类型
df['总价'].astype('str').str.cat(df['价格单位'])
df[A].str.find(childstring)
df['店铺名称'].str.find('餐厅')
返回单个字符df[A].str.get(index)
df['店铺名称'].str.get(0)
返回片段用切片
df['店铺名称'].str[:3]
df[A].str.contains(childstring)
df['店铺名称'].str.contains('餐厅')
df[A].str.count(childstring)
df['店铺名称'].str.count('餐厅')
df[A].str.replace(原字符,后字符)
df['姓名'].str.replace('三','二')#将‘三替’换成‘二’
字符串中的replace一般只可以一个字符串对应一个字符串替换,不能是列表或字典。
#建筑年代:1996\r\n
df['age'].str.strip().str.strip('建筑年代:')
>>>1996
同
df['age'].map(lambda e:e.strip().strip('建筑年代:') )
df[A].str.split(childstring)
df['姓名'].str.split('三').str[-1]
df['室']=df['户型'].str.split('室').str[0]
df_passenger['店铺名称'].str.lower()
df_passenger['店铺名称'].str.upper()
除了str内置方法,也可以根据需求定制处理函数,通用的函数方法具体见下节。
举例:
split()
分割字符串,分割后生成子字符串列表,根据列表索引选择要截取的部分df['姓名'].apply(lambda x:x.split('三')[-1])
效果同上一小节
2) 字符大小写
小写lower()
大写upper()
df_passenger['店铺名称'].apply(lambda x:x.lower())
df_passenger['店铺名称'].apply(lambda x:x.upper())
#st='2室2厅1厨1卫'
df[list('室厅厨卫')] = df['户型'].str.extract('(\d+)室(\d+)厅(\d+)厨(\d+)卫')
'''
df_sp=df['户型'].str.extract('(\d+)室(\d+)厅(\d+)厨(\d+)卫')
#df['室'],df['厅'],df['厨'],df['卫']=[df_sp.iloc[:,i] for i in range(4)]
df_sp.columns=list('室厅厨卫')
df=pd.concat([df,df_sp],axis=1)
'''
上一节字符内容的处理也是计算字段,包括转换类型部分也涉及到。本节介绍更通用的函数方法处理字段值。
要传入的计算对象.apply(func, axis=0, broadcast=None, raw=False, reduce=None, result_type=None, args=(), **kwds)
要传入的对象
可以是df,也可以是series、groupbySeries
func
可以是匿名函数或者自定义函数
1.apply()
是一种让函数作用于DataFrame中行或列的操作。
2.applymap()
是一种让函数作用于DataFrame每一个元素的操作。
3.map()
是一种让函数作用于Series每一个元素的操作。
(1).匿名函数
df['ID'].apply(lambda x: 'Boy' if x>30000 else 'Girl')
#是否包含任意关键词
keycategorylist=df_hx['核心品类'].tolist()
df_order['核心品类商品']=df_order['商品品类'].apply(lambda x:'核心' if any(kt in str(x) for kt in keycategorylist) else '非核心')
##是否包含某个子串
df_plat['本月新增商户']=df_plat_order['收入时间'].apply(lambda x:'新增' if year_month in str(x) else '非新增')
(2).自定义函数
def compare(x):
if x>30000:
y='Boy'
else:
y='Girl'
return y
df['ID'].apply(compare)#传入series,不需要指定axis
#df['ID'].map(compare)#map方法可以将函数套用到Series上的每个元素
def dfcompare(x):
if x['ID']>30000:
y='Boy'
else:
y='Girl'
return y
df.apply(dfcompare,axis=1)#传入df,axis=1指定逐行
CASE:结合re模块,利用正则表达式拆分字段成新列,并转换数据类型
split()函数无法依据多个符号拆分字符串,因此可以用到正则表达式的编组
(如上节所示,其实pandas字符串自带re模块函数方法,但是extract()方法是编组后直接返回,中间不能插入转换类型这一操作,只能返回后一列列转换)
分组-返回-转换
cols=list('室厅厨卫')
df[cols] = df['layout'].str.extract('(\d+)室(\d+)厅(\d+)厨(\d+)卫')
for i in range(4):
df[cols[i]]=pd.to_numeric(df[cols[i]])
以下方法自己写的函数,思路是先分组-转换-最后返回新列
#st='2室2厅1厨1卫'
from re import *
pat=compile('(\d+)室(\d+)厅(\d+)厨(\d+)卫')
def pa(x):
m=match(pat,x)
nums=[m.group(1),m.group(2),m.group(3),m.group(4)]
return nums
for i in range(4):
df[colli[i]]=pd.to_numeric(df['layout'].map(pa).map(lambda x:x[i]))
pandas的str本身就有re模块相对应的方法,相对而言,正则匹配相对re模块要宽松,
s='中层(共7层)\r\n'
#pandas
pat=compile('\s*(\d+)室(\d+)厅\s*')
#re
df['floor_info'].str.extract('共(\d+)层')
参考:
【Python数据科学手册】Pandas——十三、高性能的Pandas:eval()和query()
a.常规:
#(入库金额-退供应商金额)*90天售罄/100
df_sq['收入']=(df_sq['销售']-df_sq['退货'] )* df_sq['90天均价']/100
b.numpy的通用函数:
df['收入']=df['销售'].sub(df['退货']).mul(df['90天均价'])/100
c.df.assign
:
df=df.assign(收入=lambda df:(df['销售']-df['退货'])*df['90天均价']/100)
d.df.eval()
:
nisq=df_sq['90天均价']
df_sq['收入']=df_sq.eval('(销售-退货)*@nisq/100')
#列名不规范,可以先定义变量
#df_sq['收入']=df_sq.eval('(销售-退货)*90天均价/100')
#报错,不能直接使用带数字的不规范列名
e.pd.eval()
:
#df_sq['收入']=pd.eval("(df_sq.销售-df_sq.退货 )*df_sq.90天均价/100")
#报错,【df_sq.90天均价】写法错误
f.其它
原则上可以通过以上方法构建大部分公式获得新列,但是pandas提供了许多原生的方法,比如计算环比的方法pct_change()
就是用本项减去上一项的差除以上一项,含义就是变动百分比,比自定义函数方便,这些方法工作中注意积累。
df['ret'] = df['Close'].pct_change(1)
df.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=False, observed=False, **kwargs)
df.groupby(by=['brand_supplier','shop_name'])
注意 :对于多重分组,如果但凡一个分组依据列有空值,那么分组后所有涉及该空值所在组都会被删除,因此在多重分组之前,最后在这几列空值填充一下
df_cont[['作者ID','作者身份','文章类型']]=df_cont[['作者ID','作者身份','文章类型']].fillna('缺失')
df_contf=df_cont.groupby(by=['文章ID','作者ID','作者身份','文章类型']).sum()[['曝光量','浏览量']].reset_index()
DataFrameGroupBy.函数()
df.groupby(by=['brand_supplier','shop_name']).sum()
DataFrameGroupBy.函数()[列名]
/
DataFrameGroupBy[列名].函数()
ser_nor=df_nor.groupby('brand_supplier').count()['shop_name']
或者
ser_nor=df_nor.groupby('brand_supplier')['shop_name'].count()
#多指标
ser_nor=df_nor.groupby('brand_supplier')[['shop_name','fuid']].count()
orders.groupby('User')['Total_price'].sum().sort_values(ascending=False)[0:10]
参考:【Python数据科学手册】Pandas——六、层级索引
groupby后,by字段会变成index,如果需要转成正常列,操作如下
索引转列reset_index()
df_nor=df.groupby(by=['brand_supplier','shop_name']).sum().reset_index()
#'brand_supplier','shop_name'原本是index,转成正常列侯,也由Series变成了dataframe
列转索引set_index()
unstack
df_plat_order.groupby(by=['分部','开单挂零']).agg({'公司名':'count'}).unstack()
stack
参考:【Python数据科学手册】Pandas——六、层级索引
也可以考虑使用数据透视表功能
参考:【Python数据科学手册】Pandas——十、数据透视表 df. pivot_table
df_plat_order.groupby(by=['分部','开单挂零']).agg({'公司名':'count','实际支付金额':sum}).unstack()
df_plat_order.pivot_table(index='分部',columns='开单挂零',aggfunc={'公司名':'count','实际支付金额':sum})
pd.to_excel()
ser.to_excel()
ser[ser!=0].to_excel('G:\\work files\\file.xlsx',encoding='utf')
df[df['amount']!=0].to_excel('G:\\work files\\file.xlsx',encoding='utf')
如果多个df或series保存到同一个excel的不同sheet,需要用到pd.ExcelWriter()
作为存储目标
with pd.ExcelWriter('G:\\work files\\work_from_20\\'+filename+'.xlsx') as exf:
df_a.to_excel(exf,sheet_name='编辑',index=False)
df_b.to_excel(exf,sheet_name='优质用户',index=False)
impoert os
filepath='文件存放路径'
newfile_name='带后缀的完整文件名'
i=0
while newfile_name in os.listdir(filepath):#如果当前路径已经存在文件
i=i+1#指定增序
newfile_name='文件名'+'('+str(i)+')'+'.xlsx'#要保存的文件重命名:在文件名后加序号
#循环至没有同名文件
newfile=filepath+'\\'+ newfile_name#要保存的完整路径文件名
df.to_excel(newfile,index=None)
df.to_sql(name, con, schema=None, if_exists='fail', index=True, index_label=None, chunksize=None, dtype=None)
官方文档:pandas.DataFrame.to_sql
关于con参数,文档中写到如下,这意味着,con只支持sqlalchemy.engine和sqlite3.Connection。
使用SQLAlchemy可以使用该库支持的任何数据库。 为sqlite3.Connection对象提供了旧版支持。
con :sqlalchemy.engine.(Engine or Connection) or sqlite3.Connection
如果需要指定数据类型,会用到dtype参数,参考Python sqlalchemy.types模块,常用函数和类
sqllite3
import sqlite3
with sqlite3.connect('test.sqlite') as conn:
df.to_sql(name = 'employee', con = conn, if_exists='replace', index = None)
mysql
from sqlalchemy import create_engine
connect_info = 'mysql+pymysql://root:123456@localhost:3306/mytest'
engine=create_engine(connect_info)
df.to_sql('product', con = engine, if_exists='replace', index=None)
oracle
参考: sqlalchemy.exc.DatabaseError: (cx_Oracle.DatabaseError) ORA-12505: TNS: 监听程序当前无法识别连接描述符中所给出的 SID
import cx_Oracle
from sqlalchemy import create_engine
dnsStr=cx_Oracle.makedsn('localhost', '1521', service_name='orcl.16.2.133')
connect_info = 'oracle://scott:tiger@%s' %(dnsStr)
engine=create_engine(connect_info)
df.to_sql('product', con = engine, if_exists='replace', index=None)
插入拼接列
并剔除有多个shop_name的brand_supplier重复数据
import sys
def main(inda):
import pandas as pd
df=pd.read_csv('G:\\temp files\\file.csv',encoding='utf')
#插入新字段
brand_supplier=df['brand_name'].str.cat(df['supplier_name'])#拼接两个字段成一个新字段
df.insert(7,'brand_supplier',brand_supplier)#插入新字段到dataframe
#删除“华鼎”系列重复项
del_col=df[(df.brand_supplier.str.contains('.*华鼎.*'))&(df.shop_name!='XXXTRENTA')].index#获取要删除数据的索引号(品牌供应商名包含“华鼎”且店铺不为"XXXTRENTA")
df.drop(del_col,axis=0,inplace=True)#删除获得的索引号所在行记录
#获得有重复店铺数据的品牌供应商
df_nor=df.groupby(by=['brand_supplier','shop_name']).sum().reset_index()#多维度分组,随意指定一个计算行数sum(),方便将index'brand_supplier','shop_name'转为DataFrame普通列
ser_nor=df_nor.groupby('brand_supplier').count().shop_name#取到分组序列,索引号是分组依据字段'brand_supplier'
dup_list=list(ser_nor[ser_nor>1].index)#筛选计数大于1即店铺有多个的'brand_supplier'的列表
#删除多余店铺
for bs in dup_list:
shnm_list=list(df[df.brand_supplier==bs].groupby('shop_name').count().reset_index().shop_name)#多店铺的brand_supplier下的各shop_name列表
brnm=df[df.brand_supplier==bs].brand_name.iloc[0]#brand_supplier对应的brand_name(唯一),所以只要取一个就行
#逻辑:如果多个店铺名中至少有跟品牌同名的,那就将该brand_supplier下店铺名不等于品牌的数据删掉(保留店铺名与品牌有同名关系的店铺)
if brnm.lower() in [shlw.lower() for shlw in shnm_list]:#忽略大小写需要同时转大写或小写才能比较
for sn in shnm_list:#将shop_name和brand_name对比
if sn.lower()!=brnm.lower():#如果shop_name和brand_name不能完全相等
del_col_sh=df[(df.brand_supplier==bs)&(df.shop_name==sn)].index#那就找到该brand_supplier下的该shop_name
df.drop(del_col_sh,axis=0,inplace=True)#删除
#逻辑:如果店铺名没有一个与品牌名同名,那就只保留subcategory不为空的店铺
else:
list_type=['运动','美妆','男装','女装'']
del_col_su=df[(df.brand_supplier==bs)&(~df['subcategory'].isin(list_type))].index#找到该brand_supplier下subcategory不为列表中项的数据,就是subcategory空
df.drop(del_col_su,axis=0,inplace=True)
#导出所需透视图
df.subcategory=df.subcategory.fillna('其它')#空值和关店改成其它
df.loc[df.subcategory=='关店','subcategory']='其它'
ser=df.groupby(['shop_name','subcategory']).sum().amount#df.groupby(['shop_name','subcategory'])['amount'].sum()
ser[ser!=0].to_excel('G:\\work files\\file'+str(inda)+'.xlsx',encoding='utf')#取值为不为0的项
if __name__=='__main__':
main(sys.argv[1])