Pandas数据分析常用数据操作(3年总结)

原创文章,转载请注明来源,谢谢

导入设置

import odps
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']     # matplotlib画图中文支持
plt.rcParams['axes.unicode_minus']=False    # matplotlib画图中文支持
import seaborn as sns
%config InlineBackend.figure_format = 'svg'   # 显示矢量图,使图形看起来更加清晰
%matplotlib inline  # plot之后显示图形

显示设置

#显示所有列
pd.set_option('display.max_columns', None)
#最多显示100列
pd.set_option('max_columns',100) 
#显示所有行
pd.set_option('display.max_rows', None)
#最多显示100行
pd.set_option(‘max_row’,100) 
# 设置最大行宽
pd.set_option('max_colwidth',100)
# 设置浮点数小数点后位数
pd.set_option(‘display.float_format’, lambda x: ‘%.2f’ % x)

调用帮助

help(pd.Series.loc)

获取文件当前路径

import os
# print '获取当前目录'
print(os.getcwd())

# print '获取上级目录'
print(os.path.abspath(os.path.join(os.getcwd(), "..")))

# print '获取上上级目录'
print(os.path.abspath(os.path.join(os.getcwd(), "../..")))

# 输出
/Users/eleme/Documents/Documents/code/100-Days-Of-ML-Code-master/Code
/Users/eleme/Documents/Documents/code/100-Days-Of-ML-Code-master
/Users/eleme/Documents/Documents/code

输入输出

读写csv

# 从当前文件夹子文件夹data中读取,设置index列为team_id
df_kpi = pd.read_csv('data/team_KPI_data.csv',index_col='team_id') 
pd.read_csv('file.csv', header=None, nrows=5) # 数据没有字段标题(第一行当数据,读取5行) 
df.to_csv(path_or_buf = "df.csv",encoding = 'GBK') # df导出到df.csv文件,导出文件在当前文件夹下 

读写excel文件

# 读写单个excel文件
pd.read_excel('file.xlsx')
pd.to_excel('dir/myDataFrame.xlsx', sheet_name='Sheet1')
# 涉及到中文字符到读写
write = pd.ExcelWriter('file_name.xlsx')
df.to_excel(write,sheet_name='sheet_name',index=False,encoding = 'gbk')
write.save()
# 读取多个excel文件,同一个excel file不同的sheet
df1 = pd.read_excel('file_name.xlsx', sheet_name = 'sheetname')
df2 = pd.read_excel('file_name.xlsx', sheet_name = 'sheetname')

xlsx = pd.ExcelFile('file.xls')
df = pd.read_excel(xlsx, 'Sheet1')

表信息查看

df.shape() # 行,列数
df.index() # 获取index
df.columns #获取列
df.info() # 显示dataframe行数、个字段格式,内存占用
df.head() # 显示表前5行数据
df.count() # 非NA值到数量
df.describe() # 显示数值型字段最大值、最小值、均值、25%,50%,75%分位数

数据操作

数据类型转换

# 不同数据类型的字段无法进行join
df["team_id"] = df["team_id"].astype("int") # 将字段team_id格式转换为int
df['team_id']=df['team_id'].apply(str) # 将team_id格式转换为string

浮点数保留2位小数点

# 将价格保留2位小数点
df['价格'] = round(df['价格'], 2)
format = lambda x:'%.2f' % x
df['价格'].applymap(format)

字段重命名

df = df.rename(columns = {'index':'team_id'}) #将字段名index 重命名为 team_id
# 多个字段重命名
df = df.rename(columns = {'index':'team_id','A':'B'}) #将字段名index/A 重命名为 team_id/B

将多级列名转换为一级列名

如下图,聚合后列有多级列名,需要转化为一级列名

level0 = df.columns.get_level_values(0)
level1 = df.columns.get_level_values(1)
df.columns = level0 + '_' + level1
df = df_kpi_team_avg.reset_index()

表连接pd.merge(横向连接)

# merge方法适用于使用列或者index作为连接对象,只能做横向连接

# 表df1/df2 通过字段team_id连接,连接方式可以选择outer/left/right
df = pd.merge(df1,df2, on = 'team_id',how = "inner") 
# 表df1/df2 通过字段两个字段team_id和ds连接
df = pd.merge(df1,df2, on = ['team_id','ds'],how = "inner")
# 表df1/df2 通过字段df1 字段team_id_A和ds_A和df2字段team_id_B和ds_B连接,left_on,right_on字段保持一致
df = pd.merge(df1,df2, left_on = ['team_id_A','ds_A'],right_on = ['team_id_B','ds_B'],how = "inner")
# df1和df2表字段名不相同,连接后只保留一个字段名
pd.merge(df1,df2,left_on = 'team_id_A',right_on = 'team_id_B',how = "inner").drop(columns='team_id_B')

# 连接字段是index等情况,假设team_id为index列
df = pd.merge(df1,df2, left_index = True,right_on = True,how = "inner")


# 两个字段相同的表,除重叠值列,其余列加上后缀
# suffixes参数:字符串列表的元组,重叠列名后缀
left = pd.DataFrame({'k': ['K0', 'K1', 'K2'], 'v': [1, 2, 3]})
right = pd.DataFrame({'k': ['K0', 'K0', 'K3'], 'v': [4, 5, 6]})
    
result = pd.merge(left, right, on='k')
result1 = pd.merge(left, right, on='k', suffixes=['_l', '_r'])
    
left            right           result                 result1
 
    k  v            k  v            k  v_x  v_y            k  v_l  v_r
0  K0  1        0  K0  4        0  K0    1    4        0  K0    1    4
1  K1  2        1  K0  5        1  K0    1    5        1  K0    1    5
2  K2  3        2  K3  6
    
left = left.set_index('k')
right = right.set_index('k')
result = left.join(right, lsuffix='_l', rsuffix='_r')
    
# left       right         v_l  v_r
    v          v      k
k           k         K0    1  4.0
K0  1      K0  4      K0    1  5.0
K1  2      K0  5      K1    2  NaN
K2  3      K3  6      K2    3  NaN

多表merge

# 需要将df1, df2, df3, df4, df5 通过商圈id merge起来

from functools import reduce
dfs = [df1, df2, df3, df4, df5]
df_district = reduce(lambda left,right: pd.merge(left,right,on='商圈id'), dfs)

表连接pd.concat(纵向连接,横向连接)

# concat方法只适用于index之间等连接,如果index出现重复则报错,默认outer join
# 纵向连接
# df_2016,df_2017分别为两个字段结构相同的dataframe
# df_2016
        Shares  Low  High
Symbol                   
AAPL        80   95   110
TSLA        50   80   130
WMT         40   55    70
# df_2017
         Shares  Low  High
Symbol                   
AAPL        50  120   140
GE         100   30    40
IBM         87   75    95
SLB         20   55    85
TXN        500   15    23
TSLA       100  100   300
s_list =[df_2016,df_2017]
df = pd.concat(s_list,keys=['2016','2017'],names=['Year'])
#输出结果
             Shares  Low  High
Year Symbol                   
2016 AAPL        80   95   110
     TSLA        50   80   130
     WMT         40   55    70
2017 AAPL        50  120   140
     GE         100   30    40
     IBM         87   75    95
     SLB         20   55    85
     TXN        500   15    23
     TSLA       100  100   300

df.reset_index()
# 横向连接
pd.concat(s_list, join='inner', keys=['2016', '2017'], axis='columns', names='Year')
Year     2016            2017          
       Shares Low High Shares  Low High
Symbol                                 
AAPL       80  95  110     50  120  140
TSLA       50  80  130    100  100  300

去除重复值

team_id = df['team_id'].drop_duplicates()

利用字段生成无重复列表

team_id = df['team_id'].drop_duplicates() 
team_id_list = team_id.tolist()

列表转换为dataframe

利用list1,coef,intercept三个列表生成字段名分别为 team_id,beta,alpha到dataframe
c = {"team_id" : list1,
   "beta"  : coef,
   "alpha" : intercept}
df = pd.DataFrame(c)

运用函数

# 对每个单元格运用函数map(), apply()

# 实现:当单元格值小于0时,取0.005,大于0.01时取0.01,其他情形取单元格值本身
def func(x):
    if x < 0:
        return 0.0005
    elif x >= 0.01:
        return 0.01
    else:
        return x
df['beta']  = df.beta.map(func)  # 或 df['beta']  = df.beta.apply(func)

# 改为lambda函数,更简洁
df['beta'] = df.apply(lambda x: 0.0005 if x['beta'] < 0 else (0.01 if x['beta']>=0.01 else x)))

数据分组聚合为Series,并转化为dataframe

group_cols = '城市'
s = df.groupby(group_cols)['用户T超时率'].agg('mean') # 将df按城市分组求用户超时率均值,结果为series
# 将序列转换为dataframe
df = s.reset_index(name = '城市_用户T超时率') # 将df转换为dataframe,列名为'城市_用户T超时率'

# 对多列进行不同对聚合计算
group_cols = ['大区','城市']
agg_dict = {'KPI得分':['mean','max','min'],'KPI-gap':'mean'} 
df_x = df_kpi.groupby(group_cols).agg(agg_dict) # KPI得分列进行'mean','max','min'聚合运算,'KPI-gap'进行'mean'聚合运算

# 数据分组计算,聚合数值mapping到每一行(原表不聚合)
产地  价格  数量  水果  类别
0   美国   5   5  苹果  水果
1   中国   5   5   梨  水果
2   中国  10   9  草莓  水果
3   中国   3   3  番茄  蔬菜
4  新西兰   3   2  黄瓜  蔬菜
5  新西兰  13  10  羊肉  肉类
6   美国  20   8  牛肉  肉类

# 对价格按类别求平均,然后将平均值mapping到没一行

df['平均价格'] = df.groupby('类别')['价格'].transform(np.mean)
产地  价格  数量  水果  类别 平均价格
0   美国   5   5  苹果  水果	6.66
1   中国   5   5   梨  水果	6.66
2   中国  10   9  草莓  水果	6.66
3   中国   3   3  番茄  蔬菜	3.00
4  新西兰   3   2  黄瓜  蔬菜	3.00
5  新西兰  13  10  羊肉  肉类 16.50
6   美国  20   8  牛肉  肉类	16.50

数据分组聚合,计算列加权平均值

In [194]: list = ['a']* 4 + ['b'] * 6

In [195]: list
Out[195]: ['a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'b', 'b']

In [196]: df = DataFrame({'category' : list,
     ...:                 'data': np.random.randn(10),
     ...:                 'weights': np.random.rand(10)})

In [197]: df
Out[197]:
  category      data   weights
0        a -0.223955  0.017115
1        a  0.627805  0.204209
2        a -0.895798  0.904739
3        a  1.254223  0.551053
4        b -1.024985  0.904737
5        b -0.027101  0.263672
6        b -2.501462  0.364224
7        b  0.008169  0.805655
8        b  1.603461  0.630892
9        b -1.099844  0.596945

In [198]: grouped = df.groupby('category')

In [199]: get_wavg = lambda g : np.average(g['data'],weights=g['weights'])

In [200]: grouped.apply(get_wavg)
Out[200]:
category
a    0.003011
b   -0.416120
dtype: float64

数据分组聚合,不重复计数

# 统计不同省份门店的数量
df.groupby(["省份"]).agg({"门店编号":pd.Series.nunique})

排序

df.sort_index() #按索引排序
df.sort_values(by='country') # df按列country进行排序

计算分位数

# 计算某一列每个单元格数值的分位数
df['PCNT_超时率'] = df['超时率'].rank(method='max',pct=True)

# 计算某个分位数的值
data.price.quantile([0.25,0.5,0.75])
//输出
0.25  42812.25
0.50  57473.00
0.75  76099.75

缺失值填充

# 缺失值行查看
df.isnull().sum(axis=0) # 缺失值行数统计
df[df.isnull()] # 查看包含缺失值值的行
df[df['A'].isnull()] # 查看A列包含缺失值值的行
df[df.isnull().values==True].drop_duplicates() # 查看包含缺失值值的行,去除重复值

# 缺失值填充
df.fillna({"goodcase_cnt":0,"badcase_cnt":0}) # 将goodcase_cnt/badcase_cnt缺失值填为0

# 使用字典对不同列按不同值进行填充
values={"goodcase_cnt":10,"badcase_cnt":20} 
df.fillna(value=values) # goodcase_cnt列缺失值按10填充,badcase_cnt列缺失值按20填充

df.fillna(df.mean()) # 用每列对均值进行填充
df['A'].fillna(df['A'].mean())# 只对column A 进行填充
df.fillna(method='bfill') # 用每列相邻后面(back)的值进行填充
df.fillna(method='ffill') # 用每列相邻前面(forward)的值进行填充

数据替换

df.replace("a","f") # 用f替换a
# 正则表达式替换
# 将sold_price中的"$",",","-",替换为空格
df = pd.DataFrame({'price': ['$10,000', '--', '$2', '$3', '$4'],
                   'B': [5, 6 ,'', 8, 9],
                   'C': ['a', 'b', 'c', 'd', 'e']})
price	    B	C
0	$10,000	5	a
1	--	6	b
2	$2,000		c
3	$3,000	8	d
4	$4,000	9	e

df[sold_price] = df[sold_price].replace(r'[$,-]','', regex=True)

0    10000
1         
2     2000
3     3000
4     4000

# 将空字符替换为np.nan,\s表示空字符,^表示以空字符开头,$表示结束,*表示0个或者多个字符
df['B'].replace(r'^\s*$',np.nan,regex=True).astype(float)

0    5.0
1    6.0
2    NaN
3    8.0
4    9.0
Name: B, dtype: float64 

数据分箱

#将列'maxload'按-20,-18,-16...20进行分组
pd.cut(df['maxload'],bins = range(-20,20,2)) 
pd.cut(df['maxload'],bins = (0,5,10,15,20)) #将列'maxload'按0,5,10,15,20进行分组

分组百分比

# 将'current_load'按'tracking_count'求百分比
df.groupby('current_load')['tracking_count'].sum()/df['tracking_count'].sum()

# 计算某一列不同数值的计数百分比
df.groupby('收货城市')['订单时段'].value_counts(normalize=True)

重复数据

# s为Series,返回唯一值
s.unique() # 对于一维数组或者列表,unique函数去除其中重复的元素,并按元素由大到小返回一个新的无元素重复的元组或者列表
df.duplicated('Type') # 查找字段Type重复值,结果返回Type列每个单元格True or False
df.drop_duplicates('Type',keep='last')
df.index.duplicated() # 查找重复索引

设置/取消索引

df.set_index('Country') # 将Country设置为df对index
df.reset_index() # 取消索引

数据透视表pivot

'''
pandas.pivot_table(data, values=None, index=None, columns=None, aggfunc='mean',
fill_value=None, margins=False, dropna=True, margins_name='All', observed=False, sort=True)

'''
table = pd.pivot_table(df,index=['shop_city_name'],columns=['distance','test_type'],
values=['基配'])
round(table,2)

数据子集选择

列选择

# 字段标签方法
df['team_id']
df['team_id','city_name','kpi_score']
# loc方法
df.loc['team_id']
# iloc方法, 只接受整数输入
df.iloc[:,1] # 选择第2列

行选择

# 布尔值方法,dataframe
df[df['team_id']==1034] # 取team_id为1034的行,主要“==“
df[df['team_id'].isin(['162586803','135330914']) # 选择多个值
df[(df['city_name']=='上海') & (df['kpi_score']>=80)] # 满足两个字段的布尔方法

# 布尔值方法,Series
s1[s1>=80] # 选取s1中值大于80的元素

# loc方法,loc的值必须为index列的值,比如假设team_id列为index列,
df.loc['1034'] # 选择team_id为1034的行,选择行可以省略逗号,等价于df.loc['1034',:]
df.loc['1034','1035'] # 选择team_id为1034,1035的行
labels = ['University of Alaska Anchorage','International Academy of Hair Design','University of Alabama in Huntsville']
college.loc[labels] #选择index 列为三所大学的行
 
# iloc方法, 只解释整数输入
df.iloc[1,:] # 选择第2行,只选择行可以没有逗号,等价于df.iloc[1]
df.iloc[1,3,5] # 选择第2,4,6行

# query方法
df.query('team_id == 1034')
df.query("age>12 and sex=='male'")


# 对由dataframe 产生对series取出其值,如根据team_id获取商圈id,然后根据商圈id显示所有team_id

df[df['站点id']==team_id]['business_district_id']

# 对于从df中取得的series,如果只有1行,但是行序号是原df中对序号,而不是0,比如,78,1017,因此1017不能通过s[0]访问,需要使用s.iloc[0]
 

同时选择行列

# iloc方法,只接受整数输入
 >>> college.iloc[:3, :4] # 选择1-3行,1-4列
 >>> college.iloc[:, [4,6]] #选择5-6列
 >>> college.iloc[[100, 200], [7, 15]] # 选择99-199行,第8-15列
# iat方法,和iloc基本类似

# loc方法,只接受index列的值输入
>>> college.loc[:'Amridge University', :'MENONLY'] #选择1-'Amridge University'行,1-'MENONLY'列
>>> college.loc[:, ['WOMENONLY', 'SATVRMID']] #选择'WOMENONLY'到'SATVRMID'列
>>> rows = ['GateWay Community College','American Baptist Seminary of the West']
>>> columns = ['SATMTMID', 'UGDS_NHPI']
>>> college.loc[rows, columns]
## 利用get_loc方法
>>> col_start = college.columns.get_loc('UGDS_WHITE')
>>> col_end = college.columns.get_loc('UGDS_UNKN') + 1
>>> college.iloc[:5, col_start:col_end]
#at方法,和loc方法基本类似

删除列

drop_columns=['beta','alpha']
df_kpi_public = df_kpi.drop(columns = drop_columns) #去除'beta','alpha'列

删除行

# 删除空值行
df.dropna(inplace=True) #去除包含至少一个na值的行,只要有一个na,则该行drop掉
df.dropna(how='all') #去除所有值都为na值的行
df.dropna(thresh=2) #去除包含两个及以上na值的行
df.dropna(subset = ['考核周期订单量'],inplace=True) # 去除'考核周期订单量'列为空值的行
df.drop(['a', 'c']) # 删除索引为'a', 'c'对行
data[~(data['开关机状态'].isin(['关']) & data['水流量'].isin([0]))] #删除掉开关机状态为“关”且水流量为0的数据,说明热水器不处于工作状态
  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值