Python——第7章 pandas数据分析实战
7.1pandas常用数据类型
7.1.1一维数组与常用操作
import pandas as pd
import matplotlib.pyplot as plt
#设置输出结果对齐方式
pd.set_option('display.unicode.ambiguous_as_wide',True)
pd.set_option('display.unicode.east_asian_width',True)
#自动创建从0开始的非负整数索引
s1=pd.Series(range(1,20,5))
#使用字典创建Series,使用字典的“键”作为索引
s2=pd.Series({'语文':90,'数学':92,'Python':98,'物理':87,'化学':92})
#修改指定索引对应的值
s1[3]=-17
s2['语文']=94
print('s1原始数据'.ljust(20,'='))
print(s1)
s1原始数据==============
0 1
1 6
2 11
3 -17
dtype: int64
print('对s1所有数据求绝对值'.ljust(20,'='))
print(abs(s1))
对s1所有数据求绝对值=========
0 1
1 6
2 11
3 17
dtype: int64
print('s1所有的值加5'.ljust(20,'='))
print(s1+5)
s1所有的值加5============
0 6
1 11
2 16
3 -12
dtype: int64
print('s1的每行索引前面加上数字2'.ljust(20,'='))
print(s1.add_prefix(2))
s1的每行索引前面加上数字2======
20 1
21 6
22 11
23 -17
dtype: int64
print('s2原始数据'.ljust(20,'='))
print(s2)
s2原始数据==============
语文 94
数学 92
Python 98
物理 87
化学 92
dtype: int64
print('s2数据的直方图'.ljust(20,'='))
s2.hist()
plt.show()
s2数据的直方图============
https://images.cnblogs.com/cnblogs_com/blogs/792292/galleries/2312424/t_230524125723_output_8_1.png
print('s2的每行索引后面加上_张三'.ljust(20,'='))
print(s2.add_suffix('_张三'))
s2的每行索引后面加上_张三======
语文_张三 94
数学_张三 92
Python_张三 98
物理_张三 87
化学_张三 92
dtype: int64
print('s2最大值的索引'.ljust(20,'='))
print(s2.idxmax())
s2最大值的索引============
Python
print('测试s2的值是否在指定区间内'.ljust(20,'='))
print(s2.between(90,94,inclusive=True))
测试s2的值是否在指定区间内======
语文 True
数学 True
Python False
物理 False
化学 True
dtype: bool
print('查看s2中大于中值的数据'.ljust(20,'='))
print(s2[s2>s2.median()])
查看s2中大于中值的数据========
语文 94
Python 98
dtype: int64
print('查看s2中90分以上的数据'.ljust(20,'='))
print(s2[s2>90])
查看s2中90分以上的数据=======
语文 94
数学 92
Python 98
化学 92
dtype: int64
print('s2与数字之间的运算'.ljust(20,'='))
print(round((s2**0.5)*10,1))
s2与数字之间的运算==========
语文 97.0
数学 95.9
Python 99.0
物理 93.3
化学 95.9
dtype: float64
print('s2的中值'.ljust(20,'='))
print(s2.median())
s2的中值===============
92.0
print('s2中最小的2个值'.ljust(20,'='))
print(s2.nsmallest(2))
s2中最小的2个值===========
物理 87
数学 92
dtype: int64
#两个等长Series对象之间可以进行四则运算和幂运算
#只对两个Series对象中都有的索引对应的值进行计算
#非共同索引对应的值为空值NaN
print('两个Series对象相加'.ljust(20,'='))
print(pd.Series(range(5))+pd.Series(range(5,10)))
两个Series对象相加========
0 5
1 7
2 9
3 11
4 13
dtype: int64
print('每个值的平方对5的余数'.ljust(20,'='))
print(pd.Series(range(5)).pipe(lambda x,y,z:(x**y)%z,2,5))
每个值的平方对5的余数=========
0 0
1 1
2 4
3 4
4 1
dtype: int64
print('每个值加3之后再乘以3'.ljust(20,'='))
print(pd.Series(range(5)).pipe(lambda x:x+3).pipe(lambda x:x*3))
每个值加3之后再乘以3=========
0 9
1 12
2 15
3 18
4 21
dtype: int64
print('每个值加3'.ljust(20,'='))
print(pd.Series(range(5)).apply(lambda x:x+3))
每个值加3===============
0 3
1 4
2 5
3 6
4 7
dtype: int64
print('标准差、无偏方差、无偏标准差'.ljust(20,'='))
print(pd.Series(range(5)).std())
print(pd.Series(range(5)).var())
print(pd.Series(range(5)).sem())
标准差、无偏方差、无偏标准差======
1.5811388300841898
2.5
0.7071067811865476
print('查看是否存在等价于True的值'.ljust(20,'='))
print(any(pd.Series([3,0,True])))
查看是否存在等价于True的值=====
True
print('查看是否所有值都等价于True'.ljust(20,'='))
print(all(pd.Series([3,0,True])))
查看是否所有值都等价于True=====
False
7.1.2时间序列与常用操作
时间序列对象一般使用pandas的date_range()函数生成,可以指定日期时间的起始和结束范围、时间间隔以及数据数量等参数,语法为:
date_range(start=None, end=None, periods=None,freq='D', tz=None, normalize=False,name=None, closed=None, **kwargs)
stard指定起始日期,end指定结束日期,periods指定生成的数据数量
freq指定时间间隔,D表示天,W表示周,H表示小时
M表示月末最后一天,MS表示月初第一天
T表示分钟,Y表示年末最后一天,YS表示年初第一天
print('间隔5天')
print(pd.date_range(start='20190601',end='20190630',freq='5D'))
间隔5天
DatetimeIndex(['2019-06-01', '2019-06-06', '2019-06-11', '2019-06-16',
'2019-06-21', '2019-06-26'],
dtype='datetime64[ns]', freq='5D')
print('间隔1周')
print(pd.date_range(start='20190601',end='20190630',freq='W'))
间隔1周
DatetimeIndex(['2019-06-02', '2019-06-09', '2019-06-16', '2019-06-23',
'2019-06-30'],
dtype='datetime64[ns]', freq='W-SUN')
print('间隔2天,5个数据')
print(pd.date_range(start='20190601',periods=5,freq='2D'))
间隔2天,5个数据
DatetimeIndex(['2019-06-01', '2019-06-03', '2019-06-05', '2019-06-07',
'2019-06-09'],
dtype='datetime64[ns]', freq='2D')
print('间隔3小时,8个数据'.ljust(30,'='))
print(pd.date_range(start='20190601',periods=8,freq='3H'))
间隔3小时,8个数据====================
DatetimeIndex(['2019-06-01 00:00:00', '2019-06-01 03:00:00',
'2019-06-01 06:00:00', '2019-06-01 09:00:00',
'2019-06-01 12:00:00', '2019-06-01 15:00:00',
'2019-06-01 18:00:00', '2019-06-01 21:00:00'],
dtype='datetime64[ns]', freq='3H')
print('3:00开始,间隔1分钟,12个数据')
print(pd.date_range(start='201906010300',periods=12,freq='T'))
3:00开始,间隔1分钟,12个数据
DatetimeIndex(['2019-06-01 03:00:00', '2019-06-01 03:01:00',
'2019-06-01 03:02:00', '2019-06-01 03:03:00',
'2019-06-01 03:04:00', '2019-06-01 03:05:00',
'2019-06-01 03:06:00', '2019-06-01 03:07:00',
'2019-06-01 03:08:00', '2019-06-01 03:09:00',
'2019-06-01 03:10:00', '2019-06-01 03:11:00'],
dtype='datetime64[ns]', freq='T')
print('间隔1月,月末最后一天')
print(pd.date_range(start='20190101',end='20191231',freq='M'))
间隔1月,月末最后一天
DatetimeIndex(['2019-01-31', '2019-02-28', '2019-03-31', '2019-04-30',
'2019-05-31', '2019-06-30', '2019-07-31', '2019-08-31',
'2019-09-30', '2019-10-31', '2019-11-30', '2019-12-31'],
dtype='datetime64[ns]', freq='M')
print('间隔1年,6个数据,年末最后一天')
print(pd.date_range(start='20190101',periods=6,freq='A'))
间隔1年,6个数据,年末最后一天
DatetimeIndex(['2019-12-31', '2020-12-31', '2021-12-31', '2022-12-31',
'2023-12-31', '2024-12-31'],
dtype='datetime64[ns]', freq='A-DEC')
print('间隔1年,6个数据,年初第一天')
print(pd.date_range(start='20190101',periods=6,freq='AS'))
间隔1年,6个数据,年初第一天
DatetimeIndex(['2019-01-01', '2020-01-01', '2021-01-01', '2022-01-01',
'2023-01-01', '2024-01-01'],
dtype='datetime64[ns]', freq='AS-JAN')
#使用日期时间做索引,创建Series对象
data=pd.Series(index=pd.date_range(start='20190701',periods=24,freq='H'),data=range(24))
print('前5条数据')
print(data[:5])
前5条数据
2019-07-01 00:00:00 0
2019-07-01 01:00:00 1
2019-07-01 02:00:00 2
2019-07-01 03:00:00 3
2019-07-01 04:00:00 4
Freq: H, dtype: int64
print('3小时重采样,计算均值')
print(data.resample('3H').mean())
3小时重采样,计算均值
2019-07-01 00:00:00 1
2019-07-01 03:00:00 4
2019-07-01 06:00:00 7
2019-07-01 09:00:00 10
2019-07-01 12:00:00 13
2019-07-01 15:00:00 16
2019-07-01 18:00:00 19
2019-07-01 21:00:00 22
Freq: 3H, dtype: int64
print('5小时重采样,求和')
print(data.resample('5H').sum())
5小时重采样,求和
2019-07-01 00:00:00 10
2019-07-01 05:00:00 35
2019-07-01 10:00:00 60
2019-07-01 15:00:00 85
2019-07-01 20:00:00 86
Freq: 5H, dtype: int64
print('5小时重采样,统计OHLC值')
print(data.resample('5H').ohlc())
5小时重采样,统计OHLC值
open high low close
2019-07-01 00:00:00 0 4 0 4
2019-07-01 05:00:00 5 9 5 9
2019-07-01 10:00:00 10 14 10 14
2019-07-01 15:00:00 15 19 15 19
2019-07-01 20:00:00 20 23 20 23
print('所有日期替换为第二天')
data.index=data.index+pd.Timedelta('1D')
print(data[:5])
所有日期替换为第二天
2019-07-02 00:00:00 0
2019-07-02 01:00:00 1
2019-07-02 02:00:00 2
2019-07-02 03:00:00 3
2019-07-02 04:00:00 4
Freq: H, dtype: int64
print('查看指定日期是周几')
print(pd.Timestamp('20190323').day_name())
查看指定日期是周几
Saturday
print('查看指定日期时间所在年是否为闰年')
print(pd.Timestamp('201909300800').is_leap_year)
查看指定日期时间所在年是否为闰年
False
print('查看指定日期所在的季度和月份')
day=pd.Timestamp('20191025')
print(day.quarter,day.month)
查看指定日期所在的季度和月份
4 10
print('转换为Python的日期时间对象')
print(day.to_pydatetime())
转换为Python的日期时间对象
2019-10-25 00:00:00
7.1.3二维数组DataFrame
import numpy as np
import pandas as pd
pd.set_option('display.unicode.ambiguous_as_wide',True)
pd.set_option('display.unicode.east_asian_width',True)
df=pd.DataFrame(np.random.randint(1,20,(5,3)),index=range(5),columns=['A','B','C'])
print(df)
A B C
0 9 16 6
1 2 17 1
2 9 5 7
3 16 16 14
4 9 12 1
df=pd.DataFrame(np.random.randint(5,15,(13,3)),
index=pd.date_range(start='201907150900',
end='201907152100',
freq='H'),
columns=['熟食','化妆品','日用品'])
print(df)
熟食 化妆品 日用品
2019-07-15 09:00:00 12 13 10
2019-07-15 10:00:00 6 10 5
2019-07-15 11:00:00 5 13 12
2019-07-15 12:00:00 5 5 12
2019-07-15 13:00:00 13 11 12
2019-07-15 14:00:00 7 6 9
2019-07-15 15:00:00 10 10 13
2019-07-15 16:00:00 14 10 7
2019-07-15 17:00:00 13 14 14
2019-07-15 18:00:00 6 13 9
2019-07-15 19:00:00 7 7 10
2019-07-15 20:00:00 8 9 13
2019-07-15 21:00:00 13 11 5
df=pd.DataFrame({'语文':[87,79,67,92],
'数学':[93,89,80,77],
'英语':[90,80,70,75]},
index=['张三','李四','王五','赵六'])
print(df)
语文 数学 英语
张三 87 93 90
李四 79 89 80
王五 67 80 70
赵六 92 77 75
df=pd.DataFrame({'A':range(5,10),'B':3})
print(df)
A B
0 5 3
1 6 3
2 7 3
3 8 3
4 9 3
7.2DataFrame数据处理与分析实战
7.2.1读取Excel文件中的数据
read_excel(io, sheetname=0, header=0, skiprows=None, skip_footer=0, index_col=None, names=None, parse_cols=None, parse_dates=False, date_parser=None, na_values=None, thousands=None, convert_float=True, has_index_names=None, converters=None, true_values=None, false_values=None, engine=None, squeeze=False, **kwds)
1)参数io用来指定要读取的Excel文件,可以是字符串形式的文件路径、url或文件对象;
2)参数sheetname用来指定要读取的worksheet,可以是表示worksheet序号的整数或表示worksheet名字的字符串,如果要同时读取多个worksheet可以使用形如[0, 1, 'sheet3']的列表,如果指定该参数为None则表示读取所有worksheet并返回包含多个DataFrame结构的字典,该参数默认为0(表示读取第一个worksheet中的数据);
3)参数headers用来指定worksheet中表示表头或列名的行索引,默认为0,如果没有作为表头的行,必须显式指定headers=None;
4)参数skiprows用来指定要跳过的行索引组成的列表;
5)参数index_col用来指定作为DataFrame索引的列下标,可以是包含若干列下标的列表;
6)参数names用来指定读取数据后使用的列名;
7)参数thousands用来指定文本转换为数字时的千分符,如果Excel中有以文本形式存储的数字,可以使用该参数;
8)参数usecols用来指定要读取的列的索引或名字,如果确定字段类型可以使用{'col':type}的形式提高速度;
9)参数na_values用来指定哪些值被解释为缺失值。
import pandas as pd
pd.set_option('display.unicode.ambiguous_as_wide',True)
pd.set_option('display.unicode.east_asian_width',True)
df=pd.read_excel(r'超市营业额2.xlsx')
print(df[:10],end='\n\n')
工号 姓名 日期 时段 交易额 柜台
0 1001 张三 2019-03-01 9:00-14:00 1664.0 化妆品
1 1002 李四 2019-03-01 14:00-21:00 954.0 化妆品
2 1003 王五 2019-03-01 9:00-14:00 1407.0 食品
3 1004 赵六 2019-03-01 14:00-21:00 1320.0 食品
4 1005 周七 2019-03-01 9:00-14:00 994.0 日用品
5 1006 钱八 2019-03-01 14:00-21:00 1421.0 日用品
6 1006 钱八 2019-03-01 9:00-14:00 1226.0 蔬菜水果
7 1001 张三 2019-03-01 14:00-21:00 1442.0 蔬菜水果
8 1001 张三 2019-03-02 9:00-14:00 1530.0 化妆品
9 1002 李四 2019-03-02 14:00-21:00 1395.0 化妆品
df1=pd.read_excel(r'超市营业额2.xlsx',skiprows=[1,3,5],index_col=1)
print(df1[:10])
工号 日期 时段 交易额 柜台
姓名
李四 1002 2019-03-01 14:00-21:00 954.0 化妆品
赵六 1004 2019-03-01 14:00-21:00 1320.0 食品
钱八 1006 2019-03-01 14:00-21:00 1421.0 日用品
钱八 1006 2019-03-01 9:00-14:00 1226.0 蔬菜水果
张三 1001 2019-03-01 14:00-21:00 1442.0 蔬菜水果
张三 1001 2019-03-02 9:00-14:00 1530.0 化妆品
李四 1002 2019-03-02 14:00-21:00 1395.0 化妆品
王五 1003 2019-03-02 9:00-14:00 936.0 食品
赵六 1004 2019-03-02 14:00-21:00 906.0 食品
周七 1005 2019-03-02 9:00-14:00 1444.0 日用品
7.2.2筛选符合特定条件的数据
DataFrame的索引或切片有四大类:
索引单元素:基于标签的at、基于位置的iat
切片columns:用.来切片单列、用[]来切片单列或多列、基于标签的loc、基于位置的iloc
切片index:用[]来切片单行或多行、基于标签的loc、基于位置的iloc
切片index和columns:基于标签的loc、基于位置的iloc
总体规律,基于标签就用at和loc,基于位置就用iat和iloc。
——基于标签at
at()根据行列的名称,查询对应值。
print(df.at[2,'交易额'])
1407.0
——基于位置iat
iat()根据行列的位置编号,查询对应的值
print(df.iat[2,5])
食品
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 249 entries, 0 to 248
Data columns (total 6 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 工号 249 non-null int64
1 姓名 249 non-null object
2 日期 249 non-null object
3 时段 249 non-null object
4 交易额 246 non-null float64
5 柜台 249 non-null object
dtypes: float64(1), int64(1), object(4)
memory usage: 11.8+ KB
df.describe()
工号 | 交易额 | |
---|---|---|
count | 249.000000 | 246.000000 |
mean | 1003.469880 | 1330.313008 |
std | 1.668039 | 904.300720 |
min | 1001.000000 | 53.000000 |
25% | 1002.000000 | 1031.250000 |
50% | 1003.000000 | 1259.000000 |
75% | 1005.000000 | 1523.000000 |
max | 1006.000000 | 12100.000000 |
——单列的选取
如果追求简洁和方便,用.和[];如果追求一致和清晰,用loc和iloc
df1['交易额']
姓名
李四 954.0
赵六 1320.0
钱八 1421.0
钱八 1226.0
张三 1442.0
...
李四 859.0
赵六 1668.0
赵六 1722.0
王五 1274.0
钱八 812.0
Name: 交易额, Length: 246, dtype: float64
df1.loc[:,'交易额']
姓名
李四 954.0
赵六 1320.0
钱八 1421.0
钱八 1226.0
张三 1442.0
...
李四 859.0
赵六 1668.0
赵六 1722.0
王五 1274.0
钱八 812.0
Name: 交易额, Length: 246, dtype: float64
df1.交易额
姓名
李四 954.0
赵六 1320.0
钱八 1421.0
钱八 1226.0
张三 1442.0
...
李四 859.0
赵六 1668.0
赵六 1722.0
王五 1274.0
钱八 812.0
Name: 交易额, Length: 246, dtype: float64
df1.iloc[:,3]
姓名
李四 954.0
赵六 1320.0
钱八 1421.0
钱八 1226.0
张三 1442.0
...
李四 859.0
赵六 1668.0
赵六 1722.0
王五 1274.0
钱八 812.0
Name: 交易额, Length: 246, dtype: float64
——多列的选取
print(df[['姓名','日期','柜台']])
姓名 日期 柜台
0 张三 2019-03-01 化妆品
1 李四 2019-03-01 化妆品
2 王五 2019-03-01 食品
3 赵六 2019-03-01 食品
4 周七 2019-03-01 日用品
.. ... ... ...
244 李四 2019-03-31 蔬菜水果
245 赵六 2019-03-31 日用品
246 赵六 2019-03-31 日用品
247 王五 2019-03-31 食品
248 钱八 2019-03-31 食品
[249 rows x 3 columns]
print(df.loc[:,['姓名','交易额']])
姓名 交易额
0 张三 1664.0
1 李四 954.0
2 王五 1407.0
3 赵六 1320.0
4 周七 994.0
.. ... ...
244 李四 859.0
245 赵六 1668.0
246 赵六 1722.0
247 王五 1274.0
248 钱八 812.0
[249 rows x 2 columns]
print(df.iloc[:,0:2])
工号 姓名
0 1001 张三
1 1002 李四
2 1003 王五
3 1004 赵六
4 1005 周七
.. ... ...
244 1002 李四
245 1004 赵六
246 1004 赵六
247 1003 王五
248 1006 钱八
[249 rows x 2 columns]
——单行的选取
print(df.iloc[5])
工号 1006
姓名 钱八
日期 2019-03-01
时段 14:00-21:00
交易额 1421.0
柜台 日用品
Name: 5, dtype: object
——多行的选取
print(df[5:11])
工号 姓名 日期 时段 交易额 柜台
5 1006 钱八 2019-03-01 14:00-21:00 1421.0 日用品
6 1006 钱八 2019-03-01 9:00-14:00 1226.0 蔬菜水果
7 1001 张三 2019-03-01 14:00-21:00 1442.0 蔬菜水果
8 1001 张三 2019-03-02 9:00-14:00 1530.0 化妆品
9 1002 李四 2019-03-02 14:00-21:00 1395.0 化妆品
10 1003 王五 2019-03-02 9:00-14:00 936.0 食品
print(df.loc[0:5,:])
工号 姓名 日期 时段 交易额 柜台
0 1001 张三 2019-03-01 9:00-14:00 1664.0 化妆品
1 1002 李四 2019-03-01 14:00-21:00 954.0 化妆品
2 1003 王五 2019-03-01 9:00-14:00 1407.0 食品
3 1004 赵六 2019-03-01 14:00-21:00 1320.0 食品
4 1005 周七 2019-03-01 9:00-14:00 994.0 日用品
5 1006 钱八 2019-03-01 14:00-21:00 1421.0 日用品
print(df1.iloc[[3,5,10],:])
工号 日期 时段 交易额 柜台
姓名
钱八 1006 2019-03-01 9:00-14:00 1226.0 蔬菜水果
张三 1001 2019-03-02 9:00-14:00 1530.0 化妆品
钱八 1006 2019-03-02 14:00-21:00 1141.0 日用品
print(df[['姓名','交易额']])
姓名 交易额
0 张三 1664.0
1 李四 954.0
2 王五 1407.0
3 赵六 1320.0
4 周七 994.0
.. ... ...
244 李四 859.0
245 赵六 1668.0
246 赵六 1722.0
247 王五 1274.0
248 钱八 812.0
[249 rows x 2 columns]
——块的选取
print(df1.iloc[[3,5,10],[0,1,4]])
工号 日期 柜台
姓名
钱八 1006 2019-03-01 蔬菜水果
张三 1001 2019-03-02 化妆品
钱八 1006 2019-03-02 日用品
print(df[['姓名','日期','柜台']][:5])
姓名 日期 柜台
0 张三 2019-03-01 化妆品
1 李四 2019-03-01 化妆品
2 王五 2019-03-01 食品
3 赵六 2019-03-01 食品
4 周七 2019-03-01 日用品
print(df.loc[[3,5,10],['姓名','交易额']])
姓名 交易额
3 赵六 1320.0
5 钱八 1421.0
10 王五 936.0
——根据条件过滤行(布尔索引)
布尔索引就是用一个由布尔类型值组成的数组来选择元素的方法。
print(df[df['交易额']>1700])
工号 姓名 日期 时段 交易额 柜台
18 1003 王五 2019-03-03 9:00-14:00 1713.0 食品
47 1005 周七 2019-03-06 14:00-21:00 1778.0 蔬菜水果
48 1003 王五 2019-03-07 9:00-14:00 1713.0 化妆品
82 1006 钱八 2019-03-11 9:00-14:00 1737.0 食品
105 1001 张三 2019-03-14 9:00-14:00 12100.0 日用品
113 1002 李四 2019-03-15 9:00-14:00 1798.0 日用品
121 1002 李四 2019-03-16 9:00-14:00 1788.0 日用品
136 1001 张三 2019-03-17 14:00-21:00 1791.0 食品
185 1004 赵六 2019-03-24 9:00-14:00 1775.0 化妆品
188 1002 李四 2019-03-24 14:00-21:00 1793.0 蔬菜水果
205 1001 张三 2019-03-26 9:00-14:00 1746.0 日用品
223 1003 王五 2019-03-28 9:00-14:00 9031.0 食品
227 1005 周七 2019-03-29 9:00-14:00 1737.0 蔬菜水果
246 1004 赵六 2019-03-31 14:00-21:00 1722.0 日用品
print('张三下午班的交易情况')
print(df[df['时段']=='14:00-21:00'][:10])
张三下午班的交易情况
工号 姓名 日期 时段 交易额 柜台
1 1002 李四 2019-03-01 14:00-21:00 954.0 化妆品
3 1004 赵六 2019-03-01 14:00-21:00 1320.0 食品
5 1006 钱八 2019-03-01 14:00-21:00 1421.0 日用品
7 1001 张三 2019-03-01 14:00-21:00 1442.0 蔬菜水果
9 1002 李四 2019-03-02 14:00-21:00 1395.0 化妆品
11 1004 赵六 2019-03-02 14:00-21:00 906.0 食品
13 1006 钱八 2019-03-02 14:00-21:00 1141.0 日用品
15 1003 王五 2019-03-02 14:00-21:00 1179.0 蔬菜水果
17 1002 李四 2019-03-03 14:00-21:00 1034.0 化妆品
19 1004 赵六 2019-03-03 14:00-21:00 1236.0 食品
print('下午班的交易情况')
print(df[(df.姓名=='张三')&(df.时段=='14:00-21:00')][:10])
下午班的交易情况
工号 姓名 日期 时段 交易额 柜台
7 1001 张三 2019-03-01 14:00-21:00 1442.0 蔬菜水果
39 1001 张三 2019-03-05 14:00-21:00 856.0 蔬菜水果
73 1001 张三 2019-03-10 14:00-21:00 1040.0 化妆品
91 1001 张三 2019-03-12 14:00-21:00 1435.0 食品
99 1001 张三 2019-03-13 14:00-21:00 1333.0 食品
112 1001 张三 2019-03-14 14:00-21:00 1261.0 蔬菜水果
120 1001 张三 2019-03-15 14:00-21:00 1035.0 蔬菜水果
128 1001 张三 2019-03-16 14:00-21:00 1408.0 蔬菜水果
136 1001 张三 2019-03-17 14:00-21:00 1791.0 食品
144 1001 张三 2019-03-18 14:00-21:00 1378.0 食品
print('张三和李四2人销售总额')
print(df[df['姓名'].isin(['张三','李四'])]['交易额'].sum())
张三和李四2人销售总额
116860.0
print('日用品柜台销售总额')
print(df[df['柜台']=='日用品']['交易额'].sum())
日用品柜台销售总额
88162.0
print('交易额在指定范围内的记录')
print(df[df['交易额'].between(800,850)])
交易额在指定范围内的记录
工号 姓名 日期 时段 交易额 柜台
41 1002 李四 2019-03-06 14:00-21:00 822.0 化妆品
55 1002 李四 2019-03-07 14:00-21:00 831.0 蔬菜水果
59 1004 赵六 2019-03-08 14:00-21:00 825.0 食品
86 1003 王五 2019-03-11 9:00-14:00 801.0 蔬菜水果
94 1003 王五 2019-03-12 9:00-14:00 831.0 蔬菜水果
106 1002 李四 2019-03-14 14:00-21:00 822.0 日用品
129 1002 李四 2019-03-17 9:00-14:00 828.0 日用品
132 1006 钱八 2019-03-17 14:00-21:00 840.0 蔬菜水果
137 1002 李四 2019-03-18 9:00-14:00 824.0 化妆品
147 1003 王五 2019-03-19 9:00-14:00 846.0 蔬菜水果
152 1001 张三 2019-03-19 14:00-21:00 844.0 食品
160 1001 张三 2019-03-20 14:00-21:00 829.0 食品
163 1006 钱八 2019-03-21 9:00-14:00 807.0 蔬菜水果
233 1001 张三 2019-03-30 14:00-21:00 850.0 化妆品
248 1006 钱八 2019-03-31 14:00-21:00 812.0 食品
——高级索引(多层索引)
用MultiIndex函数创建「多层index」midx和「多层columns」mcol。
data=[['电商',101550,176.92,16175610],
['电商',175336,25.95,27113291],
['金融',60348,41.79,10132145],
['金融',36600,196.00,2626634]]
midx=pd.MultiIndex([['中国','美国'],['BABA','JD','GS','MS']],
[[0,0,1,1],[0,1,2,3]],
names=['地区','代号'])
mcol=pd.MultiIndex([['公司数据','交易数据'],
['行业','雇员','价格','交易量']],
[[0,0,1,1],[0,1,2,3]],
names=['概括','细分'])
df2=pd.DataFrame(data,index=midx,columns=mcol)
df2
概括 | 公司数据 | 交易数据 | |||
---|---|---|---|---|---|
细分 | 行业 | 雇员 | 价格 | 交易量 | |
地区 | 代号 | ||||
中国 | BABA | 电商 | 101550 | 176.92 | 16175610 |
JD | 电商 | 175336 | 25.95 | 27113291 | |
美国 | GS | 金融 | 60348 | 41.79 | 10132145 |
MS | 金融 | 36600 | 196.00 | 2626634 |
这个DataFrame的index和columns都有两层,严格来说是个四维数据。
df2.loc['中国'].loc['BABA':'JD']
概括 | 公司数据 | 交易数据 | ||
---|---|---|---|---|
细分 | 行业 | 雇员 | 价格 | 交易量 |
代号 | ||||
BABA | 电商 | 101550 | 176.92 | 16175610 |
JD | 电商 | 175336 | 25.95 | 27113291 |
——高级索引(调位level)
如果你不喜欢index level的顺序,可用swaplevel将它们调位。
df2.swaplevel('地区','代号')
概括 | 公司数据 | 交易数据 | |||
---|---|---|---|---|---|
细分 | 行业 | 雇员 | 价格 | 交易量 | |
代号 | 地区 | ||||
BABA | 中国 | 电商 | 101550 | 176.92 | 16175610 |
JD | 中国 | 电商 | 175336 | 25.95 | 27113291 |
GS | 美国 | 金融 | 60348 | 41.79 | 10132145 |
MS | 美国 | 金融 | 36600 | 196.00 | 2626634 |
如果你不喜欢columns level的顺序,也可用swaplevel将它们调位。
df2.columns=df.columns.swaplevel(0,1)
df2
细分 | 行业 | 雇员 | 价格 | 交易量 | |
---|---|---|---|---|---|
概括 | 公司数据 | 公司数据 | 交易数据 | 交易数据 | |
地区 | 代号 | ||||
中国 | BABA | 电商 | 101550 | 176.92 | 16175610 |
JD | 电商 | 175336 | 25.95 | 27113291 | |
美国 | GS | 金融 | 60348 | 41.79 | 10132145 |
MS | 金融 | 36600 | 196.00 | 2626634 |
——高级索引(重设index)
有时候,一个DataFrame的一个或者多个columns适合做index,这时可用set_index将它们设置为index,如果要将index还原成columns,那么用reset_index。
data={'地区':['中国','中国','美国','美国'],
'代号':['BABA','JD','MS','GS'],
'行业':['电商','电商','金融','金融'],
'价格':[176.92,25.95,41.79,196.00],
'交易量':[16175610,27113291,10132145,2626634],
'雇员':[101550,175336,60348,36600]}
df3=pd.DataFrame(data)
df3
地区 | 代号 | 行业 | 价格 | 交易量 | 雇员 | |
---|---|---|---|---|---|---|
0 | 中国 | BABA | 电商 | 176.92 | 16175610 | 101550 |
1 | 中国 | JD | 电商 | 25.95 | 27113291 | 175336 |
2 | 美国 | MS | 金融 | 41.79 | 10132145 | 60348 |
3 | 美国 | GS | 金融 | 196.00 | 2626634 | 36600 |
将「地区」和「代号」设置为第一层index和第二层index。
df4=df3.set_index(['地区','代号'])
df4
行业 | 价格 | 交易量 | 雇员 | ||
---|---|---|---|---|---|
地区 | 代号 | ||||
中国 | BABA | 电商 | 176.92 | 16175610 | 101550 |
JD | 电商 | 25.95 | 27113291 | 175336 | |
美国 | MS | 金融 | 41.79 | 10132145 | 60348 |
GS | 金融 | 196.00 | 2626634 | 36600 |
df5=df3.set_index(['地区','代号'])#将所有index变成columns
df5
行业 | 价格 | 交易量 | 雇员 | ||
---|---|---|---|---|---|
地区 | 代号 | ||||
中国 | BABA | 电商 | 176.92 | 16175610 | 101550 |
JD | 电商 | 25.95 | 27113291 | 175336 | |
美国 | MS | 金融 | 41.79 | 10132145 | 60348 |
GS | 金融 | 196.00 | 2626634 | 36600 |
7.2.3 查看数据特征和统计信息
——查看数据特征
1.从头或从尾部查看DataFrame的n行,分别用df1.head()和df1.tail(n),如果没有设定n,默认值为5行。
df1.head()
工号 | 日期 | 时段 | 交易额 | 柜台 | |
---|---|---|---|---|---|
姓名 | |||||
李四 | 1002 | 2019-03-01 | 14:00-21:00 | 954.0 | 化妆品 |
赵六 | 1004 | 2019-03-01 | 14:00-21:00 | 1320.0 | 食品 |
钱八 | 1006 | 2019-03-01 | 14:00-21:00 | 1421.0 | 日用品 |
钱八 | 1006 | 2019-03-01 | 9:00-14:00 | 1226.0 | 蔬菜水果 |
张三 | 1001 | 2019-03-01 | 14:00-21:00 | 1442.0 | 蔬菜水果 |
df1.tail()
工号 | 日期 | 时段 | 交易额 | 柜台 | |
---|---|---|---|---|---|
姓名 | |||||
李四 | 1002 | 2019-03-31 | 14:00-21:00 | 859.0 | 蔬菜水果 |
赵六 | 1004 | 2019-03-31 | 9:00-14:00 | 1668.0 | 日用品 |
赵六 | 1004 | 2019-03-31 | 14:00-21:00 | 1722.0 | 日用品 |
王五 | 1003 | 2019-03-31 | 9:00-14:00 | 1274.0 | 食品 |
钱八 | 1006 | 2019-03-31 | 14:00-21:00 | 812.0 | 食品 |
- df1.info()
df1.index
Index(['李四', '赵六', '钱八', '钱八', '张三', '张三', '李四', '王五', '赵六',
'周七',
...
'王五', '钱八', '周七', '李四', '周七', '李四', '赵六', '赵六', '王五',
'钱八'],
dtype='object', name='姓名', length=246)
df1.columns
Index(['工号', '日期', '时段', '交易额', '柜台'], dtype='object')
df1.values
array([[1002, '2019-03-01', '14:00-21:00', 954.0, '化妆品'],
[1004, '2019-03-01', '14:00-21:00', 1320.0, '食品'],
[1006, '2019-03-01', '14:00-21:00', 1421.0, '日用品'],
...,
[1004, '2019-03-31', '14:00-21:00', 1722.0, '日用品'],
[1003, '2019-03-31', '9:00-14:00', 1274.0, '食品'],
[1006, '2019-03-31', '14:00-21:00', 812.0, '食品']], dtype=object)
——统计特征
print('查看交易统计信息')
print(df['交易额'].describe())
查看交易统计信息
count 246.000000
mean 1330.313008
std 904.300720
min 53.000000
25% 1031.250000
50% 1259.000000
75% 1523.000000
max 12100.000000
Name: 交易额, dtype: float64
求某列数据最大值及位置、最小值及位置、最大或者最小几条记录
df1.describe(percentiles=[.2,.75, .8])
工号 | 交易额 | |
---|---|---|
count | 246.000000 | 243.000000 |
mean | 1003.475610 | 1330.008230 |
std | 1.667644 | 909.365395 |
min | 1001.000000 | 53.000000 |
20% | 1002.000000 | 980.400000 |
50% | 1003.500000 | 1257.000000 |
75% | 1005.000000 | 1523.000000 |
80% | 1005.000000 | 1580.200000 |
max | 1006.000000 | 12100.000000 |
print(df['交易额'].sum())
327257.0
print('交易额四分位数')
print(df['交易额'].quantile([0,0.25,0.5,0.75,1]))
交易额四分位数
0.00 53.00
0.25 1031.25
0.50 1259.00
0.75 1523.00
1.00 12100.00
Name: 交易额, dtype: float64
print('交易额中值')
print(df['交易额'].median())
交易额中值
1259.0
print('交易额最小的3条记录')
print(df.nsmallest(3,'交易额'))
交易额最小的3条记录
工号 姓名 日期 时段 交易额 柜台
76 1005 周七 2019-03-10 9:00-14:00 53.0 日用品
97 1002 李四 2019-03-13 14:00-21:00 98.0 日用品
194 1001 张三 2019-03-25 14:00-21:00 114.0 化妆品
print('交易额最大的5条记录')
print(df.nlargest(5,'交易额'))
交易额最大的5条记录
工号 姓名 日期 时段 交易额 柜台
105 1001 张三 2019-03-14 9:00-14:00 12100.0 日用品
223 1003 王五 2019-03-28 9:00-14:00 9031.0 食品
113 1002 李四 2019-03-15 9:00-14:00 1798.0 日用品
188 1002 李四 2019-03-24 14:00-21:00 1793.0 蔬菜水果
136 1001 张三 2019-03-17 14:00-21:00 1791.0 食品
print('最后一个日期')
print(df['日期'].max())
最后一个日期
2019-03-31
print('最小的工号')
print(df['工号'].min())
最小的工号
1001
print('第一个最小交易额的行下标')
index=df['交易额'].idxmin()
print(index)
第一个最小交易额的行下标
76
print('第一个最小交易额')
print(df.loc[index,'交易额'])
第一个最小交易额
53.0
print('第一个最大交易额的行下标')
index=df['交易额'].idxmax()
print(index)
第一个最大交易额的行下标
105
print('第一个最大的交易额')
print(df.loc[index,'交易额'])
第一个最大的交易额
12100.0
7.2.4按不同标准对数据排序
——sort_values()
DataFrame.sort_values(by='', axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last', ignore_index=False, key=None)
by:指定要进行排序的列名或索引值
axis:若 axis=0 或 ‘index’,则按照指定 列 的数据大小排序;若 axis=1 或 ‘columns’,则按照指定 索引 中数据大小排序。默认axis=0
ascending:若 ascending=True,则按照升序排序;若 ascending=False,则按降序排序,默认为True,即升序排序。如果这是一个 bool 列表,则必须匹配 by 的长度
inplace:排序后的数据是否替换原来的数据,默认为False,即不替换
ignore_index:是否重置索引,默认为不重置
import pandas as pd
pd.set_option('display.unicode.ambiguous_as_wide',True)
pd.set_option('display.unicode.east_asian_width',True)
df=pd.read_excel(r'超市营业额2.xlsx')
print('按交易额和工号降序排序')
print(df.sort_values(by=['交易额','工号'],ascending=False)[:12])
按交易额和工号降序排序
工号 姓名 日期 时段 交易额 柜台
105 1001 张三 2019-03-14 9:00-14:00 12100.0 日用品
223 1003 王五 2019-03-28 9:00-14:00 9031.0 食品
113 1002 李四 2019-03-15 9:00-14:00 1798.0 日用品
188 1002 李四 2019-03-24 14:00-21:00 1793.0 蔬菜水果
136 1001 张三 2019-03-17 14:00-21:00 1791.0 食品
121 1002 李四 2019-03-16 9:00-14:00 1788.0 日用品
47 1005 周七 2019-03-06 14:00-21:00 1778.0 蔬菜水果
185 1004 赵六 2019-03-24 9:00-14:00 1775.0 化妆品
205 1001 张三 2019-03-26 9:00-14:00 1746.0 日用品
82 1006 钱八 2019-03-11 9:00-14:00 1737.0 食品
227 1005 周七 2019-03-29 9:00-14:00 1737.0 蔬菜水果
246 1004 赵六 2019-03-31 14:00-21:00 1722.0 日用品
print('按交易额降序、工号升序排序')
print(df.sort_values(by=['交易额','工号'],ascending=[False,True])[:12])
按交易额降序、工号升序排序
工号 姓名 日期 时段 交易额 柜台
105 1001 张三 2019-03-14 9:00-14:00 12100.0 日用品
223 1003 王五 2019-03-28 9:00-14:00 9031.0 食品
113 1002 李四 2019-03-15 9:00-14:00 1798.0 日用品
188 1002 李四 2019-03-24 14:00-21:00 1793.0 蔬菜水果
136 1001 张三 2019-03-17 14:00-21:00 1791.0 食品
121 1002 李四 2019-03-16 9:00-14:00 1788.0 日用品
47 1005 周七 2019-03-06 14:00-21:00 1778.0 蔬菜水果
185 1004 赵六 2019-03-24 9:00-14:00 1775.0 化妆品
205 1001 张三 2019-03-26 9:00-14:00 1746.0 日用品
227 1005 周七 2019-03-29 9:00-14:00 1737.0 蔬菜水果
82 1006 钱八 2019-03-11 9:00-14:00 1737.0 食品
246 1004 赵六 2019-03-31 14:00-21:00 1722.0 日用品
print('按工号升序排序')
print(df.sort_values(by='工号',na_position='last')[:10])
按工号升序排序
工号 姓名 日期 时段 交易额 柜台
0 1001 张三 2019-03-01 9:00-14:00 1664.0 化妆品
178 1001 张三 2019-03-23 14:00-21:00 1271.0 化妆品
39 1001 张三 2019-03-05 14:00-21:00 856.0 蔬菜水果
40 1001 张三 2019-03-06 9:00-14:00 1037.0 化妆品
177 1001 张三 2019-03-23 9:00-14:00 1296.0 化妆品
169 1001 张三 2019-03-22 9:00-14:00 946.0 化妆品
160 1001 张三 2019-03-20 14:00-21:00 829.0 食品
54 1001 张三 2019-03-07 9:00-14:00 1263.0 蔬菜水果
157 1001 张三 2019-03-20 9:00-14:00 1037.0 日用品
225 1001 张三 2019-03-29 14:00-21:00 1523.0 化妆品
——sort.index()
DataFrame.sort_index(axis=0, level=None, ascending=True, inplace=False, kind=’quicksort’, na_position=’last’, sort_remaining=True, by=None)
axis:索引,直接排序的列
level:如果不是,则对指定索引级别的值进行排序
ascending:升序与降序排序
inplace:如果为True,则就地执行操作
kind:{“快速排序”,“合并排序”,“堆排序”},默认为“快速排序”。选择排序算法。有关更多信息,另请参见ndarray.np.sort。 mergesort是唯一稳定的算法。对于DataFrame,此选项仅在对单个列或标签进行排序时适用。
print('按列名升序排序')
print(df.sort_index(axis=1,ascending=True)[:10])
按列名升序排序
交易额 姓名 工号 日期 时段 柜台
0 1664.0 张三 1001 2019-03-01 9:00-14:00 化妆品
1 954.0 李四 1002 2019-03-01 14:00-21:00 化妆品
2 1407.0 王五 1003 2019-03-01 9:00-14:00 食品
3 1320.0 赵六 1004 2019-03-01 14:00-21:00 食品
4 994.0 周七 1005 2019-03-01 9:00-14:00 日用品
5 1421.0 钱八 1006 2019-03-01 14:00-21:00 日用品
6 1226.0 钱八 1006 2019-03-01 9:00-14:00 蔬菜水果
7 1442.0 张三 1001 2019-03-01 14:00-21:00 蔬菜水果
8 1530.0 张三 1001 2019-03-02 9:00-14:00 化妆品
9 1395.0 李四 1002 2019-03-02 14:00-21:00 化妆品
7.2.5 使用分组与聚合对员工业绩进行汇总
groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=False, **kwargs)
参数by用来指定作用于index的函数、字典、Series对象,或者指定列名作为分组依据;
参数as_index=False时用来分组的列中的数据不作为结果DataFrame对象的index;
参数squeeze=True时会在可能的情况下降低结果对象的维度。
print('指定by参数为字典')
print(df.groupby(by={7:'下标为7的行',
35:'下标为35的行'})['交易额'].sum())
指定by参数为字典
下标为35的行 974.0
下标为7的行 1442.0
Name: 交易额, dtype: float64
print('不同时段的销售总额')
print(df.groupby(by='时段')['交易额'].sum())
不同时段的销售总额
时段
14:00-21:00 151228.0
9:00-14:00 176029.0
Name: 交易额, dtype: float64
print('各柜台的销售总额')
print(df.groupby(by='柜台')['交易额'].sum())
各柜台的销售总额
柜台
化妆品 75389.0
日用品 88162.0
蔬菜水果 78532.0
食品 85174.0
Name: 交易额, dtype: float64
#可以查看每个员工上班总时长是否均匀
print('每个员工上班的次数')
dff=df.groupby(by='姓名')['日期'].count()
dff.name ='上班次数'
print(dff)
每个员工上班的次数
姓名
周七 42
张三 38
李四 47
王五 40
赵六 45
钱八 37
Name: 上班次数, dtype: int64
print('汇总交易额转换为整数')
print(df.groupby(by='姓名').sum()['交易额'].apply(int))
汇总交易额转换为整数
姓名
周七 47818
张三 58130
李四 58730
王五 58892
赵六 56069
钱八 47618
Name: 交易额, dtype: int64
print('每个员工交易额的史值')
dff=df.groupby(by='姓名').median()
print(dff['交易额'])
每个员工交易额的史值
姓名
周七 1134.5
张三 1290.0
李四 1276.0
王五 1227.0
赵六 1224.0
钱八 1381.0
Name: 交易额, dtype: float64
dff['排名'] = dff['交易额'].rank(ascending=False)
print('每个员工交易额中值的排名')
print(dff[['交易额','排名']])
每个员工交易额中值的排名
交易额 排名
姓名
周七 1134.5 6.0
张三 1290.0 2.0
李四 1276.0 3.0
王五 1227.0 4.0
赵六 1224.0 5.0
钱八 1381.0 1.0
print('每个员工不同时段的交易额')
print(df.groupby(by=['姓名','时段'])['交易额'].sum())
每个员工不同时段的交易额
姓名 时段
周七 14:00-21:00 15910.0
9:00-14:00 31908.0
张三 14:00-21:00 23659.0
9:00-14:00 34471.0
李四 14:00-21:00 32295.0
9:00-14:00 26435.0
王五 14:00-21:00 17089.0
9:00-14:00 41803.0
赵六 14:00-21:00 29121.0
9:00-14:00 26948.0
钱八 14:00-21:00 33154.0
9:00-14:00 14464.0
Name: 交易额, dtype: float64
#对不同的列可以采用不同的函数
print('时段和交易额采用不同的聚合方式')
print(df.groupby(by=['姓名'])['时段','交易额'].aggregate({'交易额':np.sum,
'时段':lambda x:'各时段累计'}))
时段和交易额采用不同的聚合方式
交易额 时段
姓名
周七 47818.0 各时段累计
张三 58130.0 各时段累计
李四 58730.0 各时段累计
王五 58892.0 各时段累计
赵六 56069.0 各时段累计
钱八 47618.0 各时段累计
#使用DataErame结构的agg()方法对指定列进行聚合
print('使用agg()方法对交易额进行聚合')
print(df.agg({'交易额':['sum','mean','min','max','median'],
'日期':['min','max']}))
使用agg()方法对交易额进行聚合
交易额 日期
sum 327257.000000 NaN
mean 1330.313008 NaN
min 53.000000 2019-03-01
max 12100.000000 2019-03-31
median 1259.000000 NaN
print('对分组结果进行聚合')
print('查看分组聚合后的部分结果')
print(df.groupby(by='姓名').agg(['max','min', 'mean', 'median'])['交易额'])
对分组结果进行聚合
查看分组聚合后的部分结果
max min mean median
姓名
周七 1778.0 53.0 1195.450000 1134.5
张三 12100.0 114.0 1529.736842 1290.0
李四 1798.0 98.0 1249.574468 1276.0
王五 9031.0 801.0 1472.300000 1227.0
赵六 1775.0 825.0 1245.977778 1224.0
钱八 1737.0 807.0 1322.722222 1381.0
7.2.6 数据的异常值处理
异常值是指严重超出正常范围的数值,这样的数据一般是数据采集错误或类似原因引起的。
在数据分析时,需要把这些数据删除或替换为特定的值(例如人为设定的正常范围边界值),减小对最终数据分析结果的影响。
异常值处理的关键是根据实际情况准确定义正常范围边界值,超出正常范围的数值认为是异常值。
1.基于统计与数据发布 2.箱形图分析
print('查看交易额低于200的数据')
print(df[df.交易额<200])
查看交易额低于200的数据
工号 姓名 日期 时段 交易额 柜台
76 1005 周七 2019-03-10 9:00-14:00 53.0 日用品
97 1002 李四 2019-03-13 14:00-21:00 98.0 日用品
194 1001 张三 2019-03-25 14:00-21:00 114.0 化妆品
df.loc[df.交易额<200,'交易额'] = df[df.交易额<200]['交易额'].map(lambda num:num*1.5)
print('上浮50%之后仍低于200的数据')
print(df[df.交易额<200])
上浮50%之后仍低于200的数据
工号 姓名 日期 时段 交易额 柜台
76 1005 周七 2019-03-10 9:00-14:00 79.5 日用品
97 1002 李四 2019-03-13 14:00-21:00 147.0 日用品
194 1001 张三 2019-03-25 14:00-21:00 171.0 化妆品
print('查看交易额高于3000的数据')
print(df[df['交易额']>3000])
查看交易额高于3000的数据
工号 姓名 日期 时段 交易额 柜台
105 1001 张三 2019-03-14 9:00-14:00 12100.0 日用品
223 1003 王五 2019-03-28 9:00-14:00 9031.0 食品
print('交易额低于200或高于3000的数据')
print(df[(df.交易额<200)|(df.交易额>3000)])
交易额低于200或高于3000的数据
工号 姓名 日期 时段 交易额 柜台
76 1005 周七 2019-03-10 9:00-14:00 79.5 日用品
97 1002 李四 2019-03-13 14:00-21:00 147.0 日用品
105 1001 张三 2019-03-14 9:00-14:00 12100.0 日用品
194 1001 张三 2019-03-25 14:00-21:00 171.0 化妆品
223 1003 王五 2019-03-28 9:00-14:00 9031.0 食品
#把低于200的交易额都替换为固定的200
df.loc[df.交易额<200,'交易额']=200
print('交易额低于200或高于3000的数据')
print(df[(df.交易额<200)|(df.交易额>3000)])
交易额低于200或高于3000的数据
工号 姓名 日期 时段 交易额 柜台
105 1001 张三 2019-03-14 9:00-14:00 12100.0 日用品
223 1003 王五 2019-03-28 9:00-14:00 9031.0 食品
#把高于3000的交易额都替换为固定的3000
df.loc[df.交易额>3000,'交易额']=3000
print('交易额低于200或高于3000的数量')
print(df[(df.交易额<200)|(df.交易额>3000)]['交易额'].count())
交易额低于200或高于3000的数量
0
7.2.7处理超市交易额数据中的缺失值
dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
参数how='any'时表示只要某行包含缺失值就丢弃,how='all'时表示某行全部为缺失值才丢弃;
参数thresh用来指定保留包含几个非缺失值数据的行;
参数subset用来指定在判断缺失值时只考虑哪些列。
fillna(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None, **kwargs)
参数value用来指定要替换的值,可以是标量、字典、Series或DataFrame;
参数method用来指定填充缺失值的方式,值为'pad'或'ffill'时表示使用扫描过程中遇到的最后一个有效值一直填充到下一个有效值,值为'backfill'或'bfill'时表示使用缺失值之后遇到的第一个有效值填充前面遇到的所有连续缺失值;
参数limit用来指定设置了参数method时最多填充多少个连续的缺失值;
参数inplace=True时表示原地替换,inplace=False时返回一个新的DataFrame对象而不对原来的DataFrame做任何修改。
from copy import deepcopy
pd.set_option('display.unicode.ambiguous_as_wide',True)
pd.set_option('display.unicode.east_asian_width',True)
df=pd.read_excel(r'超市营业额2.xlsx')
print('数据总行数')
print(len(df))
数据总行数
249
print('丢失缺失值之后的行数')
print(len(df.dropna()))
丢失缺失值之后的行数
246
print('包含缺失值的行')
print(df[df['交易额'].isnull()])
包含缺失值的行
工号 姓名 日期 时段 交易额 柜台
110 1005 周七 2019-03-14 14:00-21:00 NaN 化妆品
124 1006 钱八 2019-03-16 14:00-21:00 NaN 食品
168 1005 周七 2019-03-21 14:00-21:00 NaN 食品
print('使用固定值替换缺失值')
dff=deepcopy(df)
dff.loc[dff.交易额.isnull(),'交易额']=1000
print(dff.iloc[[110,124,168],:])
使用固定值替换缺失值
工号 姓名 日期 时段 交易额 柜台
110 1005 周七 2019-03-14 14:00-21:00 1000.0 化妆品
124 1006 钱八 2019-03-16 14:00-21:00 1000.0 食品
168 1005 周七 2019-03-21 14:00-21:00 1000.0 食品
print('使用每人交易额均值替换缺失值')
dff=deepcopy(df)
for i in dff[dff.交易额.isnull()].index:
dff.loc[i,'交易额']=round(dff.loc[dff.姓名==dff.loc[i,'姓名'],'交易额'].mean())
print(dff.iloc[[110,124,168],:])
使用每人交易额均值替换缺失值
工号 姓名 日期 时段 交易额 柜台
110 1005 周七 2019-03-14 14:00-21:00 1195.0 化妆品
124 1006 钱八 2019-03-16 14:00-21:00 1323.0 食品
168 1005 周七 2019-03-21 14:00-21:00 1195.0 食品
print('使用整体均值的80%填充')
df.fillna({'交易额':round(df['交易额'].mean()*0.8)},inplace=True)
print(df.iloc[[110,124,168],:])
使用整体均值的80%填充
工号 姓名 日期 时段 交易额 柜台
110 1005 周七 2019-03-14 14:00-21:00 1064.0 化妆品
124 1006 钱八 2019-03-16 14:00-21:00 1064.0 食品
168 1005 周七 2019-03-21 14:00-21:00 1064.0 食品
7.2.8处理超市交易数据中的重复值
duplicated(subset=None, keep='first')
参数subset用来指定判断不同行的数据是否重复时所依据的一列或多列,默认使用整行所有列的数据进行比较;
参数keep='first'时表示重复数据的第一次出现标记为False,keep='last'时表示重复数据的最后一次出现标记为False,keep=False时表示标记所有重复数据为True。
drop_duplicates(subset=None, keep='first', inplace=False)
参数subset和keep的含义与duplicated()方法类似;
参数inplace=True时表示原地修改,此时duplicated()方法没有返回值,inplace=False时表示返回新的DataFrame结构而不对原来的DataFrame做任何修改。
from copy import deepcopy
import pandas as pd
import numpy as np
pd.set_option('display.unicode.ambiguous_as_wide',True)
pd.set_option('display.unicode.east_asian_width',True)
df=pd.read_excel(r'超市营业额2.xlsx')
print('数据总行数')
print(len(df))
数据总行数
249
print('数据总行数')
print(len(df))
数据总行数
249
print('一人同时负责多个柜台的排班')
dff=df[['工号','姓名','日期','时段']]
dff=dff[dff.duplicated()]
for row in dff.values:
print(df[ (df.工号==row[0]) & (df.日期==row[2]) & (df.日期==row[2]) &(df.时段==row[3])])
一人同时负责多个柜台的排班
工号 姓名 日期 时段 交易额 柜台
49 1002 李四 2019-03-07 14:00-21:00 1199.0 化妆品
55 1002 李四 2019-03-07 14:00-21:00 831.0 蔬菜水果
工号 姓名 日期 时段 交易额 柜台
103 1006 钱八 2019-03-13 14:00-21:00 1609.0 蔬菜水果
104 1006 钱八 2019-03-13 14:00-21:00 1609.0 蔬菜水果
工号 姓名 日期 时段 交易额 柜台
171 1006 钱八 2019-03-22 9:00-14:00 1555.0 蔬菜水果
175 1006 钱八 2019-03-22 9:00-14:00 1503.0 食品
工号 姓名 日期 时段 交易额 柜台
201 1004 赵六 2019-03-26 9:00-14:00 1599.0 化妆品
210 1004 赵六 2019-03-26 9:00-14:00 1257.0 化妆品
#直接丢弃全部行
df = df.drop_duplicates()
print('有效数据总行')
print(len(df))
有效数据总行
248
#可以查看是否有录入错误的工号和姓名
print('所有工号与姓名的对应关系')
dff = df[['工号','姓名']]
print(dff.drop_duplicates())
所有工号与姓名的对应关系
工号 姓名
0 1001 张三
1 1002 李四
2 1003 王五
3 1004 赵六
4 1005 周七
5 1006 钱八
7.2.9使用数据差分查看员工业绩波动情况
diff(periods=1, axis=0)
参数periods用来指定差分的跨度,当periods=1且axis=0时表示每一行数据减去紧邻的上一行数据,当periods=2且axis=0时表示每一行减去上面第二行的数据;
参数axis=0时表示按行进行纵向差分,axis=1时表示按列横向差分。
import pandas as pd
pd.set_option('display.unicode.ambiguous_as_wide',True)
pd.set_option('display.unicode.east_asian_width',True)
df = pd.read_excel(r'超市营业额2.xlsx')
print('每天交易总额变化情况')
dff = df.groupby(by='日期').sum()['交易额'].diff()
print(dff.map(lambda num:'%+.2f'%num)[:5])
每天交易总额变化情况
日期
2019-03-01 +nan
2019-03-02 -248.00
2019-03-03 +924.00
2019-03-04 +56.00
2019-03-05 -277.00
Name: 交易额, dtype: object
print('张三的每天交易总额变化情况')
print(df[df.姓名=='张三'].groupby(by='日期').sum()['交易额'].diff()[:5])
张三的每天交易总额变化情况
日期
2019-03-01 NaN
2019-03-02 -1576.0
2019-03-03 -169.0
2019-03-04 -145.0
2019-03-05 1031.0
Name: 交易额, dtype: float64
7.2.10使用透视表与交叉表查看业绩汇总数据
——透视表
pivot(index=None, columns=None, values=None)
参数index用来指定使用哪一列数据作为结果DataFrame的索引;
参数columns用来指定哪一列数据作为结果DataFrame的列名;
参数values用来指定哪一列数据作为结果DataFrame的值。
pivot_table(values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All')
参数values、index、columns的含义与DataFrame结构的pivot()方法一样;
参数aggfunc用来指定数据的聚合方式,例如求平均、求和、求中值等;
参数margins用来指定是否显示边界以及边界上的数据;
参数margins_name用来指定边界数据的索引名称和列名;
参数dropna用来指定是否丢弃缺失值。
import pandas as pd
pd.set_option('display.unicode.ambiguous_as_wide',True)
pd.set_option('display.unicode.east_asian_width',True)
df = pd.read_excel(r'超市营业额2.xlsx')
print('查看每人每天交易总额')
dff = df.groupby(by=['姓名','日期'],as_index=False).sum()
print(dff.iloc[:,:5])
查看每人每天交易总额
姓名 日期 工号 交易额
0 周七 2019-03-01 1005 994.0
1 周七 2019-03-02 1005 1444.0
2 周七 2019-03-03 2010 3230.0
3 周七 2019-03-04 2010 2545.0
4 周七 2019-03-05 1005 1249.0
.. ... ... ... ...
173 钱八 2019-03-27 2012 2996.0
174 钱八 2019-03-28 1006 1219.0
175 钱八 2019-03-29 1006 1639.0
176 钱八 2019-03-30 1006 1090.0
177 钱八 2019-03-31 1006 812.0
[178 rows x 4 columns]
print('交易总额低于5万元的员工前5天业绩')
print(dff[dff.sum(axis=1)<50000].iloc[:,:5])
交易总额低于5万元的员工前5天业绩
姓名 日期 工号 交易额
0 周七 2019-03-01 1005 994.0
1 周七 2019-03-02 1005 1444.0
2 周七 2019-03-03 2010 3230.0
3 周七 2019-03-04 2010 2545.0
4 周七 2019-03-05 1005 1249.0
.. ... ... ... ...
173 钱八 2019-03-27 2012 2996.0
174 钱八 2019-03-28 1006 1219.0
175 钱八 2019-03-29 1006 1639.0
176 钱八 2019-03-30 1006 1090.0
177 钱八 2019-03-31 1006 812.0
[178 rows x 4 columns]
print('交易总额低于5万元的员工姓名')
print(dff[dff.sum(axis=1)<50000].index.values)
交易总额低于5万元的员工姓名
[ 0 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 64 65 66 67 68 69 70 71
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177]
print('使用pivot_table()方法实现')
print(df.pivot_table(values='交易额',index='姓名',columns='日期',aggfunc='sum',margins=True).iloc[:,:5])
使用pivot_table()方法实现
日期 2019-03-01 2019-03-02 2019-03-03 2019-03-04 2019-03-05
姓名
周七 994.0 1444.0 3230.0 2545.0 1249.0
张三 3106.0 1530.0 1361.0 1216.0 2247.0
李四 954.0 3044.0 1034.0 2734.0 3148.0
王五 1407.0 2115.0 1713.0 1590.0 1687.0
赵六 1320.0 906.0 2309.0 1673.0 974.0
钱八 2647.0 1141.0 1457.0 1402.0 1578.0
All 10428.0 10180.0 11104.0 11160.0 10883.0
print('查看每人在柜台的交易额')
dff = df.groupby(by=['姓名','柜台'],as_index=False).sum()
print(df.pivot_table(values='交易额',index='姓名',columns='日期',aggfunc='count',margins=True).iloc[:,:5])
查看每人在柜台的交易额
日期 2019-03-01 2019-03-02 2019-03-03 2019-03-04 2019-03-05
姓名
周七 1.0 1.0 2.0 2.0 1.0
张三 2.0 1.0 1.0 1.0 2.0
李四 1.0 2.0 1.0 2.0 2.0
王五 1.0 2.0 1.0 1.0 1.0
赵六 1.0 1.0 2.0 1.0 1.0
钱八 2.0 1.0 1.0 1.0 1.0
All 8.0 8.0 8.0 8.0 8.0
print('查看每人在各柜台的上班次数')
print(df.pivot_table(values='交易额',index='姓名',columns='柜台',aggfunc='count',margins=True))
查看每人在各柜台的上班次数
柜台 化妆品 日用品 蔬菜水果 食品 All
姓名
周七 8.0 11.0 14.0 7.0 40
张三 19.0 6.0 6.0 7.0 38
李四 16.0 9.0 18.0 4.0 47
王五 8.0 9.0 9.0 14.0 40
赵六 10.0 18.0 2.0 15.0 45
钱八 NaN 9.0 14.0 13.0 36
All 61.0 62.0 63.0 60.0 246
——交叉表
交叉表是一种特殊的透视表,往往用来统计频次,也可以使用参数aggfunc指定聚合函数实现其他功能。
crosstab(index, columns, values=None, rownames=None, colnames=None, aggfunc=None, margins=False, dropna=True, normalize=False)
参数values、index、columns的含义与DataFrame结构的pivot()方法一样;
参数aggfunc用来指定聚合函数,默认为统计次数;
参数rownames和colnames分别用来指定行索引和列索引的名字,如果不指定则直接使用参数index和columns指定的列名。
import pandas as pd
pd.set_option('display.unicode.ambiguous_as_wide',True)
pd.set_option('display.unicode.east_asian_width',True)
df = pd.read_excel(r'超市营业额2.xlsx')
print('每人每天的上班次数')
print(pd.crosstab(df.姓名,df.日期,margins=True).iloc[:,:5])
每人每天的上班次数
日期 2019-03-01 2019-03-02 2019-03-03 2019-03-04 2019-03-05
姓名
周七 1 1 2 2 1
张三 2 1 1 1 2
李四 1 2 1 2 2
王五 1 2 1 1 1
赵六 1 1 2 1 1
钱八 2 1 1 1 1
All 8 8 8 8 8
print('每人在各柜台上班总次数')
print(pd.crosstab(df.姓名,df.柜台,margins=True).iloc[:,:5])
每人在各柜台上班总次数
柜台 化妆品 日用品 蔬菜水果 食品 All
姓名
周七 9 11 14 8 42
张三 19 6 6 7 38
李四 16 9 18 4 47
王五 8 9 9 14 40
赵六 10 18 2 15 45
钱八 0 9 14 14 37
All 62 62 63 62 249
print('每人在各柜台交易总额')
print(pd.crosstab(df.姓名,df.柜台,df.交易额,aggfunc='sum'))
每人在各柜台交易总额
柜台 化妆品 日用品 蔬菜水果 食品
姓名
周七 9516.0 12863.0 16443.0 8996.0
张三 22975.0 18629.0 7265.0 9261.0
李四 20467.0 10104.0 23263.0 4896.0
王五 10112.0 11357.0 10473.0 26950.0
赵六 12319.0 23286.0 2527.0 17937.0
钱八 NaN 11923.0 18561.0 17134.0
print('每人在各柜台交易额平均值')
print(pd.crosstab(df.姓名,df.柜台,df.交易额,aggfunc='mean').apply(lambda num:round(num,2)))
每人在各柜台交易额平均值
柜台 化妆品 日用品 蔬菜水果 食品
姓名
周七 1189.50 1169.36 1174.50 1285.14
张三 1209.21 3104.83 1210.83 1323.00
李四 1279.19 1122.67 1292.39 1224.00
王五 1264.00 1261.89 1163.67 1925.00
赵六 1231.90 1293.67 1263.50 1195.80
钱八 NaN 1324.78 1325.79 1318.00
7.2.11使用重采样技术按时间段查看员工业绩
resample(rule, how=None, axis=0, fill_method=None, closed=None, label=None, convention='start', kind=None, loffset=None, limit=None, base=0, on=None, level=None)
参数rule用来指定重采样的时间间隔,例如'7D'表示每7天采样一次;
参数how用来指定如何处理两个采样时间之间的数据,不过该参数很快会被新版本丢弃不用了;
参数label = 'left'表示使用采样周期的起始时间作为结果DataFrame的index,label='right'表示使用采样周期的结束时间作为结果DataFrame的index;
参数on用来指定根据哪一列进行重采样,要求该列数据为日期时间类型。
import numpy as np
import pandas as pd
df = pd.read_excel(r'超市营业额2.xlsx')
df.日期 = pd.to_datetime(df.日期)
print('每7天营业额')
print(df.resample('7D',on='日期',label='right').sum()['交易额'])
每7天营业额
日期
2019-03-08 73600.0
2019-03-15 77823.0
2019-03-22 65996.0
2019-03-29 79046.0
2019-04-05 30792.0
Freq: 7D, Name: 交易额, dtype: float64
print('每7天营业总额')
print(df.resample('7D',on='日期').sum()['交易额'])
每7天营业总额
日期
2019-03-01 73600.0
2019-03-08 77823.0
2019-03-15 65996.0
2019-03-22 79046.0
2019-03-29 30792.0
Freq: 7D, Name: 交易额, dtype: float64
print('每7天营业额平均值')
func = lambda num:round(num,2)
print(df.resample('7D',on='日期',label='right').mean().apply(func)['交易额'])
每7天营业额平均值
日期
2019-03-08 1314.29
2019-03-15 1389.70
2019-03-22 1222.15
2019-03-29 1411.54
2019-04-05 1283.00
Freq: 7D, Name: 交易额, dtype: float64
7.2.12多索引相关技术与操作
DataFrame结构支持多个索引,既可以在读取数据时使用index_col指定多列,也可以通过groupby()方法分组时指定多个索引。对于含有多个索引的DataFrame结构,在使用sort_index()方法按索引排序、使用groupby()方法进行分组时,都可以使用参数level指定按哪一级索引进行排序或分组。
import numpy as np
import pandas as pd
#设置输出结果对齐方式
pd.set_option('display.unicode.ambiguous_as_wide',True)
pd.set_option('display.unicode.east_asian_width',True)
df = pd.read_excel(r'超市营业额2.xlsx')
#删除工号一列的数据
df.drop('工号',axis=1,inplace=True)
df = df.groupby(by=['姓名','柜台']).sum()
print('按姓名和柜台进行分组汇总')
print(df[:10])
按姓名和柜台进行分组汇总
交易额
姓名 柜台
周七 化妆品 9516.0
日用品 12863.0
蔬菜水果 16443.0
食品 8996.0
张三 化妆品 22975.0
日用品 18629.0
蔬菜水果 7265.0
食品 9261.0
李四 化妆品 20467.0
日用品 10104.0
print('查看周七的汇总数据')
print(df.loc['周七','化妆品'])
查看周七的汇总数据
交易额 9516.0
Name: (周七, 化妆品), dtype: float64
print('查看周七在化妆品柜台的交易数据')
print(df.loc[('周七','化妆品')])
查看周七在化妆品柜台的交易数据
交易额 9516.0
Name: (周七, 化妆品), dtype: float64
import numpy as np
import pandas as pd
#设置输出结果对齐方式
pd.set_option('display.unicode.ambiguous_as_wide',True)
pd.set_option('display.unicode.east_asian_width',True)
df = pd.read_excel(r'超市营业额2.xlsx')
#删除工号一列的数据
df.drop('工号',axis=1,inplace=True)
#按索引“柜台”排序,查看前12行
dff = df.sort_index(level='柜台',axis=0)
print('按柜台排序,查看前12行')
print(dff[:12])
按柜台排序,查看前12行
姓名 日期 时段 交易额 柜台
0 张三 2019-03-01 9:00-14:00 1664.0 化妆品
1 李四 2019-03-01 14:00-21:00 954.0 化妆品
2 王五 2019-03-01 9:00-14:00 1407.0 食品
3 赵六 2019-03-01 14:00-21:00 1320.0 食品
4 周七 2019-03-01 9:00-14:00 994.0 日用品
5 钱八 2019-03-01 14:00-21:00 1421.0 日用品
6 钱八 2019-03-01 9:00-14:00 1226.0 蔬菜水果
7 张三 2019-03-01 14:00-21:00 1442.0 蔬菜水果
8 张三 2019-03-02 9:00-14:00 1530.0 化妆品
9 李四 2019-03-02 14:00-21:00 1395.0 化妆品
10 王五 2019-03-02 9:00-14:00 936.0 食品
11 赵六 2019-03-02 14:00-21:00 906.0 食品
#按索引“姓名”排序,查看前12行
dff = df.sort_index(level='柜台',axis=0)
print('按姓名排序,查看前12行')
print(dff[:12])
按姓名排序,查看前12行
姓名 日期 时段 交易额 柜台
0 张三 2019-03-01 9:00-14:00 1664.0 化妆品
1 李四 2019-03-01 14:00-21:00 954.0 化妆品
2 王五 2019-03-01 9:00-14:00 1407.0 食品
3 赵六 2019-03-01 14:00-21:00 1320.0 食品
4 周七 2019-03-01 9:00-14:00 994.0 日用品
5 钱八 2019-03-01 14:00-21:00 1421.0 日用品
6 钱八 2019-03-01 9:00-14:00 1226.0 蔬菜水果
7 张三 2019-03-01 14:00-21:00 1442.0 蔬菜水果
8 张三 2019-03-02 9:00-14:00 1530.0 化妆品
9 李四 2019-03-02 14:00-21:00 1395.0 化妆品
10 王五 2019-03-02 9:00-14:00 936.0 食品
11 赵六 2019-03-02 14:00-21:00 906.0 食品
#按索引“柜台”分组求和
print('按柜台分组求和')
dfff = dff.groupby(by='柜台').sum()
dfff.columns = ['交易额总和']
print(dfff)
按柜台分组求和
交易额总和
柜台
化妆品 75389.0
日用品 88162.0
蔬菜水果 78532.0
食品 85174.0
#按索引“姓名”分组求中值
print('按姓名分组求中值')
dfff = dff.groupby(by='姓名').median()
dfff.columns = ['交易额中值']
print(dfff)
按姓名分组求中值
交易额中值
姓名
周七 1134.5
张三 1290.0
李四 1276.0
王五 1227.0
赵六 1224.0
钱八 1381.0
7.2.13 使用标准差与协方差分析员工业绩
import numpy as np
import pandas as pd
#设置输出结果对齐方式
pd.set_option('display.unicode.ambiguous_as_wide',True)
pd.set_option('display.unicode.east_asian_width',True)
df = pd.read_excel(r'超市营业额2.xlsx')
#丢弃缺失值和重复值
df.dropna(inplace=True)
df.drop_duplicates(inplace=True)
#处理缺失值
df.loc[df.交易额<200,'交易额'] = 200
df.loc[df.交易额>3000,'交易额'] = 3000
#使用交叉表得到不同员工在不同柜台的交易额平均值
dff = pd.crosstab(df.姓名,df.柜台,df.交易额,aggfunc='mean')
print('标准差')
print(dff.std())
标准差
柜台
化妆品 36.480497
日用品 159.008839
蔬菜水果 60.331171
食品 105.031231
dtype: float64
print('协方差')
print(dff.cov())
协方差
柜台 化妆品 日用品 蔬菜水果 食品
柜台
化妆品 1330.826697 -2296.460562 923.019793 692.300017
日用品 -2296.460562 25283.810853 -1030.111953 2957.850772
蔬菜水果 923.019793 -1030.111953 3639.850206 -3918.549524
食品 692.300017 2957.850772 -3918.549524 11031.559490
7.2.14 使用pandas的属性接口实现高级功能
DataFrame数据中的日期时间列支持dt接口,该接口提供了dayofweek、dayofyear、is_leap_year、quarter、weekday_name等属性和方法,例如quarter可以直接得到每个日期分别是第几个季度,weekday_name可以直接每个日期对应的周几的名字。
DataFrame数据中的字符串列支持str接口,该接口提供了center、contains、count、endswith、find、extract、lower、split等大量属性和方法。
import numpy as np
import pandas as pd
import copy
#设置输出结果对齐方式
pd.set_option('display.unicode.ambiguous_as_wide',True)
pd.set_option('display.unicode.east_asian_width',True)
df = pd.read_excel(r'超市营业额2.xlsx',usecols=['日期','交易额'])
#深复制,不影响原来的df
dff = copy.deepcopy(df)
# 把日期列替换为周几
dff['日期'] = pd.to_datetime(df['日期']).dt.weekday
#按周几分组,查看交易额平均值,四舍五入
print('按周几分组查看交易额平均值')
dff = dff.groupby('日期').mean().apply(round)
dff.index.name = '周几'
print(dff)
按周几分组查看交易额平均值
交易额
周几
0 1233.0
1 1258.0
2 1224.0
3 1830.0
4 1277.0
5 1306.0
6 1254.0
dff=copy.deepcopy(df)
#修改日期列,只保留年份和月份
dff['日期']=dff['日期'].str.extract(r'(\d{4}-\d{2})')
print('只查看年份和月份')
print(dff[:5])
只查看年份和月份
日期 交易额
0 2019-03 1664.0
1 2019-03 954.0
2 2019-03 1407.0
3 2019-03 1320.0
4 2019-03 994.0
#按字符串形式的日期最后一位数进行分组
#该月1、11、21、31日汇总为一组,2、12、22日为一组,以此类推
print('按日期的日进行分组查看交易额平均值')
print(df.groupby(df['日期'].str.__getitem__(-1)).mean().apply(round))
按日期的日进行分组查看交易额平均值
交易额
日期
0 1178.0
1 1264.0
2 1273.0
3 1317.0
4 1801.0
5 1223.0
6 1292.0
7 1216.0
8 1508.0
9 1266.0
#查看日期尾数为6的数据前12行
print('査着日期尾数力 6 的数据')
print(df[df['日期'].str.endswith('6')][:12])
査着日期尾数力 6 的数据
日期 交易额
40 2019-03-06 1037.0
41 2019-03-06 822.0
42 2019-03-06 1200.0
43 2019-03-06 1245.0
44 2019-03-06 1699.0
45 2019-03-06 1199.0
46 2019-03-06 1162.0
47 2019-03-06 1778.0
121 2019-03-16 1788.0
122 2019-03-16 1590.0
123 2019-03-16 1498.0
124 2019-03-16 NaN
#查看日期尾数为12的数据 #slice()方法接收3个参数,分别为起始位置、结束位置和步长
print('日期尾数为12的交易数据')
print(df[df.日期.str.slice(-2)=='12'])
日期尾数为12的交易数据
日期 交易额
88 2019-03-12 1183.0
89 2019-03-12 979.0
90 2019-03-12 1651.0
91 2019-03-12 1435.0
92 2019-03-12 1302.0
93 2019-03-12 1317.0
94 2019-03-12 831.0
95 2019-03-12 1530.0
#日期中月份或天数包含2的交易数据第15到第25行
print('日期中月份或天数包含2的交易数据')
print(df[df.日期.str.slice(-5).str.contains('2')][15:25])
日期中月份或天数包含2的交易数据
日期 交易额
95 2019-03-12 1530.0
153 2019-03-20 1332.0
154 2019-03-20 1485.0
155 2019-03-20 980.0
156 2019-03-20 1615.0
157 2019-03-20 1037.0
158 2019-03-20 1649.0
159 2019-03-20 1046.0
160 2019-03-20 829.0
161 2019-03-21 1528.0
7.2.16 查看DataFrame的内存占用情况
import pandas as pd
# 读取全部数据,使用默认索引
df = pd.read_excel(r'超市营业额2.xlsx')
print('交易额列占用内存情况'.ljust(20,'='))
print(df['交易额'].memory_usage())
print('内存占用情况'.ljust(20,'='))
print(df.memory_usage())
print('内存占用总额'.ljust(20,'='))
print(df.memory_usage().sum())
print('使用df.info()查看内存占用'.ljust(20,'='))
df.info()
交易额列占用内存情况==========
2120
内存占用情况==============
Index 128
工号 1992
姓名 1992
日期 1992
时段 1992
交易额 1992
柜台 1992
dtype: int64
内存占用总额==============
12080
使用df.info()查看内存占用===
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 249 entries, 0 to 248
Data columns (total 6 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 工号 249 non-null int64
1 姓名 249 non-null object
2 日期 249 non-null object
3 时段 249 non-null object
4 交易额 246 non-null float64
5 柜台 249 non-null object
dtypes: float64(1), int64(1), object(4)
memory usage: 11.8+ KB
7.2.17 数据拆分与合并
——concat()函数与append()方法
根据不同的需要,可以对DataFrame使用切片或loc等运算按行或列进行拆分,得到多个DataFrame结构。扩展库pandas提供了concat()函数用于合并多个DataFrame结构,完整语法如下:
concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, copy=True)
参数objs表示包含多个Series、DataFrame或Panel对象的序列;
参数axis默认为0,表示按行进行纵向合并和扩展。
import numpy as np
import pandas as pd
import copy
#设置输出结果对齐方式
pd.set_option('display.unicode.ambiguous_as_wide',True)
pd.set_option('display.unicode.east_asian_width',True)
df = pd.read_excel(r'超市营业额2.xlsx')
df5 = pd.read_excel(r'超市营业额2.xlsx',sheet_name='Sheet2')
#按行拆分
df1 = df[:3]
df2 = df[50:53]
#按行进行合并,要求多个dataFarame结构相同
df3 = pd.concat([df1,df2,df5])
#使用append()方法按行合并,忽略原来的索引
df4 = df1.append([df2,df5],ignore_index=True)
#按列进行拆分
df6 = df.loc[:,['姓名','柜台','交易额']]
print(df1,df2,df3,df4,df[:5],sep='\n\n')
工号 姓名 日期 时段 交易额 柜台
0 1001 张三 2019-03-01 9:00-14:00 1664.0 化妆品
1 1002 李四 2019-03-01 14:00-21:00 954.0 化妆品
2 1003 王五 2019-03-01 9:00-14:00 1407.0 食品
工号 姓名 日期 时段 交易额 柜台
50 1004 赵六 2019-03-07 9:00-14:00 1340.0 食品
51 1004 赵六 2019-03-07 14:00-21:00 942.0 食品
52 1005 周七 2019-03-07 9:00-14:00 1465.0 日用品
工号 姓名 日期 时段 交易额 柜台
0 1001 张三 2019-03-01 9:00-14:00 1664.0 化妆品
1 1002 李四 2019-03-01 14:00-21:00 954.0 化妆品
2 1003 王五 2019-03-01 9:00-14:00 1407.0 食品
50 1004 赵六 2019-03-07 9:00-14:00 1340.0 食品
51 1004 赵六 2019-03-07 14:00-21:00 942.0 食品
52 1005 周七 2019-03-07 9:00-14:00 1465.0 日用品
0 1001 张三 2019-04-01 9:00-14:00 1367.0 化妆品
1 1002 李四 2019-04-01 14:00-21:00 1005.0 化妆品
2 1003 王五 2019-04-01 9:00-14:00 1460.0 食品
3 1004 赵六 2019-04-01 14:00-21:00 1270.0 食品
4 1005 周七 2019-04-01 9:00-14:00 1123.0 日用品
5 1006 钱八 2019-04-01 14:00-21:00 1321.0 日用品
6 1007 孙九 2019-04-01 9:00-14:00 1364.0 蔬菜水果
7 1007 孙九 2019-04-01 14:00-21:00 1633.0 蔬菜水果
工号 姓名 日期 时段 交易额 柜台
0 1001 张三 2019-03-01 9:00-14:00 1664.0 化妆品
1 1002 李四 2019-03-01 14:00-21:00 954.0 化妆品
2 1003 王五 2019-03-01 9:00-14:00 1407.0 食品
3 1004 赵六 2019-03-07 9:00-14:00 1340.0 食品
4 1004 赵六 2019-03-07 14:00-21:00 942.0 食品
5 1005 周七 2019-03-07 9:00-14:00 1465.0 日用品
6 1001 张三 2019-04-01 9:00-14:00 1367.0 化妆品
7 1002 李四 2019-04-01 14:00-21:00 1005.0 化妆品
8 1003 王五 2019-04-01 9:00-14:00 1460.0 食品
9 1004 赵六 2019-04-01 14:00-21:00 1270.0 食品
10 1005 周七 2019-04-01 9:00-14:00 1123.0 日用品
11 1006 钱八 2019-04-01 14:00-21:00 1321.0 日用品
12 1007 孙九 2019-04-01 9:00-14:00 1364.0 蔬菜水果
13 1007 孙九 2019-04-01 14:00-21:00 1633.0 蔬菜水果
工号 姓名 日期 时段 交易额 柜台
0 1001 张三 2019-03-01 9:00-14:00 1664.0 化妆品
1 1002 李四 2019-03-01 14:00-21:00 954.0 化妆品
2 1003 王五 2019-03-01 9:00-14:00 1407.0 食品
3 1004 赵六 2019-03-01 14:00-21:00 1320.0 食品
4 1005 周七 2019-03-01 9:00-14:00 994.0 日用品
——merge()方法
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)
参数right表示另一个DataFrame结构;
参数how的取值可以是'left'、'right'、'outer'或'inner'之一,表示数据连接的方式;
参数on用来指定连接时依据的列名或包含若干列名的列表,要求指定的列名在两个DataFrame中都存在,如果没有任何参数指定连接键则根据两个DataFrame的列名交集进行连接;
参数left_on和right_on分别用来指定连接时依据的左侧列名标签和右侧列名标签。
import numpy as np
import pandas as pd
import copy
#设置输出结果对齐方式
pd.set_option('display.unicode.ambiguous_as_wide',True)
pd.set_option('display.unicode.east_asian_width',True)
df1 = pd.read_excel(r'超市营业额2.xlsx')
df2 = pd.read_excel(r'超市营业额2.xlsx',sheet_name='Sheet3')
#按同名的列合并,随机查看10行数据
rows=np.random.randint(0,len(df1),10)
print(pd.merge(df1,df2).iloc[rows,:],end='\n\n')
#按工号合并,指定其他同名列的后级
print(pd.merge(df1,df2,on='工号', suffixes=['_x','_y']).iloc[rows,:],end='\n\n')
工号 姓名 日期 时段 交易额 柜台 职级
83 1002 李四 2019-03-31 9:00-14:00 1274.0 化妆品 主管
217 1006 钱八 2019-03-05 14:00-21:00 1578.0 日用品 员工
156 1004 赵六 2019-03-22 14:00-21:00 981.0 日用品 员工
171 1005 周七 2019-03-02 9:00-14:00 1444.0 日用品 员工
178 1005 周七 2019-03-06 14:00-21:00 1778.0 蔬菜水果 员工
187 1005 周七 2019-03-12 14:00-21:00 1317.0 化妆品 员工
199 1005 周七 2019-03-20 9:00-14:00 1046.0 食品 员工
52 1002 李四 2019-03-10 9:00-14:00 1478.0 蔬菜水果 主管
55 1002 李四 2019-03-13 14:00-21:00 98.0 日用品 主管
108 1003 王五 2019-03-19 14:00-21:00 1026.0 化妆品 组长
工号 姓名_x 日期 时段 交易额 柜台 姓名_y 职级
83 1002 李四 2019-03-31 9:00-14:00 1274.0 化妆品 李四 主管
217 1006 钱八 2019-03-05 14:00-21:00 1578.0 日用品 钱八 员工
156 1004 赵六 2019-03-22 14:00-21:00 981.0 日用品 赵六 员工
171 1005 周七 2019-03-02 9:00-14:00 1444.0 日用品 周七 员工
178 1005 周七 2019-03-06 14:00-21:00 1778.0 蔬菜水果 周七 员工
187 1005 周七 2019-03-12 14:00-21:00 1317.0 化妆品 周七 员工
199 1005 周七 2019-03-20 9:00-14:00 1046.0 食品 周七 员工
52 1002 李四 2019-03-10 9:00-14:00 1478.0 蔬菜水果 李四 主管
55 1002 李四 2019-03-13 14:00-21:00 98.0 日用品 李四 主管
108 1003 王五 2019-03-19 14:00-21:00 1026.0 化妆品 王五 组长
——join()方法
DataFrame结构的join()方法也可以实现按列对左表(调用join()方法的DataFrame)和右表合并,如果右表other索引与左表某列的值相同可以直接连接,如果要根据右表other中某列的值与左表进行连接,需要先对右表other调用set_index()方法设定该列作为索引。
join(other, on=None, how='left', lsuffix='', rsuffix='', sort=False)
参数other表示另一个DataFrame结构,也就是右表;
参数on用来指定连接时依据的左表列名,如果不指定则按左表索引index的值进行连接;
参数how的含义与merge()方法的how相同;
参数lsuffix和rsuffix用来指定列名的后缀。
#两个表都设置工号列为索引
print(df1.set_index('工号').join(df2.set_index('工号'), lsuffix='_x' ,rsuffix='_y').iloc[rows,:])
姓名_x 日期 时段 交易额 柜台 姓名_y 职级
工号
1002 李四 2019-03-31 9:00-14:00 1274.0 化妆品 李四 主管
1006 钱八 2019-03-05 14:00-21:00 1578.0 日用品 钱八 员工
1004 赵六 2019-03-22 14:00-21:00 981.0 日用品 赵六 员工
1005 周七 2019-03-02 9:00-14:00 1444.0 日用品 周七 员工
1005 周七 2019-03-06 14:00-21:00 1778.0 蔬菜水果 周七 员工
1005 周七 2019-03-12 14:00-21:00 1317.0 化妆品 周七 员工
1005 周七 2019-03-20 9:00-14:00 1046.0 食品 周七 员工
1002 李四 2019-03-10 9:00-14:00 1478.0 蔬菜水果 李四 主管
1002 李四 2019-03-13 14:00-21:00 98.0 日用品 李四 主管
1003 王五 2019-03-19 14:00-21:00 1026.0 化妆品 王五 组长