|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
1. 引言
在当今数据驱动的时代,数据处理已成为各行各业不可或缺的技能。Python的Pandas库作为数据科学领域最强大的工具之一,提供了丰富的数据读取和存储功能,能够帮助我们高效地处理各种格式的数据。无论你是数据分析师、科学家还是工程师,掌握Pandas的数据读取和存储技巧都将大大提升你的工作效率。
本文将从基础到高级,全面解析Pandas的数据读取和存储操作,帮助你轻松应对各种数据格式挑战。我们将通过详细的代码示例和实际案例,展示如何使用Pandas处理CSV、Excel、JSON、SQL等多种数据格式,并介绍一些高级技巧来优化数据处理流程。
2. Pandas基础
2.1 Pandas简介
Pandas是Python的一个开源数据分析和处理库,提供了高性能、易于使用的数据结构和数据分析工具。它建立在NumPy之上,为Python编程语言提供了大量能使数据工作变得更快、更简单的高级数据结构和操作工具。
2.2 数据结构:Series和DataFrame
Pandas主要有两种数据结构:
• Series:一维标记数组,能够保存任何数据类型(整数、字符串、浮点数、Python对象等)。轴标签统称为索引。
- import pandas as pd
- # 创建一个Series
- s = pd.Series([1, 3, 5, np.nan, 6, 8])
- print(s)
复制代码
• DataFrame:二维标记数据结构,列可以是不同的数据类型。它类似于电子表格或SQL表,是Pandas中最常用的数据结构。
- import pandas as pd
- import numpy as np
- # 创建一个DataFrame
- df = pd.DataFrame({
- 'A': pd.date_range(start='20230101', periods=6),
- 'B': np.random.randn(6),
- 'C': pd.Series([1, 2, 3, 4, 5, 6], dtype='float32'),
- 'D': np.array([5] * 6, dtype='int32'),
- 'E': pd.Categorical(['test', 'train', 'test', 'train', 'test', 'train']),
- 'F': 'foo'
- })
- print(df)
复制代码
2.3 安装和导入
在开始使用Pandas之前,需要确保已安装该库。可以使用pip或conda进行安装:
- # 使用pip安装
- pip install pandas
- # 或者使用conda安装
- conda install pandas
复制代码
安装完成后,可以在Python脚本中导入Pandas:
3. 数据读取基础操作
3.1 CSV文件读取
CSV(Comma-Separated Values)是最常见的数据格式之一。Pandas提供了read_csv()函数来读取CSV文件。
- import pandas as pd
- # 读取CSV文件
- df = pd.read_csv('data.csv')
- # 查看前5行数据
- print(df.head())
- # 查看数据基本信息
- print(df.info())
- # 查看数据统计摘要
- print(df.describe())
复制代码
read_csv()函数有许多参数可以自定义读取行为:
- # 指定分隔符
- df = pd.read_csv('data.csv', sep=';')
- # 指定编码
- df = pd.read_csv('data.csv', encoding='utf-8')
- # 指定列名
- df = pd.read_csv('data.csv', names=['列1', '列2', '列3'])
- # 指定索引列
- df = pd.read_csv('data.csv', index_col=0)
- # 跳过行
- df = pd.read_csv('data.csv', skiprows=1)
- # 只读取指定行
- df = pd.read_csv('data.csv', nrows=100)
- # 解析日期列
- df = pd.read_csv('data.csv', parse_dates=['date_column'])
- # 处理缺失值
- df = pd.read_csv('data.csv', na_values=['NA', 'N/A', 'null', 'NaN', ''])
复制代码
3.2 Excel文件读取
Excel文件是商业环境中常用的数据格式。Pandas提供了read_excel()函数来读取Excel文件。
- import pandas as pd
- # 读取Excel文件
- df = pd.read_excel('data.xlsx')
- # 指定工作表名称
- df = pd.read_excel('data.xlsx', sheet_name='Sheet1')
- # 指定工作表索引
- df = pd.read_excel('data.xlsx', sheet_name=0)
- # 读取多个工作表
- dfs = pd.read_excel('data.xlsx', sheet_name=['Sheet1', 'Sheet2'])
- # 指定列
- df = pd.read_excel('data.xlsx', usecols=['A', 'C', 'E'])
- # 跳过行
- df = pd.read_excel('data.xlsx', skiprows=2)
- # 指定行作为列名
- df = pd.read_excel('data.xlsx', header=1)
复制代码
注意:要读取Excel文件,需要安装额外的库:
- pip install openpyxl # 用于.xlsx文件
- pip install xlrd # 用于.xls文件
复制代码
3.3 JSON文件读取
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。Pandas提供了read_json()函数来读取JSON文件。
- import pandas as pd
- # 读取JSON文件
- df = pd.read_json('data.json')
- # 指定JSON的格式
- df = pd.read_json('data.json', orient='records')
- # 处理嵌套JSON
- df = pd.read_json('data.json', orient='records', lines=True)
- # 指定数据类型
- df = pd.read_json('data.json', dtype={'column1': 'float64', 'column2': 'int32'})
复制代码
3.4 HTML表格读取
Pandas可以直接从HTML页面中读取表格数据,使用read_html()函数。
- import pandas as pd
- # 读取HTML中的所有表格
- tables = pd.read_html('https://example.com/table.html')
- # 获取第一个表格
- df = tables[0]
- # 指定表格属性
- df = pd.read_html('https://example.com/table.html', attrs={'id': 'table_id'})[0]
复制代码
注意:要使用read_html(),需要安装额外的库:
- pip install lxml
- pip install html5lib
- pip install beautifulsoup4
复制代码
3.5 SQL数据库读取
Pandas提供了read_sql()和read_sql_query()函数来从SQL数据库中读取数据。
- import pandas as pd
- import sqlite3
- # 创建数据库连接
- conn = sqlite3.connect('database.db')
- # 读取整个表
- df = pd.read_sql('table_name', conn)
- # 执行SQL查询
- df = pd.read_sql_query('SELECT * FROM table_name WHERE column1 > 100', conn)
- # 使用参数化查询
- df = pd.read_sql_query('SELECT * FROM table_name WHERE column1 > :value', conn, params={'value': 100})
- # 关闭连接
- conn.close()
复制代码
对于其他数据库,如MySQL、PostgreSQL等,需要安装相应的连接库:
- pip install pymysql # MySQL
- pip install psycopg2 # PostgreSQL
复制代码
4. 数据存储基础操作
4.1 存储为CSV
将DataFrame保存为CSV文件是最常见的存储方式之一,使用to_csv()方法。
- import pandas as pd
- # 创建示例DataFrame
- df = pd.DataFrame({
- 'Name': ['Alice', 'Bob', 'Charlie'],
- 'Age': [25, 30, 35],
- 'City': ['New York', 'Los Angeles', 'Chicago']
- })
- # 保存为CSV文件
- df.to_csv('output.csv', index=False) # 不保存索引
- # 指定分隔符
- df.to_csv('output.csv', sep=';', index=False)
- # 指定编码
- df.to_csv('output.csv', encoding='utf-8', index=False)
- # 处理缺失值
- df.to_csv('output.csv', na_rep='NULL', index=False)
- # 只保存部分列
- df.to_csv('output.csv', columns=['Name', 'Age'], index=False)
复制代码
4.2 存储为Excel
将DataFrame保存为Excel文件,使用to_excel()方法。
- import pandas as pd
- # 创建示例DataFrame
- df = pd.DataFrame({
- 'Name': ['Alice', 'Bob', 'Charlie'],
- 'Age': [25, 30, 35],
- 'City': ['New York', 'Los Angeles', 'Chicago']
- })
- # 保存为Excel文件
- df.to_excel('output.xlsx', index=False)
- # 指定工作表名称
- df.to_excel('output.xlsx', sheet_name='Data', index=False)
- # 保存多个DataFrame到同一个Excel文件
- with pd.ExcelWriter('output.xlsx') as writer:
- df1.to_excel(writer, sheet_name='Sheet1', index=False)
- df2.to_excel(writer, sheet_name='Sheet2', index=False)
- # 指定位置
- df.to_excel('output.xlsx', startrow=1, startcol=1, index=False)
复制代码
4.3 存储为JSON
将DataFrame保存为JSON文件,使用to_json()方法。
- import pandas as pd
- # 创建示例DataFrame
- df = pd.DataFrame({
- 'Name': ['Alice', 'Bob', 'Charlie'],
- 'Age': [25, 30, 35],
- 'City': ['New York', 'Los Angeles', 'Chicago']
- })
- # 保存为JSON文件
- df.to_json('output.json')
- # 指定JSON格式
- df.to_json('output.json', orient='records')
- # 处理日期
- df.to_json('output.json', date_format='iso')
- # 压缩输出
- df.to_json('output.json', compression='gzip')
复制代码
4.4 存储到SQL数据库
将DataFrame保存到SQL数据库,使用to_sql()方法。
- import pandas as pd
- import sqlite3
- # 创建示例DataFrame
- df = pd.DataFrame({
- 'Name': ['Alice', 'Bob', 'Charlie'],
- 'Age': [25, 30, 35],
- 'City': ['New York', 'Los Angeles', 'Chicago']
- })
- # 创建数据库连接
- conn = sqlite3.connect('database.db')
- # 保存到SQL数据库
- df.to_sql('table_name', conn, if_exists='replace', index=False)
- # 追加数据
- df.to_sql('table_name', conn, if_exists='append', index=False)
- # 指定数据类型
- df.to_sql('table_name', conn, if_exists='replace', index=False,
- dtype={'Age': 'INTEGER', 'Name': 'TEXT', 'City': 'TEXT'})
- # 关闭连接
- conn.close()
复制代码
5. 数据读取高级应用
5.1 处理大型数据集
当处理大型数据集时,内存可能成为限制因素。Pandas提供了几种方法来处理这种情况:
- import pandas as pd
- # 使用chunksize参数分块读取
- chunk_size = 10000
- chunks = pd.read_csv('large_data.csv', chunksize=chunk_size)
- # 处理每个块
- for chunk in chunks:
- # 对每个块执行操作
- processed_chunk = process_function(chunk)
- # 可以将处理后的块保存到文件或数据库
- processed_chunk.to_csv('processed_data.csv', mode='a', header=False, index=False)
- # 使用迭代器处理
- reader = pd.read_csv('large_data.csv', iterator=True)
- chunk = reader.get_chunk(chunk_size)
复制代码
5.2 指定数据类型
在读取数据时指定数据类型可以减少内存使用并提高性能:
- import pandas as pd
- # 指定数据类型
- dtypes = {
- 'id': 'int32',
- 'name': 'category',
- 'value': 'float32',
- 'date': 'str'
- }
- df = pd.read_csv('data.csv', dtype=dtypes)
- # 使用converters参数进行更复杂的转换
- df = pd.read_csv('data.csv', converters={
- 'id': lambda x: int(x.strip()),
- 'name': lambda x: x.strip().title()
- })
复制代码
5.3 处理缺失值
在读取数据时处理缺失值可以简化后续的数据清洗过程:
- import pandas as pd
- import numpy as np
- # 指定哪些值应被视为NaN
- na_values = ['NA', 'N/A', 'null', 'NaN', '', 'NULL']
- df = pd.read_csv('data.csv', na_values=na_values)
- # 为不同列指定不同的缺失值标记
- na_values = {
- 'column1': ['NA', 'N/A'],
- 'column2': ['null', 'NULL'],
- 'column3': ['']
- }
- df = pd.read_csv('data.csv', na_values=na_values)
- # 读取后填充缺失值
- df = pd.read_csv('data.csv').fillna({
- 'column1': 0,
- 'column2': 'Unknown',
- 'column3': df['column3'].mean()
- })
复制代码
5.4 日期时间解析
正确解析日期时间数据对于时间序列分析至关重要:
- import pandas as pd
- # 自动解析日期列
- df = pd.read_csv('data.csv', parse_dates=['date_column'])
- # 指定日期格式
- df = pd.read_csv('data.csv', parse_dates=['date_column'],
- date_parser=lambda x: pd.datetime.strptime(x, '%Y-%m-%d'))
- # 组合多个列创建日期时间
- df = pd.read_csv('data.csv', parse_dates={'datetime': ['year', 'month', 'day']})
- # 处理国际日期格式
- df = pd.read_csv('data.csv', parse_dates=['date_column'], dayfirst=True)
复制代码
6. 数据存储高级应用
6.1 压缩选项
在存储大型数据集时,使用压缩可以节省磁盘空间:
- import pandas as pd
- # 创建示例DataFrame
- df = pd.DataFrame({
- 'Name': ['Alice', 'Bob', 'Charlie'],
- 'Age': [25, 30, 35],
- 'City': ['New York', 'Los Angeles', 'Chicago']
- })
- # 保存为压缩的CSV文件
- df.to_csv('output.csv.gz', compression='gzip', index=False)
- df.to_csv('output.csv.bz2', compression='bz2', index=False)
- df.to_csv('output.csv.zip', compression='zip', index=False)
- df.to_csv('output.csv.xz', compression='xz', index=False)
- # 读取压缩文件
- df_compressed = pd.read_csv('output.csv.gz', compression='gzip')
复制代码
6.2 分区存储
对于大型数据集,分区存储可以提高查询性能:
- import pandas as pd
- import os
- # 创建示例DataFrame
- df = pd.DataFrame({
- 'Date': pd.date_range('20230101', periods=100),
- 'Category': ['A', 'B', 'C', 'D'] * 25,
- 'Value': np.random.randn(100)
- })
- # 按类别分区存储
- for category, group in df.groupby('Category'):
- if not os.path.exists(f'data/category={category}'):
- os.makedirs(f'data/category={category}')
- group.to_csv(f'data/category={category}/data.csv', index=False)
- # 按日期分区存储
- df['YearMonth'] = df['Date'].dt.strftime('%Y-%m')
- for year_month, group in df.groupby('YearMonth'):
- if not os.path.exists(f'data/year_month={year_month}'):
- os.makedirs(f'data/year_month={year_month}')
- group.to_csv(f'data/year_month={year_month}/data.csv', index=False)
复制代码
6.3 增量存储
增量存储允许你定期添加新数据而不重写整个文件:
- import pandas as pd
- import os
- # 创建示例DataFrame
- df_new = pd.DataFrame({
- 'Date': pd.date_range('20230101', periods=10),
- 'Value': np.random.randn(10)
- })
- # 检查文件是否存在
- if os.path.exists('existing_data.csv'):
- # 读取现有数据
- df_existing = pd.read_csv('existing_data.csv', parse_dates=['Date'])
- # 合并数据
- df_combined = pd.concat([df_existing, df_new])
- # 去重
- df_combined = df_combined.drop_duplicates(subset=['Date'])
- # 保存合并后的数据
- df_combined.to_csv('existing_data.csv', index=False)
- else:
- # 如果文件不存在,直接保存新数据
- df_new.to_csv('existing_data.csv', index=False)
复制代码
6.4 性能优化
优化数据存储性能的几种方法:
- import pandas as pd
- # 创建示例DataFrame
- df = pd.DataFrame({
- 'ID': range(100000),
- 'Name': ['User_' + str(i) for i in range(100000)],
- 'Value': np.random.randn(100000),
- 'Category': ['A', 'B', 'C', 'D'] * 25000
- })
- # 使用更高效的数据类型
- df['ID'] = df['ID'].astype('int32')
- df['Name'] = df['Name'].astype('category')
- df['Value'] = df['Value'].astype('float32')
- df['Category'] = df['Category'].astype('category')
- # 保存为更高效的格式
- df.to_feather('data.feather') # Feather格式,读写速度快
- df.to_parquet('data.parquet') # Parquet格式,支持压缩和列式存储
- df.to_pickle('data.pkl') # Pickle格式,Python原生支持
- # 使用HDF5存储
- df.to_hdf('data.h5', key='df', mode='w')
复制代码
7. 处理特殊数据格式
7.1 处理XML数据
虽然Pandas没有内置的XML读取函数,但可以结合其他库处理XML数据:
- import pandas as pd
- import xml.etree.ElementTree as ET
- # 解析XML文件
- tree = ET.parse('data.xml')
- root = tree.getroot()
- # 提取数据
- data = []
- for child in root:
- row = {}
- for subchild in child:
- row[subchild.tag] = subchild.text
- data.append(row)
- # 创建DataFrame
- df = pd.DataFrame(data)
- # 或者使用lxml库
- from lxml import objectify
- xml = objectify.parse('data.xml')
- root = xml.getroot()
- data = []
- for row in root.getchildren():
- row_data = {}
- for col in row.getchildren():
- row_data[col.tag] = col.text
- data.append(row_data)
- df = pd.DataFrame(data)
复制代码
7.2 处理HDF5文件
HDF5是一种高效的数据存储格式,适合处理大型数据集:
- import pandas as pd
- import numpy as np
- # 创建示例DataFrame
- df = pd.DataFrame({
- 'Date': pd.date_range('20230101', periods=1000),
- 'Value': np.random.randn(1000)
- })
- # 保存为HDF5文件
- df.to_hdf('data.h5', key='df', mode='w')
- # 读取HDF5文件
- df_read = pd.read_hdf('data.h5', key='df')
- # 存储多个DataFrame
- df2 = pd.DataFrame({
- 'Category': ['A', 'B', 'C', 'D'] * 250,
- 'Count': np.random.randint(1, 100, 1000)
- })
- with pd.HDFStore('data.h5') as store:
- store.put('df1', df)
- store.put('df2', df2)
-
- # 读取特定DataFrame
- with pd.HDFStore('data.h5') as store:
- df1_read = store.get('df1')
- df2_read = store.get('df2')
复制代码
7.3 处理Parquet文件
Parquet是一种列式存储格式,适合处理大型数据集:
- import pandas as pd
- # 创建示例DataFrame
- df = pd.DataFrame({
- 'Date': pd.date_range('20230101', periods=1000),
- 'Category': ['A', 'B', 'C', 'D'] * 250,
- 'Value': np.random.randn(1000)
- })
- # 保存为Parquet文件
- df.to_parquet('data.parquet')
- # 读取Parquet文件
- df_read = pd.read_parquet('data.parquet')
- # 指定压缩方式
- df.to_parquet('data.parquet.gzip', compression='gzip')
- df.to_parquet('data.parquet.snappy', compression='snappy')
- df.to_parquet('data.parquet.brotli', compression='brotli')
- # 只读取特定列
- df_subset = pd.read_parquet('data.parquet', columns=['Date', 'Value'])
复制代码
7.4 处理Feather文件
Feather是一种高效的二进制文件格式,适合快速读写:
- import pandas as pd
- # 创建示例DataFrame
- df = pd.DataFrame({
- 'Date': pd.date_range('20230101', periods=1000),
- 'Category': ['A', 'B', 'C', 'D'] * 250,
- 'Value': np.random.randn(1000)
- })
- # 保存为Feather文件
- df.to_feather('data.feather')
- # 读取Feather文件
- df_read = pd.read_feather('data.feather')
- # 只读取特定列
- df_subset = pd.read_feather('data.feather', columns=['Date', 'Value'])
复制代码
7.5 处理剪贴板数据
Pandas可以方便地读取和写入剪贴板数据:
- import pandas as pd
- # 从剪贴板读取数据
- df = pd.read_clipboard()
- # 将数据写入剪贴板
- df.to_clipboard(index=False)
- # 指定分隔符
- df.to_clipboard(sep='\t', index=False)
复制代码
8. 数据读取存储的性能优化
8.1 内存优化
优化内存使用可以处理更大的数据集:
- import pandas as pd
- import numpy as np
- # 创建示例DataFrame
- df = pd.DataFrame({
- 'ID': range(1000000),
- 'Name': ['User_' + str(i) for i in range(1000000)],
- 'Value': np.random.randn(1000000),
- 'Category': ['A', 'B', 'C', 'D'] * 250000
- })
- # 检查内存使用
- print(df.memory_usage(deep=True))
- # 优化数据类型
- df['ID'] = df['ID'].astype('int32')
- df['Name'] = df['Name'].astype('category')
- df['Value'] = df['Value'].astype('float32')
- df['Category'] = df['Category'].astype('category')
- # 再次检查内存使用
- print(df.memory_usage(deep=True))
- # 使用更高效的数据类型读取CSV
- dtypes = {
- 'ID': 'int32',
- 'Name': 'category',
- 'Value': 'float32',
- 'Category': 'category'
- }
- df_optimized = pd.read_csv('data.csv', dtype=dtypes)
复制代码
8.2 并行处理
使用并行处理可以提高数据处理速度:
- import pandas as pd
- import numpy as np
- from multiprocessing import Pool, cpu_count
- # 创建示例DataFrame
- df = pd.DataFrame({
- 'ID': range(1000000),
- 'Value': np.random.randn(1000000)
- })
- # 定义处理函数
- def process_chunk(chunk):
- # 对每个数据块执行操作
- chunk['Processed'] = chunk['Value'] * 2
- return chunk
- # 将数据分成多个块
- num_cores = cpu_count()
- chunks = np.array_split(df, num_cores)
- # 创建进程池
- pool = Pool(num_cores)
- # 并行处理
- result = pool.map(process_chunk, chunks)
- # 合并结果
- df_processed = pd.concat(result)
- # 关闭进程池
- pool.close()
- pool.join()
复制代码
8.3 缓存策略
使用缓存可以避免重复计算和读取:
- import pandas as pd
- import os
- import hashlib
- import pickle
- def get_data_hash(file_path):
- """计算文件哈希值作为缓存键"""
- hasher = hashlib.md5()
- with open(file_path, 'rb') as f:
- buf = f.read()
- hasher.update(buf)
- return hasher.hexdigest()
- def load_data_with_cache(file_path, cache_dir='cache'):
- """带缓存的数据加载函数"""
- # 确保缓存目录存在
- if not os.path.exists(cache_dir):
- os.makedirs(cache_dir)
-
- # 计算文件哈希值
- file_hash = get_data_hash(file_path)
- cache_file = os.path.join(cache_dir, f'{file_hash}.pkl')
-
- # 检查缓存是否存在
- if os.path.exists(cache_file):
- print("从缓存加载数据...")
- with open(cache_file, 'rb') as f:
- return pickle.load(f)
- else:
- print("从文件加载数据...")
- # 从文件加载数据
- df = pd.read_csv(file_path)
-
- # 执行一些耗时的处理
- df['Processed'] = df['Value'] * 2
-
- # 保存到缓存
- with open(cache_file, 'wb') as f:
- pickle.dump(df, f)
-
- return df
- # 使用缓存加载数据
- df = load_data_with_cache('large_data.csv')
复制代码
8.4 最佳实践
一些提高数据处理效率的最佳实践:
- import pandas as pd
- import numpy as np
- # 1. 使用适当的数据类型
- df = pd.DataFrame({
- 'ID': range(1000000),
- 'Value': np.random.randn(1000000),
- 'Category': np.random.choice(['A', 'B', 'C', 'D'], 1000000)
- })
- # 优化数据类型
- df['ID'] = pd.to_numeric(df['ID'], downcast='integer')
- df['Value'] = pd.to_numeric(df['Value'], downcast='float')
- df['Category'] = df['Category'].astype('category')
- # 2. 避免链式索引
- # 不好的做法
- df[df['Value'] > 0]['Category'] = 'Positive'
- # 好的做法
- df.loc[df['Value'] > 0, 'Category'] = 'Positive'
- # 3. 使用向量化操作
- # 不好的做法
- for i in range(len(df)):
- df.loc[i, 'NewValue'] = df.loc[i, 'Value'] * 2
- # 好的做法
- df['NewValue'] = df['Value'] * 2
- # 4. 使用适当的数据存储格式
- # 对于大型数据集,使用Parquet或Feather而不是CSV
- df.to_parquet('data.parquet')
- # 5. 分块处理大型文件
- chunk_size = 100000
- reader = pd.read_csv('very_large_file.csv', chunksize=chunk_size)
- for chunk in reader:
- # 处理每个块
- processed_chunk = process_function(chunk)
- # 保存处理后的块
- processed_chunk.to_parquet(f'processed_chunk_{chunk.index[0]}.parquet')
复制代码
9. 实战案例
9.1 案例一:数据清洗与转换
假设我们有一个包含销售数据的CSV文件,需要进行清洗和转换:
- import pandas as pd
- import numpy as np
- # 读取原始数据
- df = pd.read_csv('sales_data.csv')
- # 查看数据基本信息
- print(df.info())
- # 查看前几行数据
- print(df.head())
- # 检查缺失值
- print(df.isnull().sum())
- # 处理缺失值
- # 数值列用均值填充
- numeric_cols = df.select_dtypes(include=[np.number]).columns
- for col in numeric_cols:
- df[col].fillna(df[col].mean(), inplace=True)
- # 分类列用众数填充
- categorical_cols = df.select_dtypes(include=['object']).columns
- for col in categorical_cols:
- df[col].fillna(df[col].mode()[0], inplace=True)
- # 转换日期格式
- df['Order Date'] = pd.to_datetime(df['Order Date'], format='%m/%d/%Y')
- df['Ship Date'] = pd.to_datetime(df['Ship Date'], format='%m/%d/%Y')
- # 提取日期特征
- df['Order Year'] = df['Order Date'].dt.year
- df['Order Month'] = df['Order Date'].dt.month
- df['Order Day'] = df['Order Date'].dt.day
- df['Order Weekday'] = df['Order Date'].dt.dayofweek
- # 计算订单处理时间
- df['Processing Days'] = (df['Ship Date'] - df['Order Date']).dt.days
- # 标准化数值列
- from sklearn.preprocessing import StandardScaler
- scaler = StandardScaler()
- numeric_cols = df.select_dtypes(include=[np.number]).columns
- df[numeric_cols] = scaler.fit_transform(df[numeric_cols])
- # 编码分类变量
- df = pd.get_dummies(df, columns=['Region', 'Category'])
- # 保存处理后的数据
- df.to_csv('processed_sales_data.csv', index=False)
复制代码
9.2 案例二:多源数据整合
假设我们需要从多个数据源整合数据:
- import pandas as pd
- import sqlite3
- import os
- # 1. 从CSV文件读取客户数据
- customers = pd.read_csv('customers.csv')
- # 2. 从Excel文件读取产品数据
- products = pd.read_excel('products.xlsx', sheet_name='Products')
- # 3. 从数据库读取订单数据
- conn = sqlite3.connect('sales.db')
- orders = pd.read_sql('SELECT * FROM Orders', conn)
- conn.close()
- # 4. 从JSON文件读取员工数据
- employees = pd.read_json('employees.json')
- # 5. 数据清洗和转换
- # 处理客户数据
- customers['Join Date'] = pd.to_datetime(customers['Join Date'])
- customers['Customer ID'] = customers['Customer ID'].astype(str)
- # 处理产品数据
- products['Price'] = products['Price'].str.replace('$', '').astype(float)
- products['Launch Date'] = pd.to_datetime(products['Launch Date'])
- # 处理订单数据
- orders['Order Date'] = pd.to_datetime(orders['Order Date'])
- orders['Order ID'] = orders['Order ID'].astype(str)
- # 处理员工数据
- employees['Hire Date'] = pd.to_datetime(employees['Hire Date'])
- employees['Employee ID'] = employees['Employee ID'].astype(str)
- # 6. 数据整合
- # 合并订单和客户数据
- order_customer = pd.merge(orders, customers, on='Customer ID', how='left')
- # 合并产品数据
- order_product = pd.merge(order_customer, products, on='Product ID', how='left')
- # 添加销售代表信息
- order_employee = pd.merge(order_product, employees, left_on='Sales Rep ID', right_on='Employee ID', how='left')
- # 7. 创建新特征
- # 计算订单总金额
- order_employee['Total Amount'] = order_employee['Quantity'] * order_employee['Price']
- # 计算客户年龄
- order_employee['Customer Age'] = (pd.Timestamp.now() - order_employee['Join Date']).dt.days / 365
- # 计算产品上市天数
- order_employee['Product Age'] = (order_employee['Order Date'] - order_employee['Launch Date']).dt.days
- # 8. 数据聚合
- # 按客户聚合
- customer_summary = order_employee.groupby('Customer ID').agg({
- 'Order ID': 'count',
- 'Total Amount': 'sum',
- 'Quantity': 'sum'
- }).rename(columns={
- 'Order ID': 'Number of Orders',
- 'Total Amount': 'Total Spent',
- 'Quantity': 'Total Items'
- }).reset_index()
- # 按产品聚合
- product_summary = order_employee.groupby('Product ID').agg({
- 'Order ID': 'count',
- 'Quantity': 'sum',
- 'Total Amount': 'sum'
- }).rename(columns={
- 'Order ID': 'Number of Orders',
- 'Quantity': 'Total Sold',
- 'Total Amount': 'Total Revenue'
- }).reset_index()
- # 按销售代表聚合
- employee_summary = order_employee.groupby('Employee ID').agg({
- 'Order ID': 'count',
- 'Total Amount': 'sum',
- 'Customer ID': 'nunique'
- }).rename(columns={
- 'Order ID': 'Number of Orders',
- 'Total Amount': 'Total Sales',
- 'Customer ID': 'Number of Customers'
- }).reset_index()
- # 9. 保存整合后的数据
- # 创建数据库连接
- conn = sqlite3.connect('integrated_sales.db')
- # 保存整合后的订单数据
- order_employee.to_sql('Integrated_Orders', conn, if_exists='replace', index=False)
- # 保存汇总数据
- customer_summary.to_sql('Customer_Summary', conn, if_exists='replace', index=False)
- product_summary.to_sql('Product_Summary', conn, if_exists='replace', index=False)
- employee_summary.to_sql('Employee_Summary', conn, if_exists='replace', index=False)
- # 关闭连接
- conn.close()
- # 10. 保存为其他格式
- # 保存为Parquet格式
- order_employee.to_parquet('integrated_orders.parquet')
- customer_summary.to_parquet('customer_summary.parquet')
- product_summary.to_parquet('product_summary.parquet')
- employee_summary.to_parquet('employee_summary.parquet')
- # 保存为Excel文件,多个工作表
- with pd.ExcelWriter('integrated_sales_data.xlsx') as writer:
- order_employee.to_excel(writer, sheet_name='Orders', index=False)
- customer_summary.to_excel(writer, sheet_name='Customer Summary', index=False)
- product_summary.to_excel(writer, sheet_name='Product Summary', index=False)
- employee_summary.to_excel(writer, sheet_name='Employee Summary', index=False)
复制代码
9.3 案例三:大数据处理
假设我们有一个非常大的数据集,需要高效处理:
- import pandas as pd
- import numpy as np
- import os
- import multiprocessing
- from functools import partial
- import time
- # 1. 分块读取大型数据集
- def process_large_file(file_path, chunk_size=100000):
- """
- 分块处理大型CSV文件
- """
- # 创建读取器
- reader = pd.read_csv(file_path, chunksize=chunk_size)
-
- # 创建输出目录
- output_dir = 'processed_chunks'
- if not os.path.exists(output_dir):
- os.makedirs(output_dir)
-
- # 处理每个块
- for i, chunk in enumerate(reader):
- # 处理数据
- processed_chunk = process_chunk(chunk)
-
- # 保存处理后的块
- output_file = os.path.join(output_dir, f'chunk_{i}.parquet')
- processed_chunk.to_parquet(output_file)
-
- print(f"处理并保存了块 {i}")
-
- return output_dir
- def process_chunk(chunk):
- """
- 处理单个数据块
- """
- # 转换日期格式
- chunk['Date'] = pd.to_datetime(chunk['Date'])
-
- # 提取日期特征
- chunk['Year'] = chunk['Date'].dt.year
- chunk['Month'] = chunk['Date'].dt.month
- chunk['Day'] = chunk['Date'].dt.day
- chunk['Weekday'] = chunk['Date'].dt.dayofweek
-
- # 计算新特征
- chunk['Value_per_Unit'] = chunk['Value'] / chunk['Units']
-
- # 编码分类变量
- chunk = pd.get_dummies(chunk, columns=['Category'], prefix='Cat')
-
- return chunk
- # 2. 并行处理多个文件
- def process_multiple_files(file_paths, num_processes=None):
- """
- 并行处理多个文件
- """
- if num_processes is None:
- num_processes = multiprocessing.cpu_count()
-
- # 创建进程池
- pool = multiprocessing.Pool(num_processes)
-
- # 处理文件
- results = pool.map(process_single_file, file_paths)
-
- # 关闭进程池
- pool.close()
- pool.join()
-
- return results
- def process_single_file(file_path):
- """
- 处理单个文件
- """
- # 读取文件
- df = pd.read_csv(file_path)
-
- # 处理数据
- df = process_chunk(df)
-
- # 保存处理后的文件
- output_path = file_path.replace('.csv', '_processed.parquet')
- df.to_parquet(output_path)
-
- return output_path
- # 3. 合并多个处理后的文件
- def merge_processed_files(file_paths, output_path):
- """
- 合并多个处理后的文件
- """
- # 初始化一个空的DataFrame
- merged_df = pd.DataFrame()
-
- # 读取并合并每个文件
- for file_path in file_paths:
- df = pd.read_parquet(file_path)
- merged_df = pd.concat([merged_df, df], ignore_index=True)
-
- # 保存合并后的文件
- merged_df.to_parquet(output_path)
-
- return merged_df
- # 4. 使用Dask处理超大型数据集
- def process_with_dask(file_path, output_path):
- """
- 使用Dask处理超大型数据集
- """
- import dask.dataframe as dd
-
- # 创建Dask DataFrame
- ddf = dd.read_csv(file_path)
-
- # 转换日期格式
- ddf['Date'] = dd.to_datetime(ddf['Date'])
-
- # 提取日期特征
- ddf['Year'] = ddf['Date'].dt.year
- ddf['Month'] = ddf['Date'].dt.month
- ddf['Day'] = ddf['Date'].dt.day
- ddf['Weekday'] = ddf['Date'].dt.dayofweek
-
- # 计算新特征
- ddf['Value_per_Unit'] = ddf['Value'] / ddf['Units']
-
- # 编码分类变量
- ddf = dd.get_dummies(ddf, columns=['Category'], prefix='Cat')
-
- # 计算聚合结果
- result = ddf.groupby(['Year', 'Month']).agg({
- 'Value': 'sum',
- 'Units': 'sum',
- 'Value_per_Unit': 'mean'
- }).compute()
-
- # 保存结果
- result.to_parquet(output_path)
-
- return result
- # 5. 主函数
- def main():
- # 示例:处理大型CSV文件
- start_time = time.time()
- processed_dir = process_large_file('very_large_data.csv', chunk_size=500000)
- end_time = time.time()
- print(f"分块处理完成,耗时: {end_time - start_time:.2f}秒")
-
- # 示例:并行处理多个文件
- file_paths = ['data1.csv', 'data2.csv', 'data3.csv', 'data4.csv']
- start_time = time.time()
- processed_files = process_multiple_files(file_paths)
- end_time = time.time()
- print(f"并行处理完成,耗时: {end_time - start_time:.2f}秒")
-
- # 示例:合并处理后的文件
- start_time = time.time()
- merged_df = merge_processed_files(processed_files, 'merged_data.parquet')
- end_time = time.time()
- print(f"合并文件完成,耗时: {end_time - start_time:.2f}秒")
-
- # 示例:使用Dask处理超大型数据集
- start_time = time.time()
- result = process_with_dask('huge_data.csv', 'aggregated_result.parquet')
- end_time = time.time()
- print(f"Dask处理完成,耗时: {end_time - start_time:.2f}秒")
- print(result.head())
- if __name__ == "__main__":
- main()
复制代码
10. 总结与展望
10.1 回顾关键点
本文详细介绍了Pandas数据读取和存储的各种技术,从基础的CSV、Excel、JSON文件处理,到高级的大数据处理和性能优化。我们学习了:
1. 基础数据读取:如何使用Pandas读取CSV、Excel、JSON、HTML和SQL数据库中的数据。
2. 基础数据存储:如何将DataFrame保存为各种格式,包括CSV、Excel、JSON和SQL数据库。
3. 高级数据读取:处理大型数据集、指定数据类型、处理缺失值和日期时间解析。
4. 高级数据存储:使用压缩选项、分区存储、增量存储和性能优化。
5. 特殊数据格式处理:XML、HDF5、Parquet、Feather和剪贴板数据的处理。
6. 性能优化:内存优化、并行处理、缓存策略和最佳实践。
7. 实战案例:数据清洗与转换、多源数据整合和大数据处理。
10.2 未来发展趋势
随着数据量的不断增长和处理需求的多样化,Pandas及相关数据处理技术也在不断发展:
1. 更高效的数据格式:Parquet、Feather等二进制格式将越来越受欢迎,因为它们提供了更好的性能和压缩率。
2. 与大数据技术的集成:Pandas与Spark、Dask等大数据处理框架的集成将更加紧密,使数据科学家能够在不同规模的数据上使用相同的API。
3. 云计算支持:随着云计算的普及,Pandas将更好地支持云存储和计算服务,如AWS S3、Google Cloud Storage和Azure Blob Storage。
4. 自动化数据处理:自动化数据清洗、转换和特征工程的工具将更加成熟,减少数据科学家在数据准备上的工作量。
5. 实时数据处理:虽然Pandas主要用于批处理,但与流处理系统的集成将使实时数据分析变得更加容易。
10.3 持续学习资源
要继续深入学习Pandas和数据处理,可以参考以下资源:
1. 官方文档:Pandas官方文档是最权威的学习资源。
2. 在线课程:Coursera、edX、Udemy等平台上有许多关于Pandas和数据处理的优质课程。
3. 书籍:《Python for Data Analysis》by Wes McKinney(Pandas的创始人)、《利用Python进行数据分析》等。
4. 社区:Stack Overflow、GitHub、Reddit等社区有大量关于Pandas的讨论和示例。
5. 博客和教程:Towards Data Science、Real Python、DataCamp等网站提供了大量Pandas教程和实战案例。
通过掌握Pandas的数据读取和存储技术,你将能够更高效地处理各种数据格式,应对数据分析中的各种挑战,提升工作效率。希望本文能够成为你在数据处理旅程中的有用指南。 |
|