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 食品
  1. 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    化妆品   王五  组长
posted @ 2023-05-24 20:53  小平凡的记录  阅读(212)  评论(0编辑  收藏  举报