Pandas学习-DataFrame

Pandas学习-DataFrame

参考

1
2
3
pandas是一个python的第三方库,是一个易于使用的数据结构和数据分析工具。在数据探索,数据转换,数据清洗中常用。

pandas包含两种数据结构,series和dataframe。前者处理一维数据(类似list),后者处理二维数据(类似二维数组或者表)。
1
2
3
4
5
6
7
8
9
特点:
-数据清理和预处理:Pandas提供了一系列功能,用于处理丢失数据(缺失值)、重复数据、异常值、数据类型转换等,以使数据变得更加干净和可用于分析。
-数据选择和过滤:Pandas允许使用标签和位置进行数据选择和过滤,包括布尔索引、条件过滤、列选择等。
-数据分组和聚合:Pandas支持数据分组操作,可以对数据进行分组并执行聚合操作,如求和、均值、计数等
-合并和连接:Pandas提供了多种方法来合并和连接不同的数据集,包括数据库风格的连接、拼接和合并操作。
-时间序列处理:Pandas内置了强大的时间序列功能,支持时间索引和时间相关的操作,适用于处理时间序列数据。
-数据可视化:Pandas可以与Matplotlib等数据可视化库集成,帮助用户快速绘制图表和图形,以更好地理解数据。
-读取和存储数据:Pandas支持多种数据格式,包括CSV、Excel、SQL数据库、JSON等,可以方便地读取和存储数据。
-高性能计算:Pandas基于NumPy构建,因此具有高性能的数据处理能力,尤其在处理大规模数据集时非常有效。

DataFrame

1
它的每列数据可以是不同的数据类型,与Series的结构相似,DataFrame也是由索引和数据组成的,不同的是,DataFrame的索引不仅有行索引,还有列索引 

创建

使用字典

1
2
3
4
5
6
>>> d1=DataFrame({'c1':[1,2,3],'c2':[4,5,6],'c3':[7,8,9]})
>>> d1
c1 c2 c3
0 1 4 7
1 2 5 8
2 3 6 9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
创建时指定columns排序列(如果指定不存在的列会出现NaN),index指定行序(如果指定了column,index也得指定)

>>> d1=DataFrame({'c1':[1,2,3],'c2':[4,5,6],'c3':[7,8,9]},columns=['a','b','c'])
>>> d1
Empty DataFrame
Columns: [a, b, c]
Index: []
>>> d1=DataFrame({'c1':[1,2,3],'c2':[4,5,6],'c3':[7,8,9]},columns=['a','b','c'],index=['x','y','z'])
>>> d1
a b c
x NaN NaN NaN
y NaN NaN NaN
z NaN NaN NaN

# 用字典创建dataframe时,可以通过传入columns修改列的顺序
>>> d1=DataFrame({'c1':[1,2,3],'c2':[4,5,6],'c3':[7,8,9]},columns=['c3','c2','c1'],index=['x','y','z'])
>>> d1
c3 c2 c1
x 7 4 1
y 8 5 2
z 9 6 3

使用列表

1
2
3
4
5
6
data_list = [
['张三', 25, '北京'],
['李四', 30, '上海'],
['王五', 35, '广州']
]
df2 = pd.DataFrame(data_list, columns=['姓名', '年龄', '城市'])

使用numpy

1
2
np_data = np.random.randint(1, 100, size=(4, 3))
df3 = pd.DataFrame(np_data, columns=['列1', '列2', '列3'],index=['行1', '行2', '行3', '行4'])

使用Series

1
2
3
4
5
6
s1 = pd.Series([1, 2, 3, 4], name='A')
s2 = pd.Series([5, 6, 7, 8], name='B')
s3 = pd.Series([9, 10, 11, 12], name='C')
df4 = pd.DataFrame({'A': s1, 'B': s2, 'C': s3})

这里name属性没啥用,只是在.info()方法时可以查看series对象的名字

使用csv文件

1
df5 = pd.read_csv('temp_data.csv')

使用Excel文件

1
df5 = pd.read_excel('temp_data.xlsx',sheet_name='xx',header=0,encoding='xx')

空dataframe

1
2
3
4
5
6
7
# 创建空DataFrame并逐步添加数据

df6 = pd.DataFrame()
# 添加列
df6['姓名'] = ['小明', '小红', '小刚']
df6['成绩'] = [85, 92, 78]
df6['班级'] = ['一班', '二班', '一班']

日期索引

1
2
3
4
5
6
7
8
9
print("7. 创建时间序列DataFrame:")
dates = pd.date_range('2024-01-01', periods=5, freq='D')
time_df = pd.DataFrame({
'温度': np.random.randint(20, 35, 5),
'湿度': np.random.randint(40, 80, 5),
'风速': np.random.randint(1, 10, 5)
}, index=dates)
print("时间序列DataFrame:")
print(time_df)
1
2
3
4
5
6
7
时间序列DataFrame:
温度 湿度 风速
2024-01-01 24 42 1
2024-01-02 32 61 6
2024-01-03 21 70 8
2024-01-04 20 57 6
2024-01-05 20 66 7

取值

1
2
3
4
5
6
7
8
series取值:通过[],iloc,loc
[]:
-能用显式标签索引(没有设置默认等于隐式索引,设置后可以是数字类型或者字符串类型)-最简单的方法就是输入变量回车看显示索引是啥
-[x:x]里面只要是数字就是左闭右开,字符串就是左闭又闭
-设置的是字符串索引,还是可以用隐式索引;设置的是数字索引,则隐式索引不能用(取的是标签数字对应的值)

iloc 它使用隐式索引:0-n-1 左闭右开
loc (没有设置默认等于隐式索引,设置后可以是数字类型或者字符串类型)-最简单的方法就是输入变量回车看显示索引是啥 不管是数字还是字符串都是左闭又闭
1
2
3
4
5
6
7
8
dataframe取值:
取行值通过iloc,loc
iloc 只能用隐式索引0-len-1 左闭右开
loc 只能用显式索引 可以是字符串或者数字(以实际显式索引为准) 左闭右闭

取列值通过:
.列 ['列']
loc iloc

单列

[c1]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
d[x] 取的是某一列,结果为series,index仍为dataframe的index

>>> d1
c3 c2 c1
x 7 4 1
y 8 5 2
z 9 6 3
>>> d1['c3']
x 7
y 8
z 9
Name: c3, dtype: int64
>>> type(d1['c3'])
<class 'pandas.core.series.Series'>
.c1
1
2
3
4
5
6
7
.x取值也可以

>>> d1.c3
x 7
y 8
z 9
Name: c3, dtype: int64
loc iloc
1
2
employee.loc[:,'id'] #取id这一列
employee.iloc[:,0]

多列

[‘c1’,’c2’]
1
2
取多列,结果为dataframe
df[['name', 'age']]
loc iloc
1
2
3
4
employee.loc[:,'id':'name'] # 取id到name这几列
employee.loc[:,['id','name']]
employee.iloc[:,0:2]
employee.iloc[:,[0,2]]

iloc
1
2
3
4
5
6
7
8
# 访问第一行:
print(df.iloc[0])

# 访问前两行:
print(df.iloc[0:2]) #左闭右开

# 取奇数行
print(df.iloc[0:5:2])
loc
1
2
3
4
这里只列举了行标签被设置为字符串的情况
employee.loc[['a','b']]
employee.loc['b']
employee.loc['a':'b']

取行列

loc
1
2
3
4
5
data = [[1, 'Joe', 70000, 3], [2, 'Henry', 80000, 4], [3, 'Sam', 60000, ], [4, 'Max', 90000, None]]
employee = pd.DataFrame(data, columns=['id', 'name', 'salary', 'managerId'],index=['a','b','c','d']).astype({'id':'Int64', 'name':'object', 'salary':'Int64','managerId':'Int64'})

employee.loc[['a','b'],['id','salary']]
employee.loc['a':'b',['id','salary']]
1
2
3
employee.loc['a',['id','salary']]
employee.loc['a','id']
employee.loc[['a','c'],'id']
1
2
3
employee.loc[:,['id','salary']] # 取id,salary这两列
employee.loc[['a','c'],['id','salary']] # 取两行两列
employee.loc['a':'c',['id','salary']] # 取3行两列
iloc
1
2
data = [[1, 'Joe', 70000, 3], [2, 'Henry', 80000, 4], [3, 'Sam', 60000, ], [4, 'Max', 90000, None]]
employee = pd.DataFrame(data, columns=['id', 'name', 'salary', 'managerId'],index=['a','b','c','d']).astype({'id':'Int64', 'name':'object', 'salary':'Int64','managerId':'Int64'})
1
2
employee.iloc[[0,2],[0,2]] # 取两行两列
employee.iloc[0,[0,2]] # 取1行两列

修改

参考

插入列 insert和[]和concat

insert
1
2
3
4
5
df = pd.DataFrame(data=[['lisa', 'f', 22], ['joy', 'f', 22], ['tom', 'm', 21]], columns=['name', 'sex', 'age'])
citys = ['ny', 'zz', 'xy']
df.insert(0, 'city', citys) # 在第0列插入新列 'city'

没有inplace和axis参数 原本就是对列插入和对原数据影响
[]
1
2
3
尾部插入
jobs = ['student', 'AI', 'teacher']
df['job'] = jobs # 在最后一列增加新列 'job'
1
2
3
4
5
6
7
8
9
10
11
12
# 添加新列:
df['salary_level'] = df['salary'].apply(lambda x: '高' if x > 12000 else '中' if x > 9000 else '低')
df['age_group'] = pd.cut(df['age'], bins=[0, 30, 35, 100], labels=['青年', '中年', '资深'])
print("添加薪资等级和年龄组:")

name age city salary department salary_level age_group
0 张三 25 北京 8000 IT 低 青年
1 李四 30 上海 12000 HR 中 青年
2 王五 35 广州 15000 IT 高 中年
3 赵六 28 深圳 10000 Finance 中 青年
4 钱七 32 杭州 13000 IT 高 中年
5 孙八 27 成都 9000 HR 低 青年

插入行 loc append concat

loc
1
2
3
4
5
6
7
8
>>> df.loc[4] = ['zz','mason','m',24,'engineer’]
#若df中没有index为“4”的这一行的话,该行代码作用是往df中加一行index为“4”,值为等号右边值的数据。
#若df中已经有index为“4”的这一行(也不一定是一行,因为显式标签不一定唯一,那么修改的就是多行),则该行代码作用是把df中index为“4”的这一行修改为等号右边数据。

# 创建一个 DataFrame
df = pd.DataFrame({'Name': ['Alice', 'Bob'], 'Age': [25, 30]})
# 使用 loc 添加新行
df.loc[len(df)] = ['Charlie', 35]
append
1
2
3
4
5
6
7
8
9
10
>>> df_insert = pd.DataFrame({'name':['mason','mario'],'sex':['m','f'],'age':[21,22]},index = [4,5])
>>> ndf = df.append(df_insert,ignore_index = True)
#返回添加后的值,并不会修改df的值。ignore_index默认为False,意思是不忽略index值,即生成的新的ndf的index采用df_insert中的index值。若为True,则新的ndf的index值不使用df_insert中的index值,而是自己默认生成。


df = pd.DataFrame({'Name': ['Alice', 'Bob'], 'Age': [25, 30]})
# 创建新行的 DataFrame
new_row = pd.DataFrame({'Name': ['Charlie'], 'Age': [35]})
# 使用 append 添加新行(不推荐)
df = df.append(new_row, ignore_index=True)
concat
1
2
3
4
5
6
7
8
# 创建一个 DataFrame
df = pd.DataFrame({'Name': ['Alice', 'Bob'], 'Age': [25, 30]})

# 创建新行的 DataFrame
new_rows = pd.DataFrame({'Name': ['Charlie', 'David'], 'Age': [35, 40]})

# 使用 concat 添加新行
df = pd.concat([df, new_rows], ignore_index=True)
某个位置插入行
1
2
3
4
5
6
7
df = pd.DataFrame({"姓名": ["老许", "虎子"],"种类": ["猫", "狗"], "重量": ["10", "15"]})
data = pd.DataFrame({
'姓名': ["老许二代", "二赖子"],
'种类': ["黑猫", "花狗"],
'重量': [3, 15]
})
df2 = pd.concat([df.loc[:0], data, df.loc[1:]]).reset_index(drop=True)

修改数据类型

1
2
3
df.astype({'user_id':'Int64', 'tweet_id':'Int64','tweet':'object','tweet_date':'object'})

#修改的类型,str。{'str','int','float','',....}
1
2
3
4
5
6
7
8
import pandas as pd
#读取数据
df = pd.read_excel(r'C:\Users\XXXXXX\Desktop\pandas练习文档.xlsx',sheet_name=2)
# print(df.head(5))
print(df.info())
#将'age'这一列改成浮点类型。#注意先将缺失值填充后再修改。
df['age'] = df['age'].fillna('0').astype('float')
print(df.info())

标题

列标题
1
2
>>> df.columns = ['name','gender','age'] #尽管我们只想把’sex’改为’gender’,但是仍然要把所有的列全写上,否则报错。
>>> df.rename(columns = {'name':'Name','age':'Age'},inplace = True) #只修改name和age。inplace若为True,直接修改df,否则,不修改df,只是返回一个修改后的数据。

设置索引

参考

.index
1
2
>>> df.index = list('abc')#把index改为a,b,c.直接修改了df。
>>> df.rename({1:'a',2:'b',3:'c'},axis = 0,inplace = True)#无返回值,直接修改df的index。
1
df.index = [i for i in range(1,len(df)+1)]
修改索引标签名
1
2
3
4
#方法1:
df.index.name = 'index_col'
#方法2:
df.rename_axis('index_col',inplace=True)
set_index( )
1
注意就算重新设置过索引,但是默认的0-n的隐式索引还是可以使用,也就是可以使用iloc进行访问,series可以[index]
1
2
3
4
5
6
7
8
DataFrame.set_index(keys, drop=True, append=False, inplace=False, verify_integrity=False)

参数解释:
keys:列标签或列标签/数组列表,需要设置为索引的列
drop:默认为True,删除用作新索引的列
append:是否将列附加到现有索引,默认为False。
inplace:输入布尔值,表示当前操作是否对原数据生效,默认为False。
verify_integrity:检查新索引的副本。否则,请将检查推迟到必要时进行。将其设置为false将提高该方法的性能,默认为false。
1
2
3
4
5
6
7
import pandas as pd
import numpy as np
df = pd.DataFrame({'Country':['China','China', 'India', 'India', 'America', 'Japan', 'China', 'India'],

'Income':[10000, 10000, 5000, 5002, 40000, 50000, 8000, 5000],

'Age':[50, 43, 34, 40, 25, 25, 45, 32]})
drop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
下面我们尝试将Country这一列作为索引:

df_new = df.set_index('Country',drop=True, append=False, inplace=False, verify_integrity=False)

可以看到,在上一步的代码中,是指定了drop=True,也就是删除用作新索引的列

Income Age
Country
China 10000 50
China 10000 43
India 5000 34
India 5002 40
America 40000 25
Japan 50000 25
China 8000 45
India 5000 32
1
2
3
4
5
6
7
8
9
10
11
>>> df.set_index('Country',drop=False, append=False, inplace=False, verify_integrity=False)
Country Income Age
Country
China China 10000 50
China China 10000 43
India India 5000 34
India India 5002 40
America America 40000 25
Japan Japan 50000 25
China China 8000 45
India India 5000 32
append
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
下面,我们再探索一下append参数的用法。(append的用法:是否将列附加到现有索引,默认为False。)

df.set_index('Country',drop=True, append=True, inplace=False, verify_integrity=False)
Income Age
Country
0 China 10000 50
1 China 10000 43
2 India 5000 34
3 India 5002 40
4 America 40000 25
5 Japan 50000 25
6 China 8000 45
7 India 5000 32

可以看到,原来的索引和新索引一起被保留下来了
1
2
3
4
5
6
7
8
9
10
11
>>> df.set_index('Country',drop=False, append=False, inplace=False, verify_integrity=False)
Country Income Age
Country
China China 10000 50
China China 10000 43
India India 5000 34
India India 5002 40
America America 40000 25
Japan Japan 50000 25
China China 8000 45
India India 5000 32
设置层级索引
.set_index()
1
2
3
4
5
import pandas as pd
#读取数据
df = pd.read_excel(r'C:\Users\XXXXXX\Desktop\pandas练习文档.xlsx',sheet_name=4)
# print(df.head(5))
df = df.set_index(['国家/地区','区域','城市'])
index_col=[]
1
2
3
4
5
df = pd.read_excel(r'C:\Users\XXXXXX\Desktop\pandas练习文档.xlsx',sheet_name=4,index_col=[0,1])

df.index

df.index.names
取值
1
2
3
4
5
6
7
order
...
11 20 a b c
11 19 e x y
11 1 d q e
8 7 p i u
...
1
2
3
4
5
6
7
order.loc[11].loc[19]
或者
order.loc[(11,9),:] #等于order.loc[(11,9)]
或者
order.loc[(11,[20,19]),:] #等于order.loc[(11,[20,19])]

这里取的是所有列,要取固定列和前面的取值方法一样的
reset_index( )
1
DataFrame.reset_index(level=None, drop=False, inplace=False, col_level=0, col_fill='')
1
2
3
4
5
6
7
8
9
level:数值类型可以为:int、str、tuple或list,默认无,仅从索引中删除给定级别。默认情况下移除所有级别。控制了具体要还原的那个等级的索引 。

drop:当指定drop=False时,则索引列会被还原为普通列;否则,经设置后的新索引值被会丢弃。默认为False。

inplace:输入布尔值,表示当前操作是否对原数据生效,默认为False。

col_level:数值类型为int或str,默认值为0,如果列有多个级别,则确定将标签插入到哪个级别。默认情况下,它将插入到第一级。

col_fill:对象,默认‘’,如果列有多个级别,则确定其他级别的命名方式。如果没有,则重复索引名。
在使用set_index()后的基础上
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
df_new = df.set_index('Country',drop=True, append=False, inplace=False, verify_integrity=False)


下面,用reset_index()函数进行还原:(看清楚哦,这个时候我们指定drop=False)
df_new01 = df_new.reset_index(drop=False)

>>> df_new.reset_index(drop=False)
Country Income Age
0 China 10000 50
1 China 10000 43
2 India 5000 34
3 India 5002 40
4 America 40000 25
5 Japan 50000 25
6 China 8000 45
7 India 5000 32

可以看到,被作为索引的列被还原成原来的样子
1
2
3
4
5
6
7
8
9
10
>>> df_new.reset_index(drop=True)
Income Age
0 10000 50
1 10000 43
2 5000 34
3 5002 40
4 40000 25
5 50000 25
6 8000 45
7 5000 32
在原表没有set_index的基础上
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
>>> df
Country Income Age
0 China 10000 50
1 China 10000 43
2 India 5000 34
3 India 5002 40
4 America 40000 25
5 Japan 50000 25
6 China 8000 45
7 India 5000 32

df.reset_index(drop=False)

>>> df.reset_index(drop=False)
index Country Income Age
0 0 China 10000 50
1 1 China 10000 43
2 2 India 5000 34
3 3 India 5002 40
4 4 America 40000 25
5 5 Japan 50000 25
6 6 China 8000 45
7 7 India 5000 32
1
可以看到,此时数据表在原有的索引不变的基础上,添加了列名为index的新列,同时在新列上进行重置索引。
1
2
3
4
5
6
7
8
9
10
11
12
>>> df.reset_index(drop=True)
Country Income Age
0 China 10000 50
1 China 10000 43
2 India 5000 34
3 India 5002 40
4 America 40000 25
5 Japan 50000 25
6 China 8000 45
7 India 5000 32

可以看到,输出结果和原来的数据表没有区别。但是其实在这个时候是有操作的,是在原有的索引列重置索引,同时不另外添加新列。这个常用于索引的重置,在进行数据删减处理的时候能派上很大的用场哦

分组聚合

聚合函数

np.
1
2
3
4
5
np.min(df[[列1,列2...]],axis=0) 按着每一行操作,作用到每一列
np.max(df[[列1,列2...]],axis=0)
np.median([[列1,列2...]],axis=0)
np.mean([[列1,列2...]],axis=0)
...
df.
1
2
3
4
5
6
7
8
9
10
11
12
13
df[[列1,列2...]].max(axis=0)
.mean
.min
.median
.cumsum 累加
.sum
.quantile([0,0.2,0.5,1],axis=0)
.min,max,mean
...

.describe() # 统计每一个数值类型列的各个指标,include=['object']时统计非数值类型


1
2
3
4
5
6
7
8
9
10
11
.describe(include=['object'])
col .. coln
count
unique
top
freq

count:非缺失值个数
unique:唯一值个数
top:出现频率最高的值
freq:top值出现的次数

参考

1
2
3
4
5
6
# 按部门分组统计:
dept_stats = df.groupby('department').agg({
'salary': ['mean', 'max', 'min', 'count'],
'age': 'mean'
})
print(dept_stats)
1
2
3
4
5
6
             salary                            age
mean max min count mean
department
Finance 10000.0 10000 10000 1 28.000000
HR 10500.0 12000 9000 2 28.500000
IT 12000.0 15000 8000 3 30.666667

分组

单列分组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pandas as pd

# 创建示例数据
data = {
'name': ['Alice', 'Bob', 'Charlie', 'Alice', 'Bob'],
'city': ['New York', 'London', 'Paris', 'New York', 'London'],
'sales': [100, 200, 300, 150, 250]
}
df = pd.DataFrame(data)

# 按name分组并计算sales的总和
grouped = df.groupby('name')['sales'].sum()

type(grouped):DataFrameGroupBy 分组对象
1
2
3
4
5
6
7
8
9
10
11
12
grouped = vgsales.groupby('Year').mean() 
grouped.mean()
#根据年份分组,统计数值类型所有列的均值
col1 col2 ...
1988
1980
1999
...

grouped.count() #相当于统计每一个年份下各个列的非空缺值个数
grouped.size() #每一个年份下,样本个数
grouped.umcount() # 返回元素在对应分组里的位置0开始
多列分组
1
2
3
4
5
6
7
8
9
10
11
12
13
import pandas as pd

# 创建示例数据
data = {
'name': ['Alice', 'Bob', 'Charlie', 'Alice', 'Bob'],
'city': ['New York', 'London', 'Paris', 'New York', 'London'],
'category': ['A', 'B', 'A', 'B', 'A'],
'sales': [100, 200, 300, 150, 250]
}
df = pd.DataFrame(data)

# 按name和city分组并计算sales的平均值
grouped = df.groupby(['name', 'city'])['sales'].mean() # 先分组,再取列,再统计
1
2
3
4
grouped = vgsales[['c1','c2'...,'Year','Genre']].groupby(['Year','Genre']) 
grouped.mean() #先取列,再分组,再统计

结果是层次索引的dataframe

image-20250726170844972

多个聚合函数
1
2
3
4
5
6
7
8
9
10
11
12
import pandas as pd

# 创建示例数据
data = {
'name': ['Alice', 'Bob', 'Charlie', 'Alice', 'Bob'],
'city': ['New York', 'London', 'Paris', 'New York', 'London'],
'sales': [100, 200, 300, 150, 250]
}
df = pd.DataFrame(data)

# 按name分组并应用多个聚合函数
grouped = df.groupby('name')['sales'].agg(['sum', 'mean', 'max', 'min'])

.agg()

.agg([xxx,xxx]) 对列使用相同的聚合函数
1
也可以是单个函数,不用[]
1
2
3
4
5
6
7
8
9
10
11
12
13
vgsales=pd.DataFrame(xxx)
names=['xxx','xxx'...]
grouped=vgsales[names].groupby('Year')
grouped.agg([np.mean,np.sum]) # 结果列上是层次索引

NA_Sales EU_Sales ...
mean sum mean sum
Year
1980 1.17 10.5 0.07 0.67
...

grouped.agg([np.mean,np.sum]).loc[[1980,1981],('NA_Sales','sum')] # 对列上的层次索引进行访问
grouped.agg([np.mean,np.sum]).loc[[1980,1981],('NA_Sales',['sum','mean'])]
.agg({‘xx’:xx,’xx’:xx}) 为列指定不同的聚合函数
1
grouped.agg({'NA_Sales':np.sum,'EU_Sales':np.mean}) #这种方式只会对指定列进行计算
1
grouped.agg({'NA_Sales':[np.sum,np.median],'EU_Sales':[np.mean,np.sum]})
自定义函数
1
2
3
4
5
def DoubleSum(data):
s=data.sum()*2
return s

grouped.agg({'NA_Sales':DoubleSum})

.apply()

1
2
3
4
var_names = [xx,xx...]
vgsales[var_names].apply(np.sum,axis=0) # 计算指定列的和

vgsales[var_names].apply(np.sum,axis=1) # 计算每一行的和
自定义函数
1
vgsales[var_names].apply(lambda x:x[2]-x[3],axis=1) # 计算每一行的第三列-第四列

.transform() 分组转换

1
vgsales[var_name].transform(lambda x:x*2)
与groupby搭配
1
2
3
4
5
6
7
8
9
10
11
12
13
groupby还支持转换操作,可以将结果广播回原始DataFrame的形状:

import pandas as pd
# 创建示例数据
data = {
'name': ['Alice', 'Bob', 'Charlie', 'Alice', 'Bob'],
'city': ['New York', 'London', 'Paris', 'New York', 'London'],
'sales': [100, 200, 300, 150, 250]
}
df = pd.DataFrame(data)

# 按name分组并计算每组的平均值,然后广播回原始DataFrame
df['sales_mean'] = df.groupby('name')['sales'].transform('mean')

总结

1
2
3
4
agg:方法灵活,能够对分组对象进行相同的聚合,还可以选择不同的聚合方法
apply: apply可以进行聚合计算,还可以按行计算
transform:返回与数据同样长度的行,无法进行聚合
建议:建议今后在更多使用apply或者agg

数据透视表

1
2
3
4
5
6
7
pivot_table = df.pivot_table(
values='salary',
index='department',
columns='age_group',
aggfunc='mean',
fill_value=0
)
1
2
3
4
5
6
# 部门-年龄组薪资透视表:
age_group 青年 中年
department
Finance 10000.0 0.0
HR 10500.0 0.0
IT 8000.0 14000.0

缺失值处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 创建包含缺失值的数据
df_with_nan = df.copy()
df_with_nan.loc[1, 'salary'] = np.nan
df_with_nan.loc[3, 'age'] = np.nan

# 包含缺失值的数据:
print(df_with_nan)
# 缺失值统计:
print(df_with_nan.isnull().sum())

# 删除包含缺失值的行:
print(df_with_nan.dropna())
# 用均值填充缺失值:
df_filled = df_with_nan.fillna(df_with_nan.mean(numeric_only=True))
print(df_filled)
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
包含缺失值的数据:
name age city salary department salary_level age_group
0 张三 25.0 北京 8000.0 IT 低 青年
1 李四 30.0 上海 NaN HR 中 青年
2 王五 35.0 广州 15000.0 IT 高 中年
3 赵六 NaN 深圳 10000.0 Finance 中 青年
4 钱七 32.0 杭州 13000.0 IT 高 中年
5 孙八 27.0 成都 9000.0 HR 低 青年

缺失值统计:
name 0
age 1
city 0
salary 1
department 0
salary_level 0
age_group 0
dtype: int64

删除包含缺失值的行:
name age city salary department salary_level age_group
0 张三 25.0 北京 8000.0 IT 低 青年
2 王五 35.0 广州 15000.0 IT 高 中年
4 钱七 32.0 杭州 13000.0 IT 高 中年
5 孙八 27.0 成都 9000.0 HR 低 青年

用均值填充缺失值:
name age city salary department salary_level age_group
0 张三 25.0 北京 8000.0 IT 低 青年
1 李四 30.0 上海 11000.0 HR 中 青年
2 王五 35.0 广州 15000.0 IT 高 中年
3 赵六 29.8 深圳 10000.0 Finance 中 青年
4 钱七 32.0 杭州 13000.0 IT 高 中年
5 孙八 27.0 成都 9000.0 HR 低 青年

.merge()

1
和关系型数据库的join操作一样,将两个表的数据记录连接

内连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
有用相同的列

>>> d2
c1 b c2
x 1 NaN 4
y 2 NaN 5
z 3 NaN 6
>>> d1
c3 c2 c1
x 7 4 1
y 8 5 2
z 9 6 3
>>> pd.merge(d1,d2,on='c1')
c3 c2 c1 b
0 7 4 1 NaN
1 8 5 2 NaN
2 9 6 3 NaN
1
2
3
4
5
6
7
用不同的列

>>> pd.merge(left=d1,right=d2,left_on='c1',right_on='c1')
c3 c2_x c1 b c2_y
0 7 4 1 NaN 4
1 8 5 2 NaN 5
2 9 6 3 NaN 6

外连接

1
how='outer' left right 可以实现全外 左 右 外连接 inner默认
1
2
3
4
5
6
7
8
9
# 创建另一个DataFrame
bonus_data = {
'name': ['张三', '李四', '王五', '新员工'],
'bonus': [2000, 3000, 4000, 1000]
}
bonus_df = pd.DataFrame(bonus_data)

# 合并数据
merged_df = pd.merge(df[['name', 'salary', 'department']], bonus_df, on='name', how='left')
1
2
3
4
5
6
7
8
合并后的数据:
name salary department bonus
0 张三 8000 IT 2000.0
1 李四 12000 HR 3000.0
2 王五 15000 IT 4000.0
3 赵六 10000 Finance NaN
4 钱七 13000 IT NaN
5 孙八 9000 HR NaN

使用多个键连接

1
2
3
4
5
>>> pd.merge(d1,d2,on=['c1','c2'])
c3 c2 c1 b
0 7 4 1 NaN
1 8 5 2 NaN
2 9 6 3 NaN
1
pd.merge(df1,df2,left_on=['xx','xx'],right_on=['xx','xx'])

left_index,right_index

1
2
3
4
5
6
很少用

当想用一个dataframe的index作为连接键时,就需要用到left_index,right_index
默认还是inner join

pd.merge(d5,d6,left_on='xx',right_index='xx')

sort参数

1
2
是否按照连接键排序
pd.merge(d5,d6,left_on='xx',right_index='xx',sort=True)

.concat()

series

1
2
3
类似于numpy的concatenate操作,进行串接

默认axis=0
1
2
3
4
5
6
7
8
9
10
11
12
>>> s1=Series(['a','b'])
>>> s2=Series(['c','d'])
>>> s3=Series(['e','f','g'])
>>> pd.concat([s1,s2,s3])
0 a
1 b
0 c
1 d
0 e
1 f
2 g
dtype: object
1
2
3
4
5
>>> pd.concat([s1,s2,s3],axis=1)
0 1 2
0 a c e
1 b d f
2 NaN NaN g
1
2
3
4
5
默认为outer操作
>>> pd.concat([s1,s2,s3],axis=1,join='inner')
0 1 2
0 a c e
1 b d f

dataframe

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> df1=DataFrame(np.arange(6).reshape(3,2),index=['a','b','c'],columns=['one','two'])
>>> df2=DataFrame(5+np.arange(4).reshape(2,2),index=['a','c'],columns=['three','four'])
>>> df1
one two
a 0 1
b 2 3
c 4 5
>>> df2
three four
a 5 6
c 7 8
>>> pd.concat([df1,df2],axis=1)
one two three four
a 0 1 5.0 6.0
b 2 3 NaN NaN
c 4 5 7.0 8.0

运算

1
np.random.seed(42)  # 设置随机种子以获得可重复的结果

mean

1
2
3
4
5
6
7
8
9
10
11
12
结果为series

>>> d1.mean()
c3 8.0
c2 5.0
c1 2.0
dtype: float64
>>> d1.sum()
c3 24
c2 15
c1 6
dtype: int64

sum

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
两个dataframe相加,相同的列才可以

>>> d2=DataFrame({'c1':[1,2,3],'c2':[4,5,6],'c3':[7,8,9]},columns=['c1','b','c2'],index=['x','y','z'])
>>> d2
c1 b c2
x 1 NaN 4
y 2 NaN 5
z 3 NaN 6
>>> d1
c3 c2 c1
x 7 4 1
y 8 5 2
z 9 6 3
>>> d2+d1
b c1 c2 c3
x NaN 2 8 NaN
y NaN 4 10 NaN
z NaN 6 12 NaN

条件筛选

1
2
3
4
5
6
7
8
data = {
'name': ['张三', '李四', '王五', '赵六', '钱七', '孙八'],
'age': [25, 30, 35, 28, 32, 27],
'city': ['北京', '上海', '广州', '深圳', '杭州', '成都'],
'salary': [8000, 12000, 15000, 10000, 13000, 9000],
'department': ['IT', 'HR', 'IT', 'Finance', 'IT', 'HR']
}
df = pd.DataFrame(data)
1
2
3
4
5
6
7
8
9
10
# 薪资大于10000的员工:
high_salary = df[df['salary'] > 10000]
print(high_salary)

name age city salary department
1 李四 30 上海 12000 HR
2 王五 35 广州 15000 IT
4 钱七 32 杭州 13000 IT


1
2
3
4
5
6
7
8
9
# IT部门的员工:
it_employees = df[df['department'] == 'IT']
print(it_employees)

IT部门的员工:
name age city salary department
0 张三 25 北京 8000 IT
2 王五 35 广州 15000 IT
4 钱七 32 杭州 13000 IT
1
2
3
4
5
6
7
8
# 多条件筛选(IT部门且薪资>10000):
it_high_salary = df[(df['department'] == 'IT') & (df['salary'] > 10000)]
print(it_high_salary)

多条件筛选(IT部门且薪资>10000):
name age city salary department
2 王五 35 广州 15000 IT
4 钱七 32 杭州 13000 IT

数据排序

参考

sort_values
1
2
3
na_position:last,first设置空缺值排在什么位置

排序之后,索引标签是乱的,可以用reset_index()重置
按单列排序
1
2
3
4
5
6
7
8
9
10
11
# 按薪资降序排列:
sorted_by_salary = df.sort_values('salary', ascending=False,na_position='last')

按薪资降序排列:
name age city salary department
2 王五 35 广州 15000 IT
4 钱七 32 杭州 13000 IT
1 李四 30 上海 12000 HR
3 赵六 28 深圳 10000 Finance
5 孙八 27 成都 9000 HR
0 张三 25 北京 8000 IT
按多列排序
1
2
3
4
5
6
7
8
9
10
11
# 按部门和薪资排序:
sorted_multi = df.sort_values(['department', 'salary'], ascending=[True, False])

按部门和薪资排序:
name age city salary department
3 赵六 28 深圳 10000 Finance
1 李四 30 上海 12000 HR
5 孙八 27 成都 9000 HR
2 王五 35 广州 15000 IT
4 钱七 32 杭州 13000 IT
0 张三 25 北京 8000 IT
rank
dense
1
2
3
4
5
6
7
8
import pandas as pd

# 创建示例数据
data = {'score': [85, 90, 80, 95, 85]}
df = pd.DataFrame(data)

# 计算排名
df['rank'] = df['score'].rank(method='dense', ascending=False)
average(默认)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pandas as pd
# 创建示例数据
data = {'score': [85, 90, 80, 95, 85]}
df = pd.DataFrame(data)

# 使用不同的方法处理平局
df['rank_average'] = df['score'].rank(method='average', ascending=False)

score rank rank_average
0 85 3.0 3.5
1 90 2.0 2.0
2 80 4.0 5.0
3 95 1.0 1.0
4 85 3.0 3.5
min
1
相同的值取较小的排名
1
2
3
4
5
6
7
8
df['rank_min'] = df['score'].rank(method='min', ascending=False)

score rank rank_average rank_min
0 85 3.0 3.5 3.0
1 90 2.0 2.0 2.0
2 80 4.0 5.0 5.0
3 95 1.0 1.0 1.0
4 85 3.0 3.5 3.0
max
1
相同的值取较大的排名
1
2
3
4
5
6
7
8
df['rank_max'] = df['score'].rank(method='max', ascending=False)

score rank rank_average rank_min rank_max
0 85 3.0 3.5 3.0 4.0
1 90 2.0 2.0 2.0 2.0
2 80 4.0 5.0 5.0 5.0
3 95 1.0 1.0 1.0 1.0
4 85 3.0 3.5 3.0 4.0
first
1
值相同按出现顺序排列,不允许并列。
1
2
3
4
5
6
7
8
9
df['rank_first'] = df['score'].rank(method='first', ascending=False)

>>> df
score rank rank_average rank_min rank_max rank_first
0 85 3.0 3.5 3.0 4.0 3.0
1 90 2.0 2.0 2.0 2.0 2.0
2 80 4.0 5.0 5.0 5.0 5.0
3 95 1.0 1.0 1.0 1.0 1.0
4 85 3.0 3.5 3.0 4.0 4.0
应用于整个DataFrame
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
这个例子展示了如何对DataFrame中的每一列进行排名

import pandas as pd

# 创建示例数据
data = {
'math': [85, 90, 80, 95, 85],
'physics': [88, 92, 78, 96, 86],
'chemistry': [82, 88, 76, 94, 84]
}
df = pd.DataFrame(data)

# 对每列进行排名
df_ranked = df.rank(ascending=False)

print("pandasdataframe.com - Ranking in DataFrame:")
print(df_ranked)
1
2
3
4
5
6
  math  physics  chemistry
0 3.5 3.0 4.0
1 2.0 2.0 2.0
2 5.0 5.0 5.0
3 1.0 1.0 1.0
4 3.5 4.0 3.0
分组内排名
1
2
3
4
5
6
7
8
9
10
11
12
import pandas as pd

# 创建示例数据
data = {
'name': ['Alice', 'Bob', 'Charlie', 'Alice', 'Bob'],
'subject': ['Math', 'Math', 'Math', 'Physics', 'Physics'],
'score': [85, 90, 80, 95, 88]
}
df = pd.DataFrame(data)

# 在每个subject组内对score进行排名
df['rank'] = df.groupby('subject')['score'].rank(method='dense', ascending=False)
1
2
3
4
5
6
      name  subject  score  rank
0 Alice Math 85 2.0
1 Bob Math 90 1.0
2 Charlie Math 80 3.0
3 Alice Physics 95 1.0
4 Bob Physics 88 2.0
计算组内百分比排名
1
2
3
4
5
6
7
8
9
10
11
12
import pandas as pd

# 创建示例数据
data = {
'name': ['Alice', 'Bob', 'Charlie', 'Alice', 'Bob'],
'department': ['Sales', 'Sales', 'Marketing', 'Marketing', 'Sales'],
'sales': [100, 200, 300, 150, 250]
}
df = pd.DataFrame(data)

# 计算每个department内的百分比排名
df['percentile'] = df.groupby('department')['sales'].rank(pct=True)
1
2
3
4
5
6
      name department  sales  percentile
0 Alice Sales 100 0.333333
1 Bob Sales 200 0.666667
2 Charlie Marketing 300 1.000000
3 Alice Marketing 150 0.500000
4 Bob Sales 250 1.000000
跨组的相对排名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import pandas as pd

# 创建示例数据
data = {
'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
'department': ['Sales', 'Sales', 'Marketing', 'Marketing', 'HR'],
'score': [85, 90, 80, 95, 88]
}
df = pd.DataFrame(data)

# 计算每个department的平均分
dept_mean = df.groupby('department')['score'].transform('mean')

# 计算每个人相对于其department平均分的差异
df['relative_score'] = df['score'] - dept_mean

# 对相对分数进行排名
df['relative_rank'] = df['relative_score'].rank(ascending=False)

image-20250720094744676

计算滚动排名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pandas as pd

# 创建示例数据
data = {
'date': pd.date_range(start='2023-01-01', periods=10),
'sales': [100, 150, 120, 200, 180, 220, 190, 210, 230, 250]
}
df = pd.DataFrame(data)

# 计算3天滚动窗口内的排名
df['rolling_rank'] = df['sales'].rolling(window=3).rank(ascending=False)

print("pandasdataframe.com - Rolling ranking:")
print(df)

image-20250720094800441

计算累积排名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pandas as pd

# 创建示例数据
data = {
'date': pd.date_range(start='2023-01-01', periods=10),
'sales': [100, 150, 120, 200, 180, 220, 190, 210, 230, 250]
}
df = pd.DataFrame(data)

# 计算累积排名
df['cumulative_rank'] = df['sales'].expanding().rank(method='min')

print("pandasdataframe.com - Cumulative ranking:")
print(df)

image-20250720094813876

计算分组累积排名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import pandas as pd

# 创建示例数据
data = {
'date': pd.date_range(start='2023-01-01', periods=10).repeat(2),
'product': ['A', 'B'] * 10,
'sales': [100, 150, 120, 200, 180, 220, 190, 210, 230, 250,
110, 140, 130, 190, 170, 210, 200, 220, 240, 260]
}
df = pd.DataFrame(data)

# 计算每个产品的累积排名
df['cumulative_rank'] = df.groupby('product')['sales'].expanding().rank(method='min').reset_index(level=0, drop=True)

print("pandasdataframe.com - Grouped cumulative ranking:")
print(df)

image-20250720094457168

计算排名的百分位数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import pandas as pd
import numpy as np

# 创建示例数据
data = {
'score': np.random.randint(60, 100, 100)
}
df = pd.DataFrame(data)

# 计算排名
df['rank'] = df['score'].rank(method='min')

# 计算排名的百分位数
df['percentile'] = df['rank'].apply(lambda x: (x - 1) / (len(df) - 1) * 100)

print("pandasdataframe.com - Ranking percentiles:")
print(df.head())

image-20250720094625615

计算分组内的Top N
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import pandas as pd

# 创建示例数据
data = {
'department': ['Sales', 'Sales', 'Marketing', 'Marketing', 'HR', 'HR'] * 5,
'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve', 'Frank'] * 5,
'score': [85, 90, 80, 95, 88, 92, 78, 82, 89, 91, 86, 84,
93, 87, 81, 94, 90, 88, 79, 83, 92, 96, 85, 89,
91, 88, 82, 97, 89, 93]
}
df = pd.DataFrame(data)

# 计算每个部门内的排名
df['rank'] = df.groupby('department')['score'].rank(method='first', ascending=False)

# 选择每个部门的Top 3
top_3 = df[df['rank'] <= 3].sort_values(['department', 'rank'])

print("pandasdataframe.com - Top 3 in each department:")
print(top_3)

image-20250720094356902

计算分组内的百分比排名差异
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import pandas as pd

# 创建示例数据
data = {
'department': ['Sales', 'Sales', 'Marketing', 'Marketing', 'HR', 'HR'] * 5,
'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve', 'Frank'] * 5,
'score': [85, 90, 80, 95, 88, 92, 78, 82, 89, 91, 86, 84,
93, 87, 81, 94, 90, 88, 79, 83, 92, 96, 85, 89,
91, 88, 82, 97, 89, 93]
}
df = pd.DataFrame(data)

# 计算每个部门内的百分比排名
df['dept_percentile'] = df.groupby('department')['score'].rank(pct=True)

# 计算整体的百分比排名
df['overall_percentile'] = df['score'].rank(pct=True)

# 计算百分比排名差异
df['percentile_diff'] = df['dept_percentile'] - df['overall_percentile']

print("pandasdataframe.com - Percentile ranking difference:")
print(df.head(10))

image-20250720094055062

计算移动窗口内的排名变化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import pandas as pd

# 创建示例数据
data = {
'date': pd.date_range(start='2023-01-01', periods=10),
'sales': [100, 150, 120, 200, 180, 220, 190, 210, 230, 250]
}
df = pd.DataFrame(data)

# 计算3天移动窗口内的排名
df['window_rank'] = df['sales'].rolling(window=3).rank(method='dense', ascending=False)

# 计算排名变化
df['rank_change'] = df['window_rank'].diff()

print("pandasdataframe.com - Moving window rank change:")
print(df)

计算分组内的排名密度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import pandas as pd

# 创建示例数据
data = {
'department': ['Sales', 'Sales', 'Marketing', 'Marketing', 'HR', 'HR'] * 5,
'score': [85, 90, 80, 95, 88, 92, 78, 82, 89, 91, 86, 84,
93, 87, 81, 94, 90, 88, 79, 83, 92, 96, 85, 89,
91, 88, 82, 97, 89, 93]
}
df = pd.DataFrame(data)

# 计算每个部门内的排名
df['rank'] = df.groupby('department')['score'].rank(method='dense')

# 计算每个部门的排名密度
rank_density = df.groupby(['department', 'rank']).size().unstack(fill_value=0)

print("pandasdataframe.com - Rank density in each department:")
print(rank_density)

image-20250720093816397

计算跨组的相对百分比排名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import pandas as pd

# 创建示例数据
data = {
'department': ['Sales', 'Sales', 'Marketing', 'Marketing', 'HR', 'HR'] * 5,
'score': [85, 90, 80, 95, 88, 92, 78, 82, 89, 91, 86, 84,
93, 87, 81, 94, 90, 88, 79, 83, 92, 96, 85, 89,
91, 88, 82, 97, 89, 93]
}
df = pd.DataFrame(data)

# 计算每个部门的平均分和标准差
dept_stats = df.groupby('department')['score'].agg(['mean', 'std'])

# 计算z-score
df = df.merge(dept_stats, on='department')
df['z_score'] = (df['score'] - df['mean']) / df['std']

# 计算相对百分比排名
df['relative_percentile'] = df['z_score'].rank(pct=True)

print("pandasdataframe.com - Cross-group relative percentile ranking:")
print(df.head(10))

image-20250720093556018

数据重塑

综合分析案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 创建模拟销售数据
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=100, freq='D')

products = ['产品A', '产品B', '产品C', '产品D', '产品E']
regions = ['北区', '南区', '东区', '西区']

sales_data = []
for i in range(500):
sales_data.append({
'date': np.random.choice(dates),
'product': np.random.choice(products),
'region': np.random.choice(regions),
'quantity': np.random.randint(1, 100),
'unit_price': np.random.randint(50, 500),
})

sales_df = pd.DataFrame(sales_data)
sales_df['total_amount'] = sales_df['quantity'] * sales_df['unit_price']
sales_df['month'] = sales_df['date'].dt.month

print("销售数据样本:")
print(sales_df.head(10))
print(f"\n数据形状:{sales_df.shape}")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
销售数据样本:
date product region quantity unit_price total_amount month
0 2024-02-21 产品E 东区 72 238 17136 2
1 2024-01-21 产品B 东区 87 380 33060 1
2 2024-03-15 产品E 西区 24 180 4320 3
3 2024-01-22 产品E 南区 88 463 40744 1
4 2024-02-07 产品B 西区 60 326 19560 2
5 2024-02-02 产品D 南区 22 302 6644 2
6 2024-03-29 产品A 东区 59 219 12921 3
7 2024-04-01 产品D 西区 15 239 3585 4
8 2024-03-02 产品C 西区 55 293 16115 3
9 2024-03-04 产品A 东区 51 184 9384 3

数据形状:(500, 7)

基础统计分析

1
2
3
4
# 1. 基础统计分析
print("1. 基础统计分析:")
print("销售金额描述性统计:")
print(sales_df['total_amount'].describe())
1
2
3
4
5
6
7
8
9
10
11
1. 基础统计分析:
销售金额描述性统计:
count 500.000000
mean 13484.932000
std 10844.490364
min 57.000000
25% 4368.000000
50% 10641.500000
75% 20421.500000
max 48015.000000
Name: total_amount, dtype: float64

按产品分析

1
2
3
4
5
6
7
8
# 2. 按产品分析
print("2. 按产品销售分析:")
product_analysis = sales_df.groupby('product').agg({
'total_amount': ['sum', 'mean', 'count'],
'quantity': 'sum'
}).round(2)
product_analysis.columns = ['总销售额', '平均销售额', '订单数', '总销量']
print(product_analysis.sort_values('总销售额', ascending=False))
1
2
3
4
5
6
7
8
按产品销售分析:
总销售额 平均销售额 订单数 总销量
product
产品E 1445669 14173.23 102 4958
产品A 1394052 13940.52 100 4921
产品C 1331848 12107.71 110 5375
产品D 1300082 14943.47 87 4138
产品B 1270815 12582.33 101 4803

按地区分析

1
2
3
4
5
6
7
8
9
# 3. 按地区分析
print("3. 按地区销售分析:")
region_analysis = sales_df.groupby('region').agg({
'total_amount': 'sum',
'quantity': 'sum'
}).round(2)
region_analysis.columns = ['总销售额', '总销量']
region_analysis['平均单价'] = (region_analysis['总销售额'] / region_analysis['总销量']).round(2)
print(region_analysis.sort_values('总销售额', ascending=False))
1
2
3
4
5
6
7
按地区销售分析:
总销售额 总销量 平均单价
region
西区 2021105 7042 287.01
北区 1655052 6001 275.80
东区 1572510 5342 294.37
南区 1493799 5810 257.11

时间序列分析

1
2
3
4
5
# 4. 时间序列分析
print("4. 按月销售趋势分析:")
monthly_sales = sales_df.groupby('month')['total_amount'].sum().round(2)
print("月度销售额:")
print(monthly_sales)
1
2
3
4
5
6
7
8
4. 按月销售趋势分析:
月度销售额:
month
1 2134244
2 1938552
3 1891071
4 778599
Name: total_amount, dtype: int64

交叉分析

1
2
3
4
5
6
7
8
9
10
11
12
# 5. 交叉分析
print("5. 产品-地区交叉分析:")
cross_analysis = sales_df.pivot_table(
values='total_amount',
index='product',
columns='region',
aggfunc='sum',
fill_value=0
).round(2)
print("产品在各地区的销售额:")
print(cross_analysis)
print()
1
2
3
4
5
6
7
8
9
5. 产品-地区交叉分析:
产品在各地区的销售额:
region 东区 北区 南区 西区
product
产品A 276865 386919 296162 434106
产品B 252216 349127 249466 420006
产品C 405441 288120 222458 415829
产品D 329375 322671 276026 372010
产品E 308613 308215 449687 379154

Top分析

1
2
3
4
5
# 6. Top分析
print("6. Top分析:")
print("销售额前10的订单:")
top_orders = sales_df.nlargest(10, 'total_amount')[['date', 'product', 'region', 'total_amount']]
print(top_orders)
1
2
3
4
5
6
7
8
9
10
11
12
13
6. Top分析:
销售额前10的订单:
date product region total_amount
380 2024-01-29 产品D 西区 48015
325 2024-04-04 产品D 东区 44649
118 2024-03-21 产品B 西区 42687
76 2024-04-02 产品E 南区 42471
47 2024-02-23 产品E 西区 42098
32 2024-03-03 产品A 西区 41952
289 2024-01-05 产品E 南区 41548
471 2024-01-19 产品D 北区 41474
129 2024-01-09 产品D 南区 41135
3 2024-01-22 产品E 南区 40744

异常值检测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 7. 异常值检测
print("7. 异常值检测:")
Q1 = sales_df['total_amount'].quantile(0.25)
Q3 = sales_df['total_amount'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

outliers = sales_df[(sales_df['total_amount'] < lower_bound) |
(sales_df['total_amount'] > upper_bound)]
print(f"异常值数量:{len(outliers)}")
print(f"异常值占比:{len(outliers)/len(sales_df)*100:.2f}%")
if len(outliers) > 0:
print("异常值示例:")
print(outliers.head())
1
2
3
4
5
6
7
7. 异常值检测:
异常值数量:2
异常值占比:0.40%
异常值示例:
date product region quantity unit_price total_amount month
325 2024-04-04 产品D 东区 99 451 44649 4
380 2024-01-29 产品D 西区 99 485 48015 1

相关性分析

1
2
3
4
# 8. 相关性分析
print("8. 数值变量相关性分析:")
correlation = sales_df[['quantity', 'unit_price', 'total_amount']].corr().round(3)
print(correlation)
1
2
3
4
5
8. 数值变量相关性分析:
quantity unit_price total_amount
quantity 1.000 0.042 0.75
unit_price 0.042 1.000 0.60
total_amount 0.750 0.600 1.00

业务洞察

1
2
3
4
5
6
7
8
9
10
11
12
# 9. 业务洞察
print("9. 业务洞察总结:")
best_product = product_analysis.index[0]
best_region = region_analysis.index[0]
best_month = monthly_sales.idxmax()

print(f"• 最佳销售产品:{best_product}")
print(f"• 最佳销售地区:{best_region}")
print(f"• 最佳销售月份:{best_month}月")
print(f"• 平均订单金额:{sales_df['total_amount'].mean():.2f}元")
print(f"• 总订单数:{len(sales_df)}笔")
print(f"• 总销售额:{sales_df['total_amount'].sum():.2f}元")
1
2
3
4
5
6
7
9. 业务洞察总结:
• 最佳销售产品:产品A
• 最佳销售地区:东区
• 最佳销售月份:1月
• 平均订单金额:13484.93元
• 总订单数:500笔
• 总销售额:6742466.00元