数据分析入门

ops/2024/9/24 5:26:35/

数据分析入门

pandas_2">一、pandas加载数据

1、根据列加载数据

格式

df对象[列名]
df对象.列名

例如

# 场景1: 加载1列数据. 
# 格式: df['列名'] 或者 df.列名
df['country']
df.country# 场景2: 加载多列数据.
# 格式: df[['列名1', '列名2'...]]
df[['country', 'year', 'lifeExp']]

2、根据行加载数据

格式

df对象.head()			# 默认前五行,可指定行数
df对象.tail()			# 默认后五行,可指定行数
df对象.loc[索引值]	  # 根据索引值找行
df对象.iloc[行号]	   # 根据行号找行

例如

# head(), 默认是前5行
df.head()
df.head(n=2)  # 前2行# tail(), 默认是后5行
df.tail()
df.tail(n=3)  # 后3行 
df.tail(n=1)  # 最后1行 # loc: 根据 索引列 来获取数据的. 
df.loc[0]  # 第1行 => Series对象
df.loc[[0, 1, 2]]  # 第1, 2, 3行 => DataFrame对象
# df.loc[-1]              # 最后一行, 如果写-1, 则: 报错.# iloc: 根据 行号 来获取数据的. 
df.iloc[0]  # 第1行 => Series对象
df.iloc[[0, 1, 2]]  # 第1, 2, 3行 => DataFrame对象
df.iloc[-1]  # 最后一行

3、加载指定行指定列的数据

格式

df对象.loc[[], []]        # 索引列值 + 列名 的方式获取
df对象.iloc[[], []]       # 行号 + 列的编号(索引) 的方式获取

例如

# 1. 精准的获取某几行的, 某几列.
df.loc[[0, 21, 211], :]  # : 可以代表: 所有行, 所有列.
df.loc[[0, 21, 211], ['country', 'year', 'lifeExp']]  # 获取指定列
df.iloc[[0, 21, 211], [0, 2, 3]]  # 获取指定列# 2. 获取所有行的某几列.
# 写法1: 直接传入 列名 或者 列的索引
df.loc[:, ['continent', 'pop']]
df.iloc[:, [1, 4]]# 写法2: 可以通过 range方式来生成 索引.
df.iloc[:, range(1, 5, 2)]  # 所有行, 索引为:1, 3列的信息.
df.loc[:, ['continent', 'lifeExp']]# 写法3: 可以通过 切片的方式来生成索引.
df.iloc[:, 1:4]  # 所有行, 索引为:1, 2, 3列的信息, 包左不包右.
df.loc[:, ['continent', 'year', 'lifeExp']]# 3. 下述代码, 执行结果是什么.
df.loc[range(0, 10, 2), ['lifeExp', 'pop']]
df.iloc[range(0, 10, 2), 3: 5]  # 第0, 2, 4, 6, 8行,  第3, 4列
df.iloc[range(10, -1, -2), 3: 5]
df.iloc[range(10, -2, -1), 3: 5]  # 10 ~ -1 => -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10  共12条数据

二、分组聚合

格式

# aggregate可以用agg替换
df对象.groupby([分组的列名1, 分组的列名2...]).aggregate({'要被聚合操作的字段1':'聚合函数名', '字段2':'聚合函数名'...})# 如果需要聚合的字段都是用一个聚合函数,有语法糖写法:
df对象.groupby([分组的列名1, 分组的列名2...])[[要被聚合操作的字段1, 字段2...]].聚合函数名()# 如果分组字段和聚合字段只有一个,有语法糖写法:
df对象.groupby('分组字段')['聚合字段'].聚合函数名()# 聚合函数
mean()				# 平均值
value_counts()		# 每个值出现了几次
nunique()			# 去重统计
max()				# 最大值
min()				# 最小值
等等

例如

# 场景1: 分组字段 和 聚合字段都只有1个.
# 需求1: 每年的平均预期寿命.
# 类推到MySQL中, SQL语句写法为: select year, avg(lifeExp) as 别名 from df group by year;
df.groupby('year')['lifeExp'].mean()  # 细节: 分组字段会作为 索引列# 场景2: 分组字段 => 1个, 聚合字段 => 2个
# 需求2: 每一年的平均人口和平均GDP.
df.groupby('year')[['pop', 'gdpPercap']].mean()# 场景3: 分组字段 => 2个, 聚合字段 => 3个
# 需求3: 统计每年, 每个大洲的 平均预期寿命, 平均人口, 平均GDP.
df.groupby(['year', 'continent'])[['lifeExp', 'pop', 'gdpPercap']].mean()# 需求4: 统计每个大洲列出了多少个国家和地区.
# 理解1: 一共有多少个大洲, 多少个国家 共计参与了多少次.  即: 总次数.
# 类推SQL写法:  select continent, count(country) from df group by continent;
df.groupby('continent')['country'].value_counts()  # value_counts() 每个值出现了多少次# 理解2: 每个大洲, 有多少个国家参与.   不同的大洲, 国家 => 总数.
# 类推SQL写法:  select continent, count(distinct country) from df group by continent;
df.groupby('continent')['country'].nunique()  # nunique() 去重统计, 根据洲分组, 根据国家去重统计.# 需求5: 统计每年的 平均预期寿命, 最大的总人口, 最小的GDP
# 类推SQL写法: select year, avg(lifeExp), max(pop), min(gdpPercap) from df group by year;# pandas写法: df对象.groupby([分组的列名1, 分组的列名2...]).aggregate({'要被聚合操作的字段1':'聚合函数名', '字段2':'聚合函数名'...})
# 语法糖, df对象.groupby([分组的列名1, 分组的列名2...]).agg({'要被聚合操作的字段1':'聚合函数名', '字段2':'聚合函数名'...})df.groupby('year').agg({'lifeExp': 'mean', 'pop': 'max', 'gdpPercap': 'min'})
df.groupby('year').aggregate({'lifeExp': 'mean', 'pop': 'max', 'gdpPercap': 'min'})

三、基本绘图

格式

df对象.plot.line()  # 折线图    
df对象.plot.bar()   # 柱状图
df对象.plot.pie()   # 饼图

例如

data = df.groupby('year')['lifeExp'].mean()
data.plot.line()
data.plot.bar()
data.plot.pie()

四、常用函数

1、查看数据函数

格式

df对象.shape		# 维度(显示行列)
df对象.info()		# 基本信息
df对象.describe()	# 统计信息

例如

# 1. 读取数据, 获取df对象
movie = pd.read_csv('data/movie.csv')
movie.head()
# 2. 查看和数据分析相关的统计值.
movie.shape  # 维度: (4916, 28) => (行数, 列数)movie.info()  # 基本信息
movie.describe()  # 统计信息
movie.describe().T  # 统计信息, 行列转置movie.describe(include='all')  # 统计信息, 所有字段
movie.describe(include='object')  # 统计信息, 字符串类型的列的信息
movie.describe(include=object)    # 语法糖写法, 效果同上

2、排序函数

格式

df对象.sort_values(列名)			# 指定列的值排序
df对象.sort_values([列名1, 列名2...], ascending=[True, False])	# 多个列的值排序
df对象.sort_index()				 # 按照索引排序df对象.nlargest(个数, 列名)			# 取目标列最大的几个值
df对象.nsmallest(个数, 列名)			# 取目标列最小的几个值df对象.drop_duplicates(列名)				# 删除重复的数据
df对象.drop_duplicates([列名1, 列名2...])	   # 删除多列一起的重复的数据

例如

# 1. 从movie这个df对象中, 找到我们要用的列的信息. 
movie_df = movie[['movie_title', 'imdb_score', 'budget']]
movie_df.head()# 2. 找到 高口碑(评分最高的前100部电影)
# movie_df.sort_values('imdb_score', ascending=False).head(100)
tmp_df = movie_df.nlargest(100, 'imdb_score')        # 效果同上.# 3. 在高口碑的数据基础上, 找到 成品最低的那 10 部电影.
# tmp_df.sort_values('budget').head(10)        # ascending默认是True, 升序
tmp_df.nsmallest(10, 'budget')      # 效果同上.# 4. 上述代码, 一行搞定.
movie[['movie_title', 'imdb_score', 'budget']].nlargest(100, 'imdb_score').nsmallest(10, 'budget')

3、取值函数

格式

df对象.nlargest(个数, 列名)			# 取目标列最大的几个值
df对象.nsmallest(个数, 列名)			# 取目标列最小的几个值

例如

# 1. 从movie这个df对象中, 找到我们要用的列的信息. 
movie_df = movie[['movie_title', 'imdb_score', 'budget']]
movie_df.head()# 2. 找到 高口碑(评分最高的前100部电影)
# movie_df.sort_values('imdb_score', ascending=False).head(100)
tmp_df = movie_df.nlargest(100, 'imdb_score')        # 效果同上.# 3. 在高口碑的数据基础上, 找到 成品最低的那 10 部电影.
# tmp_df.sort_values('budget').head(10)        # ascending默认是True, 升序
tmp_df.nsmallest(10, 'budget')      # 效果同上.# 4. 上述代码, 一行搞定.
movie[['movie_title', 'imdb_score', 'budget']].nlargest(100, 'imdb_score').nsmallest(10, 'budget')

4、数据清洗函数

格式

df对象.dropna()							# 删除包含缺失值的行或列
df对象.fillna()							# 将缺失值替换为指定的值
df对象.replace(旧值, 新值)				  # 新值替换旧值df对象.duplicated()						 # 检查是否有重复的数据
df对象.drop_duplicates(列名)				# 删除重复的数据,保留一份
df对象.drop_duplicates([列名1, 列名2...])	   # 删除多列一起的重复的数据

例如

# 1. 获取到我们要处理的数据集.
movie_df = movie[['title_year', 'movie_title', 'imdb_score']]       # 电影名, 评分, 年费
movie_df.head()# 2. 按照年排序, 降序.
movie_df.sort_values('title_year', ascending=False)# 3. 按照年, 评分 降序排序.
tmp_df = movie_df.sort_values(['title_year', 'imdb_score'], ascending=False)# 4. 基于上述的临时数据, 按照 年份去重, 保留第1份即可. 
# subset参数: 参考哪一列进行去重. 
tmp_df.drop_duplicates(subset='title_year')       # 5. 一行代码搞定. 
# 完整代码
movie[['title_year', 'imdb_score', 'movie_title']].sort_values(['title_year', 'imdb_score'], ascending=[False, False]).drop_duplicates(subset='title_year')# 语法糖
movie[['title_year', 'imdb_score', 'movie_title']].sort_values(['title_year', 'imdb_score'], ascending=False).drop_duplicates('title_year')

五、数据拼接

1、concat函数

格式

pandas.concat([df对象1, df对象2, df对象3 ...], axis='rows/columns', ignore_index=True)
'''
第一个参数:需要拼接的df对象,用列表包裹
axis参数:rows为行拼接,columns为列拼接
ignore_index参数:是False时,默认的索引;时True时,忽略索引,默认用0~n填充。默认是False拼接未匹配的数据用NAN填充
'''
(一)、df对象和df对象拼接
# 记忆: concat()函数既能实现行拼接(默认), 也能实现列拼接.   行拼接参考: 列名,   列拼接参考: 索引列(行索引)
# 1. 演示行拼接
pd.concat([df1, df2, df3])                  # 默认是: 行拼接.
pd.concat([df1, df2, df3], axis='rows')     # 效果同上
pd.concat([df1, df2, df3], axis=0)          # 效果同上, 0 => rows, 行,   1 => columns, 列# 2. 演示列拼接
pd.concat([df1, df2, df3], axis='columns')  # 列拼接
pd.concat([df1, df2, df3], axis=1)          # 效果同上# 3. 演示 行, 列拼接时, 重置: 索引 和 列名
# 细节: 无论是行, 列拼接时, 只要忽略索引了, 都会默认用 0 ~ n来填充.
pd.concat([df1, df2, df3], axis='rows', ignore_index=True)     # 行拼接
pd.concat([df1, df2, df3], axis='columns', ignore_index=True)     # 列拼接# 4. 拼接 df1 和 df4
# 行拼接, 参考: 列名
pd.concat([df1, df4], axis='rows')      # 未匹配, 用NAN填充.# 列拼接, 参考: 索引列
pd.concat([df1, df4], axis='columns')   # 未匹配, 用NAN填充.
(二)、df对象和Series对象拼接
'''
当进行行拼接时,需要对比列名,如果列名相同就并入目标列,如果不相同就单开一列,空值用NAN填充
当进行列拼接时,需要对比行索引,如果行索引相同就并入目标行,如果不相同就单开一行,空值用NAN填充
'''
# 1. 创建Series对象.
s1 = pd.Series(['n1', 'n2', 'n3'])   # 2. 使用concat拼接df和series对象.
pd.concat([df1, s1], axis='rows')        # 默认是: 行拼接.
pd.concat([df1, s1], axis='columns')     # 默认是: 列拼接.
(三)、df对象新增一列
# 方式一:df对象[列名] = 列表, 要求: 列表的长度 要和 df的行数一致
df1['new_col1'] = [10, 20, 30, 40]# 方式二:df对象[列名] = Series对象, Series对象值的个数无要求
'''
少的值用NAN填充
数量一样则正常填充
数量大于目标行/列则只取前n个,多余的丢弃
'''
df1['new_col2'] = pd.Series([1, 2, 3])
df1['new_col3'] = pd.Series([1, 2, 3, 4])
df1['new_col4'] = pd.Series([1, 2, 3, 4, 5])

2、merge函数

concat_1.csv concat_2.csv concat_3.csv

格式

df对象.merge(df对象/Series对象, on='关联字段', how='链接方式', suffixes='后缀')
'''
参1: 要被合并的df对象. 
参2: on表示两个df合并的 关联字段, 如果一样可以直接写 on, 如果不一样, 则要写 left_on='左表字段名', right_on='右表字段名'
参3: how表示合并方式, 内连接: inner, 左连接: left, 右连接: right, 全(满)连接: outer
'''

**总结: **

merge的格式. df1.merge(df2, on=‘关联字段’, how=‘连接方式’)

**细节: **

**1. 默认是inner. **

**2. 关联字段不一致, 用 left_on 和 right_on **

3.两个df的字段有重名, 可以通过 suffixes 解决.

(一)、一对一关系

例子

# 准备动作
# 1. 创建连接对象, 关联: *.db文件.
conn = sqlite3.connect('data/chinook.db')# 2. 从上述的文件中, 读取 歌曲表的信息.
# 参1: 要执行的SQL语句,   参2: 连接对象.
tracks_df = pd.read_sql_query('select * from tracks;', conn)
tracks_df.head()# 3. 从上述的文件中, 读取 歌曲分类表的信息.
genres_df = pd.read_sql_query('select * from genres;', conn)
genres_df# 4. 查看 歌曲表的信息, 并从中找到 不同的音乐风格的数据
tracks_subset_df = tracks_df.loc[[0, 62, 76, 98, 110, 193, 204, 281]]
tracks_subset_df[['TrackId', 'GenreId', 'Milliseconds']] # 场景1: 内连接
genres_df.merge(tracks_subset_df[['TrackId', 'GenreId', 'Milliseconds']], on='GenreId', how='inner')# 场景2: 左外连接
genres_df.merge(tracks_subset_df[['TrackId', 'GenreId', 'Milliseconds']], on='GenreId', how='left')# 场景3: 右外连接
genres_df.merge(tracks_subset_df[['TrackId', 'GenreId', 'Milliseconds']], on='GenreId', how='right')# 场景4: 满外连接, 也叫: 全连接, 即: 它的查询结果 = 左连接 + 右连接,   即: 左表全集 + 右表全集 + 交集.
genres_df.merge(tracks_subset_df[['TrackId', 'GenreId', 'Milliseconds']], on='GenreId', how='outer')# 场景5: 查看默认是哪种连接. 
genres_df.merge(tracks_subset_df[['TrackId', 'GenreId', 'Milliseconds']], on='GenreId')     # 默认是: 内连接 => inner# 场景6: 如果关联的多个df有重名的列, 则默认会加上 _x, _y这样的后缀, 来源于: suffixes字段.
genres_df.merge(tracks_subset_df[['TrackId', 'Name', 'GenreId', 'Milliseconds']], on='GenreId')     # 默认后缀: _x, _y
genres_df.merge(tracks_subset_df[['TrackId', 'Name', 'GenreId', 'Milliseconds']], on='GenreId', suffixes=('_left', '_right'))     # 默认后缀: _x, _y
(二)、一对多关系
# 1. 合并 genres(风格表) 和 tracks(歌曲表)
genres_df.merge(tracks_df[['TrackId', 'Name', 'GenreId', 'Milliseconds']], on='GenreId') # 需求2: 计算每种类型音乐的平均时长. 
# 1. 合并 genres(风格表) 和 tracks(歌曲表).  交集.
genre_track =  genres_df.merge(tracks_df[['TrackId', 'GenreId', 'Milliseconds']], on='GenreId', how='inner')    # 风格表.merge(歌曲表['歌曲id', '风格id', '歌曲时长毫秒']) 
# 左外连接.
genre_track =  genres_df.merge(tracks_df[['TrackId', 'GenreId', 'Milliseconds']], on='GenreId', how='left')    # 风格表.merge(歌曲表['歌曲id', '风格id', '歌曲时长毫秒']) 
genre_track# 2. 根据 风格id分组, 计算 时长的平均值.
genre_time = genre_track.groupby(['GenreId', 'Name']).Milliseconds.mean()
genre_time# 3. 扩展, 后边详解.  把上述的 genre_time => 秒.
pd.to_timedelta(genre_time, unit='ms').dt.floor('s')# pd.to_timedelta(genre_time, unit='ms') 意思是: 把 genre_time 的毫秒数, 转换成 pandas.Timedelta 类型.
# dt.floor('s') 意思是: 取整, 取秒.
pd.to_timedelta(genre_time, unit='ms').dt.floor('s').sort_values()

3、join函数

stocks_2016.csv stocks_2017.csv stocks_2018.csv

格式

df对象.join(df1对象/Series对象,  lsuffix='别名1', rsuffix='别名2', on='匹配列', how='关联方式')
'''
参1:选择要连接的对象
参2:如果有重名的字段,则需要起别名来区分,此处别名为df
参3:如果有重名的字段,则需要起别名来区分,此处别名为df1
参4:on设定函数外df对象的普通列
参5:how是指定关联方式, 内连接: inner, 左连接: left, 右连接: right, 全(满)连接: outer
'''

总结:
1. 默认是 左外连接.
2. 如果两个df有重名字段, 需要手动设置后缀名.
3. 默认是根据两个df的 索引列来合并的, 如果想要关联普通列, 需要通过 on 参数实现.

例子

# 1. 加载数据, 获取df对象.
stock_2016 = pd.read_csv('data/stocks_2016.csv')
stock_2017 = pd.read_csv('data/stocks_2017.csv')
stock_2018 = pd.read_csv('data/stocks_2018.csv')
stock_2016
stock_2017
stock_2018# 2. 默认情况下, join会参考 两个df的 索引列 进行合并连接.
stock_2016.join(stock_2017, lsuffix='_2016', rsuffix='_2017')               # 默认: 左外连接
stock_2016.join(stock_2017, lsuffix='_2016', rsuffix='_2017', how='left')   # 效果同上# 3. 设置两个df对象的 Symbol列为索引列, 再次关联.
stock_2016.set_index('Symbol')
stock_2017.set_index('Symbol')# 设置索引列, 并关联. 
stock_2016.set_index('Symbol').join(stock_2017.set_index('Symbol'), lsuffix='_2016', rsuffix='_2017', how='left')   # 左外连接
stock_2016.set_index('Symbol').join(stock_2017.set_index('Symbol'), lsuffix='_2016', rsuffix='_2017', how='right')  # 右外连接
stock_2016.set_index('Symbol').join(stock_2017.set_index('Symbol'), lsuffix='_2016', rsuffix='_2017', how='outer')  # 满外连接
stock_2016.set_index('Symbol').join(stock_2017.set_index('Symbol'), lsuffix='_2016', rsuffix='_2017', how='inner')  # 内连接# 4. 设置stock_2016的索引为: Symbol 和 stock_2018做关联.
stock_2016
stock_2018.set_index('Symbol')# 拿着 stock_2016的 指定列(普通列) 和 stock_2018的 索引列 进行关联.
# 细节: on参数设定的是 函数外 df对象的 普通列
stock_2016.join(stock_2018.set_index('Symbol'), lsuffix='_left', rsuffix='_right', on='Symbol', how='outer')

六、缺失值处理

1、缺失值的查看和比较

pandas库中,缺失值来源于numpy中的NAN,nan,NaN,他们都是空,需要注意的是,空代表什么都没有,也就是说,空不能等于空.

isnull():判断是否为空

isna():判断是否为空

notnull():判断是否不为空

notna():判断是否不为空

# 细节: 在Pandas中, 缺失值来源于numpy包的NAN, nan, NaN, 他们都表示空.
# from numpy import NAN, nan, NaN# 1. 空值比较.
print(np.NAN == True)   # False
print(np.NAN == False)  # False
print(np.NAN == '') # False
print(np.NAN == 0)  # False# 2. 空和空比较, 也都是False.
print(np.NAN == np.nan) # False
print(np.NAN == np.NaN) # False
print(np.nan == np.NaN) # False# 3. 判断是否为空.  Pandas库的 isnull(), isna(),  notnull(), notna()
print(pd.isnull(np.NAN))    # True
print(pd.isnull(''))        # Falseprint(pd.notnull(np.NAN))    # False
print(pd.notnull(''))        # True

2、加载数据时操作缺失值

格式

对象.read_csv('路径', keep_default_na=False)	# keep_default_na: 设置加载时是否加载缺失值.  True(默认): 加载.  False: 不加载对象.read_csv('路径', na_values=['值'])			# na_values: 设置加载时, 哪些值 设置为缺失值

例子

# 1. 读取数据, 获取df对象.
pd.read_csv('data/survey_visited.csv')      # 默认: 会加载缺失值.# keep_default_na: 设置加载时是否加载缺失值.  True(默认): 加载.  False: 不加载.
pd.read_csv('data/survey_visited.csv', keep_default_na=False)# na_values: 设置加载时, 哪些值 设置为缺失值.
pd.read_csv('data/survey_visited.csv', na_values=['734', '751', 'MSK-4', '1939-01-07'])

3、删除缺失值

格式

df对象.dropna(axis='rows')		# 按照: 行 删除空值
df对象.dropna(axis=0)				# 按照: 行 删除空值df对象.dropna(axis='columns')		# 按列删除缺失值
df对象.dropna(axis=1)				# 按列删除缺失值# subset参数: 参考的列, 即: 该列值为空, 才会删除行, 或者 列.
# how参数: 删除方式, any: 只要有空值, 就删除行或者列. all: 全部为空, 才删除行或者列.
df对象.dropna(subset=['列名', '列名'...], how='all')
df对象.dropna(subset=['列名', '列名'...], how='any')

例子

# 1. 查看 df 对象
train.isnull().sum()        # 查看各列的空值情况.# 2. 删除缺失值.
# 按 行 删除缺失值.
train.dropna()
train.dropna(axis='rows')   # 效果同上, 默认按照: 行 删除空值.
train.dropna(axis=0)        # 效果同上, 默认按照: 行 删除空值.# 按 列 删除缺失值
train.dropna(axis='columns')    # 按列删除缺失值.
train.dropna(axis=1)            # 效果同上.# subset参数: 参考的列, 即: 该列值为空, 才会删除行, 或者 列.
# how参数: 删除方式, any: 只要有空值, 就删除行或者列. all: 全部为空, 才删除行或者列.
train.dropna(subset=['Age', 'Embarked'], how='all')     
train.dropna(subset=['Age', 'Embarked'], how='any')     # 查看删除后的数据
train.dropna(subset=['Age', 'Embarked'], how='any').isnull().sum()

4、填充缺失值

(一)、非时间序列,固定值

格式

df对象.fillna()		# 填充所有的空值

例子

# 1. 查看数据集.
train.isnull().sum()# 2. 填充缺失值, 用 固定值填充. 
train.fillna(0)     # 填充所有的空值.# 3. 查看填充后的数据集.
train.fillna(0).isnull().sum()
(二)、时间序列,非固定值

格式

ffill()		# 空值的上一个值bfill()		# 空值的下一个值# 采用 线性插入法, 即: 结合上下值, 计算出结果, 并填充
# both: 结合上下值.  forward: 结合上1个值, backward: 结合下一个值
interpolate(limit_direction='forward'|'both'|'backward')

例子

# 时间序列填充 = 结合数据列的上下文的值, 计算出要填充的值. 
# 1. 加载数据, 获取df对象. 
city_day = pd.read_csv('data/city_day.csv', parse_dates=['Date'], index_col='Date')
city_day# 2. 从中提取出一些数据, 二甲苯列的数据. 
city_day.Xylene[50:64]# 3. 采用 时间序列填充, 参考: 空值的上一个值.
# city_day.Xylene[50:64].fillna(method='ffill')       # 已过时.
city_day.Xylene[50:64].ffill()                        # 推荐写法# 4. 采用 时间序列填充, 参考: 空值的下一个值.
# city_day.Xylene[50:64].fillna(method='bfill')       # 已过时.
city_day.Xylene[50:64].bfill()                     	  # 推荐写法# 5. 采用 线性插入法, 即: 结合上下值, 计算出结果, 并填充.
# both: 结合上下值.  forward: 结合上1个值, backward: 结合下一个值.
city_day.interpolate(limit_direction='forward').Xylene[50:64]

七、apply自定义函数

1、操作Series对象

格式

# apply()函数操作Series对象, 是把Series的逐个值进行传入并操作的
series对象.apply(函数对象)

例子

# 1. 定义1个df对象.
df = pd.DataFrame({'a': [10, 20, 30], 'b': [20, 30, 40]})# 2. 定义1个函数, 用于求 值 的 平方.  2 => 4,   5 => 25
def my_fun1(x):print('看看我执行了嘛!')return x ** 2# 扩展: 定义函数, 计算x的e次方.
def my_fun2(x, e):return x ** e# 3. 把上述的函数, 作用于 df对象的 a列值(Series对象)
df['a'].apply(my_fun1)  # 细节: 这里写的是函数名, 即: 函数对象.  如果写: 函数名() 则表示是在调用函数.df.a.apply(my_fun2, e=3)  # 细节: 传参数时, 使用 关键字参数 写法进行传参.

2、操作DataFrame对象

格式

# apply()函数操作DataFrame对象, 是把DataFrame的整列/整行进行传入并操作的
series对象.apply(函数对象)

例如

# 1. 定义1个df对象.
df = pd.DataFrame({'a': [10, 20, 30], 'b': [20, 30, 40]})# 2. 把上述的函数, 作用于 df对象
df.apply(my_fun1)  # 默认: axis=0(列), 即: 整列值进行传入, 进行操作.# 3. 计算每列的平均值, 尝试用如下的函数做, 发现报错.  最终验证 => df的apply()函数, 默认是传入整列值的, 而不是逐个值进行传入的. 
def my_fun3(x, y, z):return (x + y + z) / 3df.apply(my_fun3)		# 报错,因为默认是传入整列值# 4. 分析上述报错原因, 得出: apply()函数默认传入的是整列值, 而不是逐个值.
def my_fun4(x):print(x)print(type(x))df.apply(my_fun4)# 5. 定义函数, 计算df对象 每列的平均值
def my_fun5(x):# 这里的x可以是: df对象的整行 或者 整列数据return x.mean()df.apply(my_fun5)  # 默认: axis=0(列)
df.apply(my_fun5, axis=0)  # 效果同上# 6. 定义函数, 计算df对象 每行的平均值
df.apply(my_fun5, axis=1)

3、向量化函数

格式

# 通过 np.vectorize()函数, 将自定义函数向量化. 即: 如果遇到了向量, 则会逐个进行遍历, 获取标量并操作
# 写法一
@np.vectorize# 写法二
函数名 = np.vectorize(函数名)

例如

# 1. 定义1个df对象.
df = pd.DataFrame({'a': [10, 20, 30], 'b': [20, 30, 40]})# 2. 自定义函数, 接收 df对象的 两列数据, 计算 每行的平均值. 
# 装饰的写法1: @装饰器名
@np.vectorize
def my_fun6(x, y):# 判断, 如果x的值是20, 就返回NaNif x == 20:         # 报错: x是向量, 20是标量, 向量和标量无法直接计算. return np.NAN# for i in x:#     if i == 20:         # 手动遍历, 就不报错了, 但是结果不是我们要的.#         return np.NAN# x代表第1列数据, y代表第2列数据return (x + y) / 2# 调用函数
my_fun6(df.a, df.b)# 3. 可以通过 np.vectorize()函数, 将自定义函数向量化. 即: 如果遇到了向量, 则会逐个进行遍历, 获取标量并操作.
# 装饰的写法2: 传统写法.
my_fun6 = np.vectorize(my_fun6)     # 装饰后的函数对象 = 装饰器(要被装饰的函数名)
my_fun6(df.a, df.b)

4、结合lambda表达式使用

将lambda表达式作为函数对象传入apply中。

# 1. 定义数据集.
df = pd.DataFrame({'a': [10, 20, 30], 'b': [20, 30, 40]})# 2. 需求: 每个值 => 该值的平方.
def my_fun1(x):return x ** 2df.apply(my_fun1)# 3. 上述的需求可以用 Lambda表达式来完成.
df.apply(lambda x : x ** 2)
df.apply(lambda x : x.mean())
df.apply(lambda x : x.mean(), axis=0)   # 效果同上.df.apply(lambda x : x.mean(), axis=1)   # 统计每行的平均值

八、分组操作

1、单变量分组聚合

格式

df对象.groupby('列名')

例如

# 写法1
df.groupby('year')['lifeExp'].mean()
# 写法2
df.groupby('year').lifeExp.mean()# 上述都是一步到位, 直接计算结果, 我们也可以手动计算. 
# 1. 我们先看看一共有多少个年
df.year.unique()  # 12个年份, 底层算 12 次即可, 这里我们就用 1952年举例.# 2. 获取1952年所有的数据, 计算平均寿命
df[df['year'] == 1952].lifeExp.mean()
df[df.year == 1952].lifeExp.mean()  # 效果同上.

2、分组+转换

格式

对象.groupby('列名').列名.apply(聚合函数)				# n => 1  聚合的效果
对象.groupby('列名').列名.transform(聚合函数)			# n => n  类似于: MySQL的窗口函数的效果

例子

# 需求1: 计算x的 z-score分数, 也叫: 标准分数,  公式为: (x - x_mean) / x_std
# 1. 读取数据, 获取df对象
df = pd.read_csv('data/gapminder.tsv', sep='\t')# 2. 定义函数, 计算某列的 z-score分数.
def my_zscore(col):return (col - col.mean()) / col.std()  # (列值 - 平均值) / 标准差# 3. 调用上述的格式.
df.groupby('year').lifeExp.apply(my_zscore)  # 1704条# 需求2: 分组填充案例
# 需求: 读取文件(小票信息), 获取df对象. 其中有1列 total_bill 表示总消费. 随机抽取4个缺失值, 然后进行填充. 
# 填充方式: 每个组的平均值. 即: 如果是Male => 就用 Male列的平均值填充, 如果是Female => Female列的平均值填充.
# 1. 读取文件, 获取DataFrame对象
df = pd.read_csv('data/tips.csv')# 2. 抽样方式, 从上述的df对象中, 随机抽取10条数据. 
# tips_10 = df.sample(10)     # 这里的10表示随机抽取 10 条数据.
# random_state: 随机种子, 只要种子一样, 每次抽取的数值都是一样的. 
tips_10 = df.sample(10, random_state=21)
tips_10# 3. 随机的从上述的10条数据中, 抽取4行数据, 设置他们的 total_bill(消费总金额) 为 NaN
# 写法1: 每次固定 这四条数据 的 total_bill为 空值.
# tips_10.loc[[173, 240, 243, 175], 'total_bill'] = np.NaN# 写法2: 每次随机4条数据, 设置它们的 total_bill为 空值.
# np.random.permutation()解释: 随机打乱索引值, 并返回打乱后的索引值.
tips_10.loc[np.random.permutation(tips_10.index)[:4], 'total_bill'] = np.NaN
tips_10# 4. 分别计算 Male 和 Female 的平均消费金额, 用于填充对应组的 缺失值.
# 思路1: 直接用 整体的 总消费金额的 平均值 填充.
tips_10.fillna(tips_10.total_bill.mean())# 思路2: 自定义函数, 计算每组的平均消费金额, 进行填充
def my_mean(col):# return col.sum() / col.size     # 某列总金额 / 某列元素个数,  这种写法会导致: 本组所有的数据都会被新值覆盖.return col.fillna(col.mean())     # 用该列的平均值, 来填充该列的缺失值, 其它不变.# 调用上述函数, 实现: 分组填充, 即: 给我N条, 处理后, 还是返回N条数据.
# tips_10.groupby('sex').total_bill.apply(my_mean)      # n => 1  聚合的效果.
tips_10.groupby('sex').total_bill.transform(my_mean)    # n => n  类似于: MySQL的窗口函数的效果.

3、分组+过滤

格式

对象.groupby('列名').filter(条件)
对象.query(条件)

例子

# 1. 读取文件, 获取DataFrame对象
df = pd.read_csv('data/tips.csv')# 2. 查看用餐人数情况.
tmp_df = df.groupby('size', as_index=False).total_bill.count()
tmp_df.columns = ['size', 'count']
tmp_dfdf.size     # 这样写, 会把 size当做 属性, 而不是 size列.
df['size'].value_counts()# 3. 我们发现, 在所有的 消费记录中, 就餐人数 在 1, 5, 6个人的消费次数相对较少, 我们可以过滤掉这部分的数据
tmp_df = df.groupby('size').filter(lambda x : x['size'].count() > 30)
tmp_df# 4. 验证上述筛选后的数据, size列只有 2, 3, 4 这三种就餐人数的情况.
tmp_df['size'].value_counts()# 5. 上述代码的合并版, 一行搞定.
df.groupby('size').filter(lambda x : x['size'].count() > 30)['size'].value_counts()# 另外一种筛选的方式, 可以基于: query()函数 + 筛选条件, 找出要的合法的数据. 
df.query('size == 2 or size == 3 or size == 4')
df.query('size in [2, 3, 4]')

4、DataFrameGroupby df的分组对象

格式

# 分组对象不能使用 0 索引获取数据,要获取数据, 可以通过  grouped.get_group() 函数实现
DataFrameGroupBy对象.get_group(('列名'))

例子

# 1. 从小费数据中, 随机的获取10条数据.
tips_10 = pd.read_csv('data/tips.csv').sample(10, random_state=21)
tips_10# 2. 演示 根据性别分组, 获取: 分组对象.
grouped = tips_10.groupby('sex')      # DataFrameGroupBy 对象
grouped# 3. 遍历上述的分组对象, 看看每个分组都是啥(即: 每个分组的数据)
for sex_group in grouped:print(sex_group)        # sex_group: 就是具体的每个分组的数据. # 4. 获取指定的某个分组的数据.
grouped.get_group('Male')
grouped.get_group('Female')# 5. 需求: 使用groupby() 按 性别 和 用餐时间分组, 计算小费数据的平均值. 
df.groupby(['sex', 'time']).tip.mean()# 6. 分组对象不能使用 0 索引获取数据
# grouped[0]      # 分组对象不能使用 0 索引获取数据, 要获取数据, 可以通过  grouped.get_group() 函数实现
grouped.get_group('Male')

5、透视表

格式

# 参1: index, 索引列, 等价于: groupby()的分组字段.
# 参2: columns, 列索引, 要写的也是 原表中的 列名. 
# 参3: values, 统计字段, 等价于: groupby()的聚合字段.
# 参4: aggfunc, 聚合函数, 默认为: mean
df对象.pivot_table(index='索引列', values='统计字段', aggfunc='聚合函数')# 扩展:
# 可视化数据. 
# 绘制 月增量, figsize=宽高, color=颜色, secondary_y: 启用双Y轴, legend: 图例, grid: 网格, xlabel=X轴标签, ylabel=Y轴标签
对象.列名.plot(figsize=(20, 10), color='red', secondary_y=True, legend=True)

例子

# 可视化上述的数据.
# 1. 构建画布(画板), 坐标系.
fig, ax1 = plt.subplots(figsize=(20, 10))
# 2. 基于ax1坐标轴对象, 构建ax2 坐标轴对象.
ax2 = ax1.twinx()
# 3. 绘制 白银, 黄金会员分布情况. 
member_rating[1:][['白银会员', '黄金会员']].plot(kind='bar', ax=ax1, legend=True, xlabel='年月', ylabel='白银/黄金')
# 4. 绘制 铂金, 钻石会员分布情况.
member_rating[1:][['铂金会员', '钻石会员']].plot(ax=ax2, legend=True,  ylabel='铂金/钻石', grid=True, color=['pink', 'green'])
# 5. 设置 ax2 坐标轴的图例 到 画布的 左上角.
ax2.legend(loc='upper left')
# 6. 设置标题
plt.title('增量等级分布', fontsize=21)
# 7. 绘制图形.
plt.show()

九、日期时间处理

pandas_1109">1、pandas中的日期类型

格式

对象.to_datetime('时间')		# Timestamp('时间:年月日时分秒')
对象.Timestamp('时间')			# Timestamp('时间:年月日时分秒')

例子

d1 = pd.to_datetime('2024-10-01')		# Timestamp('2024-10-01 00:00:00')d2 = pd.Timestamp('2024-10-01')			# Timestamp('2024-10-01 00:00:00')

2、提取日期中的各个部分

格式

对象.to_datetime('时间')		# Timestamp('时间:年月日时分秒')
对象.year						 # 年
对象.month					 # 月
对象.day						 # 日
对象.dayofyear				 # 一年的第几天对象.Timestamp('时间')			# Timestamp('时间:年月日时分秒')

例子

d1 = pd.to_datetime('2024-10-01')		# Timestamp('2024-10-01 00:00:00')d2 = pd.Timestamp('2024-10-01')			# Timestamp('2024-10-01 00:00:00')

3、生成日期序列

格式

对象.date_range(start, end, freq='生成规则')		# 包左包右

例子

# 1. 获取 2024年9月, 10月的日期序列.
pd.date_range('2024-09-01', '2024-10-31')       # 默认: freq='D',  D => 日历日# 2. 获取 2024年9月, 10月, 获取所有的工作日时间
pd.date_range('2024-09-01', '2024-10-31', freq='B')         # 不间隔工作日.
'''
DatetimeIndex(['2024-09-02', '2024-09-03', '2024-09-04', '2024-09-05','2024-09-06', '2024-09-09', '2024-09-10', '2024-09-11','2024-09-12', '2024-09-13', '2024-09-16', '2024-09-17','2024-09-18', '2024-09-19', '2024-09-20', '2024-09-23','2024-09-24', '2024-09-25', '2024-09-26', '2024-09-27','2024-09-30', '2024-10-01', '2024-10-02', '2024-10-03','2024-10-04', '2024-10-07', '2024-10-08', '2024-10-09','2024-10-10', '2024-10-11', '2024-10-14', '2024-10-15','2024-10-16', '2024-10-17', '2024-10-18', '2024-10-21','2024-10-22', '2024-10-23', '2024-10-24', '2024-10-25','2024-10-28', '2024-10-29', '2024-10-30', '2024-10-31'],dtype='datetime64[ns]', freq='B')
'''# 3. 获取 2024年9月, 10月, 间隔1个工作日, 获取1个日期.
pd.date_range('2024-09-01', '2024-10-31', freq='2B')
'''
DatetimeIndex(['2024-09-02', '2024-09-04', '2024-09-06', '2024-09-10','2024-09-12', '2024-09-16', '2024-09-18', '2024-09-20','2024-09-24', '2024-09-26', '2024-09-30', '2024-10-02','2024-10-04', '2024-10-08', '2024-10-10', '2024-10-14','2024-10-16', '2024-10-18', '2024-10-22', '2024-10-24','2024-10-28', '2024-10-30'],dtype='datetime64[ns]', freq='2B')
'''# 4. 获取 2024年9月, 10月, 每个月的第1个周四.  Week Of Month, Thursday => 周四
pd.date_range('2024-09-01', '2024-10-31', freq='WOM-1THU')
'''
DatetimeIndex(['2024-09-05', '2024-10-03'], dtype='datetime64[ns]', freq='WOM-1THU')
'''# 5. 获取 2024年9月, 10月, 每个月的第3个周五.  Week Of Month, Friday => 周五
pd.date_range('2024-09-01', '2024-10-31', freq='WOM-3FRI')
'''
DatetimeIndex(['2024-09-20', '2024-10-18'], dtype='datetime64[ns]', freq='WOM-3FRI')
'''


http://www.ppmy.cn/ops/115132.html

相关文章

dockerfile案例

dockerfile构建nginx FROM centos:7 RUN rm -rf /etc/yum.repos.d/* ADD Centos-7.repo /etc/yum.repo.d/ ADD epel-7.repo /etc/yum.repo.d/ RUN yum -y install nginx EXPOSE 80 CMD ["/usr/sbin/nginx","-g","daemon off;"]dockerfile构建ng…

Spring Boot文件上传/下载问题

在现代的 Web 应用程序中,文件上传和下载是非常常见的功能。Spring Boot 提供了非常简便和强大的解决方案来处理文件上传和下载。虽然基本功能很容易实现,但在实际项目中,文件大小限制、并发上传、文件类型验证、安全性等问题也常常需要重点考…

【计算机网络 - 基础问题】每日 3 题(二十)

✍个人博客:Pandaconda-CSDN博客 📣专栏地址:http://t.csdnimg.cn/fYaBd 📚专栏简介:在这个专栏中,我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话,欢迎点赞👍收藏&…

K8S容器实例Pod安装curl-vim-telnet工具

在没有域名的情况下,有时候需要调试接口等需要此工具 安装curl、telnet、vim等 直接使用 apk add curlapk add vimapk add tennet

统信服务器操作系统【开机自启动】配置方法

开机自启动的四种配置方法,包括systemctl命令、rc.local文件、crontab任务,通过desktop配置开机自动,前三种方法适合后台程序或者脚本启动,最后一种方法适合图形化程序启动。 文章目录 准备环境配置方法一、通过编写service的方法,使用systemctl配置开机自启二、通过rc.lo…

FortiGate 硬盘格式化指南

FortiGate硬盘格式化步骤如下:1,下载对应产品的硬盘格式化镜像文件,可以参照下表;2,用串口线连接设备并开启超级终端工具等待串口输… 注意:如果您感觉无法独自完成检测请及时联系您的代理商或飞塔技术支持…

Django 数据库配置以及字段设置详解

配置PostGre 要在 Django 中配置连接 PostgreSQL 数据库,并创建一个包含“使用人”和“车牌号”等字段的 Car 表 1. 配置 PostgreSQL 数据库连接 首先,在 Django 项目的 settings.py 中配置 PostgreSQL 连接。 修改 settings.py 文件: …

小程序开发设计-小程序的宿主环境:宿主环境简介⑥

上一篇文章导航: 小程序开发设计-小程序代码的构成:小程序页面的组成部分详解⑤-CSDN博客https://blog.csdn.net/qq_60872637/article/details/142306902?spm1001.2014.3001.5501 注:不同版本选项有所不同,并无大碍。 目录 上…