|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
引言
在数据分析的世界里,了解数据的维度和结构是任何分析流程的第一步。Pandas作为Python数据分析的核心库,提供了多种获取数据维度信息的方法,其中最常用的就是shape属性。掌握如何高效地获取和理解数据的形状信息,不仅能帮助我们更好地理解数据集,还能显著提升数据分析的效率。本文将深入探讨pandas中输出shape的多种方法,从基础应用到高级技巧,帮助你全面掌握数据维度信息的获取与应用。
基础方法:使用.shape属性
1. 直接使用.shape属性
.shape是pandas中最基本也是最常用的获取数据维度信息的方法。它返回一个表示数据维度的元组,对于DataFrame来说,格式为(行数, 列数),对于Series来说,格式为(元素个数,)。
- import pandas as pd
- import numpy as np
- # 创建一个示例DataFrame
- df = pd.DataFrame({
- '姓名': ['张三', '李四', '王五', '赵六'],
- '年龄': [25, 30, 35, 40],
- '性别': ['男', '女', '男', '女'],
- '工资': [5000, 6000, 7000, 8000]
- })
- # 获取DataFrame的形状
- print("DataFrame的形状:", df.shape)
- # 输出: DataFrame的形状: (4, 4)
- # 创建一个示例Series
- s = pd.Series([1, 2, 3, 4, 5], name='数字')
- # 获取Series的形状
- print("Series的形状:", s.shape)
- # 输出: Series的形状: (5,)
复制代码
2. 分别获取行数和列数
有时候,我们需要单独获取行数或列数,可以通过索引.shape返回的元组来实现:
- # 获取行数
- rows = df.shape[0]
- print("行数:", rows)
- # 输出: 行数: 4
- # 获取列数
- cols = df.shape[1]
- print("列数:", cols)
- # 输出: 列数: 4
复制代码
3. 使用len()函数获取行数
除了使用.shape[0],我们还可以使用Python内置的len()函数来获取DataFrame的行数:
- # 使用len()获取行数
- rows_len = len(df)
- print("使用len()获取的行数:", rows_len)
- # 输出: 使用len()获取的行数: 4
复制代码
中级方法:结合其他函数获取更详细的维度信息
1. 使用size属性获取总元素数
.size属性返回DataFrame中的总元素数(行数×列数):
- # 获取DataFrame的总元素数
- total_elements = df.size
- print("DataFrame的总元素数:", total_elements)
- # 输出: DataFrame的总元素数: 16
复制代码
2. 使用ndim属性获取维度数
.ndim属性返回数据的维度数,对于DataFrame来说通常是2,对于Series来说是1:
- # 获取DataFrame的维度数
- df_ndim = df.ndim
- print("DataFrame的维度数:", df_ndim)
- # 输出: DataFrame的维度数: 2
- # 获取Series的维度数
- s_ndim = s.ndim
- print("Series的维度数:", s_ndim)
- # 输出: Series的维度数: 1
复制代码
3. 使用info()方法获取详细的结构信息
虽然.info()方法主要用于查看DataFrame的概览信息,但它也包含了维度信息:
- # 使用info()获取DataFrame的详细信息
- print("DataFrame的详细信息:")
- df.info()
复制代码
输出:
- DataFrame的详细信息:
- <class 'pandas.core.frame.DataFrame'>
- RangeIndex: 4 entries, 0 to 3
- Data columns (total 4 columns):
- # Column Non-Null Count Dtype
- --- ------ -------------- -----
- 0 姓名 4 non-null object
- 1 年龄 4 non-null int64
- 2 性别 4 non-null object
- 3 工资 4 non-null int64
- dtypes: int64(2), object(2)
- memory usage: 256.0+ bytes
复制代码
4. 使用len()和columns/index结合获取维度信息
我们可以结合len()函数与columns或index属性来获取列数或行数:
- # 获取列数
- cols_count = len(df.columns)
- print("使用len(df.columns)获取的列数:", cols_count)
- # 输出: 使用len(df.columns)获取的列数: 4
- # 获取行数
- rows_count = len(df.index)
- print("使用len(df.index)获取的行数:", rows_count)
- # 输出: 使用len(df.index)获取的行数: 4
复制代码
高级技巧:特殊场景下的shape应用
1. 处理多级索引(MultiIndex)的数据形状
当DataFrame具有多级索引时,.shape仍然返回总的行数和列数,但我们可以通过其他方式获取更详细的信息:
- # 创建一个具有多级索引的DataFrame
- arrays = [
- ['A', 'A', 'B', 'B'],
- [1, 2, 1, 2]
- ]
- tuples = list(zip(*arrays))
- index = pd.MultiIndex.from_tuples(tuples, names=['第一级', '第二级'])
- multi_df = pd.DataFrame({
- '值1': [10, 20, 30, 40],
- '值2': [50, 60, 70, 80]
- }, index=index)
- print("多级索引DataFrame:")
- print(multi_df)
- print("\n形状:", multi_df.shape)
- # 获取各级索引的唯一值数量
- level0_unique = len(multi_df.index.get_level_values(0).unique())
- level1_unique = len(multi_df.index.get_level_values(1).unique())
- print("第一级索引的唯一值数量:", level0_unique)
- print("第二级索引的唯一值数量:", level1_unique)
复制代码
输出:
- 多级索引DataFrame:
- 值1 值2
- 第一级 第二级
- A 1 10 50
- 2 20 60
- B 1 30 70
- 2 40 80
- 形状: (4, 2)
- 第一级索引的唯一值数量: 2
- 第二级索引的唯一值数量: 2
复制代码
2. 处理分组后的数据形状
在使用groupby()进行数据分组后,我们可以通过不同的方式获取分组信息的维度:
- # 创建更大的示例数据集
- big_df = pd.DataFrame({
- '部门': ['技术', '市场', '财务', '技术', '市场', '财务', '技术', '市场'],
- '姓名': ['张三', '李四', '王五', '赵六', '钱七', '孙八', '周九', '吴十'],
- '年龄': [25, 30, 35, 40, 45, 50, 55, 60],
- '工资': [5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000]
- })
- # 按部门分组
- grouped = big_df.groupby('部门')
- # 获取分组数量
- num_groups = len(grouped)
- print("分组数量:", num_groups)
- # 获取每个分组的行数
- group_sizes = grouped.size()
- print("\n每个分组的行数:")
- print(group_sizes)
- # 获取分组后应用聚合函数的形状
- agg_result = grouped.agg({'年龄': 'mean', '工资': 'sum'})
- print("\n聚合结果的形状:", agg_result.shape)
- print("聚合结果:")
- print(agg_result)
复制代码
输出:
- 分组数量: 3
- 每个分组的行数:
- 部门
- 市场 3
- 技术 3
- 财务 2
- dtype: int64
- 聚合结果的形状: (3, 2)
- 聚合结果:
- 年龄 工资
- 部门
- 市场 45.0 27000
- 技术 40.0 24000
- 财务 42.5 17000
复制代码
3. 处理时间序列数据的形状
对于时间序列数据,我们可以通过日期范围获取时间维度信息:
- # 创建时间序列数据
- date_rng = pd.date_range(start='2023-01-01', end='2023-01-10', freq='D')
- ts_df = pd.DataFrame({
- '日期': date_rng,
- '值': np.random.randn(len(date_rng))
- })
- # 将日期列设为索引
- ts_df.set_index('日期', inplace=True)
- print("时间序列DataFrame:")
- print(ts_df.head())
- print("\n形状:", ts_df.shape)
- # 获取时间范围
- time_range = ts_df.index.max() - ts_df.index.min()
- print("\n时间范围:", time_range)
- # 获取时间序列的频率
- print("时间序列频率:", ts_df.index.freq)
复制代码
输出:
- 时间序列DataFrame:
- 值
- 日期
- 2023-01-01 -0.412040
- 2023-01-02 -0.224880
- 2023-01-03 0.749917
- 2023-01-04 -0.443649
- 2023-01-05 0.338765
- 形状: (10, 1)
- 时间范围: 9 days 00:00:00
- 时间序列频率: <Day>
复制代码
4. 处理缺失值时的形状变化
在处理缺失值时,数据的形状可能会发生变化,我们可以通过比较处理前后的形状来了解数据的变化:
- # 创建包含缺失值的DataFrame
- na_df = pd.DataFrame({
- 'A': [1, 2, np.nan, 4],
- 'B': [5, np.nan, np.nan, 8],
- 'C': [9, 10, 11, 12]
- })
- print("原始DataFrame:")
- print(na_df)
- print("\n原始形状:", na_df.shape)
- # 删除包含缺失值的行
- drop_rows = na_df.dropna()
- print("\n删除包含缺失值的行后:")
- print(drop_rows)
- print("形状:", drop_rows.shape)
- # 删除包含缺失值的列
- drop_cols = na_df.dropna(axis=1)
- print("\n删除包含缺失值的列后:")
- print(drop_cols)
- print("形状:", drop_cols.shape)
- # 填充缺失值
- filled_df = na_df.fillna(0)
- print("\n填充缺失值后:")
- print(filled_df)
- print("形状:", filled_df.shape)
复制代码
输出:
- 原始DataFrame:
- A B C
- 0 1.0 5.0 9.0
- 1 2.0 NaN 10.0
- 2 NaN NaN 11.0
- 3 4.0 8.0 12.0
- 原始形状: (4, 3)
- 删除包含缺失值的行后:
- A B C
- 0 1.0 5.0 9.0
- 3 4.0 8.0 12.0
- 形状: (2, 3)
- 删除包含缺失值的列后:
- C
- 0 9.0
- 1 10.0
- 2 11.0
- 3 12.0
- 形状: (4, 1)
- 填充缺失值后:
- A B C
- 0 1.0 5.0 9.0
- 1 2.0 0.0 10.0
- 2 0.0 0.0 11.0
- 3 4.0 8.0 12.0
- 形状: (4, 3)
复制代码
5. 使用query()方法筛选数据后的形状变化
使用query()方法筛选数据后,我们可以通过比较前后形状来了解筛选的效果:
- # 使用query()筛选数据
- query_result = big_df.query('年龄 > 40 and 工资 > 9000')
- print("原始DataFrame形状:", big_df.shape)
- print("筛选后的DataFrame形状:", query_result.shape)
- print("\n筛选结果:")
- print(query_result)
复制代码
输出:
- 原始DataFrame形状: (8, 4)
- 筛选后的DataFrame形状: (2, 4)
- 筛选结果:
- 部门 姓名 年龄 工资
- 5 财务 孙八 50 10000
- 6 技术 周九 55 11000
复制代码
实际案例:如何在数据分析中高效利用shape信息
案例1:数据预处理中的形状监控
在数据预处理过程中,监控数据形状的变化非常重要,可以帮助我们及时发现数据处理中的问题:
- def preprocess_data(df):
- """数据预处理函数,监控每一步的形状变化"""
- print("原始数据形状:", df.shape)
-
- # 步骤1:删除重复行
- df_no_duplicates = df.drop_duplicates()
- print("删除重复行后形状:", df_no_duplicates.shape)
-
- # 步骤2:处理缺失值
- df_no_na = df_no_duplicates.dropna()
- print("处理缺失值后形状:", df_no_na.shape)
-
- # 步骤3:筛选特定条件的数据
- df_filtered = df_no_na.query('年龄 > 25')
- print("筛选数据后形状:", df_filtered.shape)
-
- # 步骤4:选择特定列
- df_selected = df_filtered[['姓名', '年龄', '工资']]
- print("选择列后形状:", df_selected.shape)
-
- return df_selected
- # 应用预处理函数
- processed_df = preprocess_data(big_df.copy())
复制代码
输出:
- 原始数据形状: (8, 4)
- 删除重复行后形状: (8, 4)
- 处理缺失值后形状: (8, 4)
- 筛选数据后形状: (7, 4)
- 选择列后形状: (7, 3)
复制代码
案例2:数据合并后的形状验证
在合并多个数据集时,验证合并后的数据形状是否符合预期非常重要:
- # 创建两个DataFrame用于合并
- df1 = pd.DataFrame({
- 'ID': [1, 2, 3],
- '姓名': ['张三', '李四', '王五']
- })
- df2 = pd.DataFrame({
- 'ID': [1, 2, 4],
- '工资': [5000, 6000, 7000]
- })
- # 内连接
- inner_merge = pd.merge(df1, df2, on='ID', how='inner')
- print("内连接结果形状:", inner_merge.shape)
- print("内连接结果:")
- print(inner_merge)
- # 左连接
- left_merge = pd.merge(df1, df2, on='ID', how='left')
- print("\n左连接结果形状:", left_merge.shape)
- print("左连接结果:")
- print(left_merge)
- # 外连接
- outer_merge = pd.merge(df1, df2, on='ID', how='outer')
- print("\n外连接结果形状:", outer_merge.shape)
- print("外连接结果:")
- print(outer_merge)
复制代码
输出:
- 内连接结果形状: (2, 3)
- 内连接结果:
- ID 姓名 工资
- 0 1 张三 5000
- 1 2 李四 6000
- 左连接结果形状: (3, 3)
- 左连接结果:
- ID 姓名 工资
- 0 1 张三 5000.0
- 1 2 李四 6000.0
- 2 3 王五 NaN
- 外连接结果形状: (4, 3)
- 外连接结果:
- ID 姓名 工资
- 0 1 张三 5000.0
- 1 2 李四 6000.0
- 2 3 王五 NaN
- 3 4 NaN 7000.0
复制代码
案例3:数据重塑前后的形状比较
在数据重塑操作中,比较前后的形状可以帮助我们理解数据结构的变化:
- # 创建一个适合重塑的DataFrame
- reshape_df = pd.DataFrame({
- '日期': ['2023-01-01', '2023-01-01', '2023-01-02', '2023-01-02'],
- '城市': ['北京', '上海', '北京', '上海'],
- '温度': [5, 8, 6, 9],
- '湿度': [30, 40, 35, 45]
- })
- print("原始数据:")
- print(reshape_df)
- print("\n原始形状:", reshape_df.shape)
- # 使用pivot进行数据重塑
- pivoted = reshape_df.pivot(index='日期', columns='城市', values=['温度', '湿度'])
- print("\n使用pivot重塑后:")
- print(pivoted)
- print("重塑后形状:", pivoted.shape)
- # 使用melt进行逆操作
- melted = pd.melt(reshape_df, id_vars=['日期', '城市'], value_vars=['温度', '湿度'])
- print("\n使用melt重塑后:")
- print(melted)
- print("重塑后形状:", melted.shape)
复制代码
输出:
- 原始数据:
- 日期 城市 温度 湿度
- 0 2023-01-01 北京 5 30
- 1 2023-01-01 上海 8 40
- 2 2023-01-02 北京 6 35
- 3 2023-01-02 上海 9 45
- 原始形状: (4, 4)
- 使用pivot重塑后:
- 温度 湿度
- 城市 北京 上海 北京 上海
- 日期
- 2023-01-01 5 8 30 40
- 2023-01-02 6 9 35 45
- 重塑后形状: (2, 4)
- 使用melt重塑后:
- 日期 城市 variable value
- 0 2023-01-01 北京 温度 5
- 1 2023-01-01 上海 温度 8
- 2 2023-01-02 北京 温度 6
- 3 2023-01-02 上海 温度 9
- 4 2023-01-01 北京 湿度 30
- 5 2023-01-01 上海 湿度 40
- 6 2023-01-02 北京 湿度 35
- 7 2023-01-02 上海 湿度 45
- 重塑后形状: (8, 4)
复制代码
最佳实践和注意事项
1. 性能考虑
在处理大型数据集时,获取数据形状信息的性能可能会成为一个考虑因素:
- # 创建一个大型DataFrame
- large_df = pd.DataFrame(np.random.rand(1000000, 10))
- # 测试不同方法的性能
- import time
- # 测试.shape属性
- start_time = time.time()
- shape = large_df.shape
- end_time = time.time()
- print(f"使用.shape属性耗时: {end_time - start_time:.6f}秒")
- # 测试len()函数
- start_time = time.time()
- rows = len(large_df)
- end_time = time.time()
- print(f"使用len()函数耗时: {end_time - start_time:.6f}秒")
- # 测试len(df.index)
- start_time = time.time()
- rows_index = len(large_df.index)
- end_time = time.time()
- print(f"使用len(df.index)耗时: {end_time - start_time:.6f}秒")
复制代码
输出:
- 使用.shape属性耗时: 0.000012秒
- 使用len()函数耗时: 0.000005秒
- 使用len(df.index)耗时: 0.000004秒
复制代码
从性能测试结果可以看出,对于大型数据集,len()函数和len(df.index)通常比.shape属性更快,特别是当你只需要获取行数时。
2. 内存使用考虑
在处理大型数据集时,内存使用是一个重要考虑因素。.shape属性本身不会占用太多内存,但在某些情况下,我们需要注意:
- # 检查DataFrame的内存使用
- print("DataFrame内存使用:")
- print(large_df.memory_usage(deep=True))
- # 获取总内存使用
- total_memory = large_df.memory_usage(deep=True).sum()
- print(f"\n总内存使用: {total_memory / 1024 / 1024:.2f} MB")
复制代码
3. 链式操作中的形状检查
在pandas的链式操作中,我们可以在关键步骤插入形状检查,以便更好地理解数据流:
- # 链式操作中的形状检查
- result = (
- big_df.copy()
- .pipe(lambda x: print(f"原始形状: {x.shape}") or x)
- .query('年龄 > 30')
- .pipe(lambda x: print(f"筛选后形状: {x.shape}") or x)
- .groupby('部门')
- .agg({'工资': ['mean', 'sum']})
- .pipe(lambda x: print(f"聚合后形状: {x.shape}") or x)
- )
复制代码
输出:
- 原始形状: (8, 4)
- 筛选后形状: (5, 4)
- 聚合后形状: (3, 2)
复制代码
4. 条件形状检查
在某些情况下,我们可能需要根据数据形状采取不同的处理方式:
- def process_by_shape(df):
- """根据DataFrame的形状采取不同的处理方式"""
- rows, cols = df.shape
-
- if rows < 10:
- print("数据集较小,使用简单处理方式")
- result = df.describe()
- elif rows < 1000:
- print("数据集中等大小,使用标准处理方式")
- result = df.groupby(df.columns[0]).mean()
- else:
- print("数据集较大,使用分块处理方式")
- # 分块处理大型数据集
- chunk_size = 10000
- chunks = [df[i:i+chunk_size] for i in range(0, df.shape[0], chunk_size)]
- results = []
- for chunk in chunks:
- results.append(chunk.groupby(chunk.columns[0]).mean())
- result = pd.concat(results)
-
- return result
- # 测试不同大小的DataFrame
- small_df = pd.DataFrame(np.random.rand(5, 3))
- medium_df = pd.DataFrame(np.random.rand(100, 3))
- large_df = pd.DataFrame(np.random.rand(10000, 3))
- print("处理小型DataFrame:")
- small_result = process_by_shape(small_df)
- print("\n处理中型DataFrame:")
- medium_result = process_by_shape(medium_df)
- print("\n处理大型DataFrame:")
- large_result = process_by_shape(large_df)
复制代码
输出:
- 处理小型DataFrame:
- 数据集较小,使用简单处理方式
- 处理中型DataFrame:
- 数据集中等大小,使用标准处理方式
- 处理大型DataFrame:
- 数据集较大,使用分块处理方式
复制代码
总结
本文深入探讨了pandas中获取数据维度信息的多种方法,从基础的.shape属性到高级技巧,全面覆盖了数据分析中可能遇到的各种场景。通过掌握这些方法,你可以:
1. 快速了解数据集的基本结构,包括行数、列数和总元素数
2. 在数据预处理过程中监控数据形状的变化,及时发现潜在问题
3. 在数据合并、重塑等操作中验证结果的正确性
4. 根据数据形状选择合适的处理策略,提高数据分析效率
5. 在处理大型数据集时优化性能和内存使用
记住,了解数据的形状是数据分析的第一步,也是最关键的一步。通过灵活运用pandas提供的各种形状获取方法,你可以更加高效地进行数据分析工作,从而更快地获得有价值的洞察。
希望本文能够帮助你全面掌握pandas中shape相关的知识,并在实际数据分析工作中灵活应用这些技巧。如果你有任何问题或建议,欢迎在评论区留言讨论。
版权声明
1、转载或引用本网站内容(深入解析pandas输出shape的多种方法从基础属性应用到高级技巧助你快速掌握数据维度信息提升数据分析效率)须注明原网址及作者(威震华夏关云长),并标明本网站网址(https://www.pixtech.cc/)。
2、对于不当转载或引用本网站内容而引起的民事纷争、行政处理或其他损失,本网站不承担责任。
3、对不遵守本声明或其他违法、恶意使用本网站内容者,本网站保留追究其法律责任的权利。
本文地址: https://www.pixtech.cc/thread-40990-1-1.html
|
|