前言
这是很多 Pandas 初学者在跑通 pd.read_csv() 之后面临的第一个灵魂拷问。文件读进来了,数据躺在 DataFrame 里了,但你发现它列名不规范、索引是乱的、需要新增一列计算、想筛选出符合条件的数据、按分组汇总结果------这些真正构成数据分析日常的操作,才是 Pandas 的核心战场。
Pandas基本数据操作
数据集
python
data = pd.read_csv("./stock_day.csv")
# 删除一些列,让数据更简单些,再去做后面的操作
data = data.drop(["ma5","ma10","ma20","v_ma5","v_ma10","v_ma20"], axis=1)
print(data.head(5))

索引操作
直接使用行列索引(先列后行)
获取'2018-02-13'这天的'close'的结果
python
print(data['close']['2018-02-13'])

结合loc或者iloc使用索引
获取从'2018-02-24':'2018-02-18','open'的结果
python
print(data.loc['2018-02-24':'2018-02-18', 'open'])

python
# 使用iloc可以通过索引的下标去获取
# 获取前3天数据,前5列的结果
print(data.iloc[:3, :5])

赋值操作
对DataFrame当中的close列进行重新赋值为2
python
# 直接修改原来的值
data['close'] = 1
# 或者
data.close = 1

排序操作
排序有两种形式,一种对于索引进行排序,一种对于内容进行排序
DataFrame排序
- 使用data.sort_values(by=, ascending=)
- 单个键或者多个键进行排序,
- 参数:
- by:指定排序参考的键
- ascending:默认升序
- ascending=False:降序
- ascending=True:升序
python
# 按照开盘价大小进行排序 , 使用ascending指定按照大小排序
print(data.sort_values(by='open',ascending=True).head())

python
# 按照多个键进行排序
print(data.sort_values(by=['open', 'high']).head())

使用data.sort_index给索引进行排序
python
# 对索引进行排序
print(data.sort_index().head())

Series排序
使用series.sort_values(ascending=True)进行排序
series排序时,只有一列,不需要参数
python
data['p_change'].sort_values(ascending=True).head()

DataFrame运算
算法运算
add(other)
比如进行数学运算加上具体的一个数字
python
data['open'].add(2)

sub(other)
比如进行数学运算减去具体的一个数字
python
data['open'].sub(3)

逻辑运算符
逻辑运算符号
例如筛选data"open" > 20的日期数据
data"open" > 20返回逻辑结果
python
data['open'] > 20

python
# 逻辑判断的结果可以作为筛选的依据
data[data["open"] > 20].head()

完成多个逻辑判断
python
data[(data["open"] > 23) & (data["open"] < 24)].head()

逻辑运算函数
- query(expr)
- expr:查询字符串
通过query使得刚才的过程更加方便简单
python
data.query("open<22 & open>21").head()

isin(values)
例如判断'open'是否为24和25
python
# 可以指定值进行一个判断,从而进行筛选操作
data[data["open"].isin([23, 24])]

统计运算
describe
综合分析: 能够直接得出很多统计结果,count, mean, std, min, max 等
python
data.describe()

统计函数
min(最小值), max(最大值), mean(平均值), median(中位数), var(方差), std(标准差),mode(众数)

对于单个函数去进行统计的时候,坐标轴还是按照默认列"columns" (axis=0, default),如果要对行"index" 需要指定(axis=1)
max()、min()
python
# 使用统计函数:0 代表列求结果, 1 代表行求统计结果
data.max(0)

std()、var()
python
data.var(0)

median():中位数
中位数为将数据从小到大排列,在最中间的那个数为中位数。如果没有中间数,取中间两个数的平均值。
python
scores_df = pd.DataFrame({'Test1': [4, 7, 8, 9, 8, 5], 'Test2': [5, 2, 6, 3, 7, 4]})
print(scores_df.median())

idxmax()、idxmin()
python
data.idxmax(0)

累计统计函数

排序
python
# 排序之后,进行累计求和
data = data.sort_index()
对p_change进行求和
python
new_data = data.sort_index()
result = new_data['p_change'].cumsum()

如果要使用plot函数,需要导入matplotlib.
python
import matplotlib.pyplot as plt
new_data = data.sort_index()
result = new_data['p_change'].cumsum()
# plot显示图形
result.plot()
# 需要调用show,才能显示出结果
plt.show()

apply自定义运算
apply(func, axis=0)
- func:自定义函数
- axis=0:默认是列,axis=1为行进行运算
定义一个对列,最大值-最小值的函数
python
data[['open', 'close']].apply(lambda x: x.max() - x.min(), axis=0)

文件读取与存储
CSV
read_csv
- pandas.read_csv(filepath_or_buffer, sep =',', usecols )
- filepath_or_buffer:文件路径
- sep :分隔符,默认用","隔开
- usecols:指定读取的列名,列表形式
python
data = pd.read_csv("./stock_day.csv",usecols=['open', 'close'])

to_csv
- DataFrame.to_csv(path_or_buf=None, sep=', ', columns=None, header=True, index=True, mode='w', encoding=None)
- path_or_buf :文件路径
- sep :分隔符,默认用","隔开
- columns :选择需要的列索引
- header :boolean or list of string, default True
- index:是否写进行索引,是否写进列索引值
- mode:'w':重写, 'a' 追加
to_csv 是 Pandas 中最常用的数据导出方法,它的作用是把 DataFrame 保存成 CSV(逗号分隔值)文件。简单来说,它就是 read_csv 的逆操作------把内存里的表格数据"写"到硬盘上。
提取数据框(DataFrame)的前 10 行,并只将其中的 open(开盘价)这一列保存到本地的 CSV 文件中,然后再重新读取该文件以检查保存结果
python
# 选取10行数据保存,便于观察数据
data[:10].to_csv("./data/test.csv", columns=['open'])
# 读取,查看结果
pd.read_csv("./data/test.csv")

会发现将索引存入到文件当中,变成单独的一列数据。如果需要删除,可以指定index参数,删除原来的文件,重新保存一次。
python
# index:存储不会讲索引值变成一列数据
data[:10].to_csv("./test.csv", columns=['open'], index=False)

MySQL
以MySQL数据库为例,此时默认你已经在本地安装好了MySQL数据库。如果想利用pandas和MySQL数据库进行交互,需要先安装与数据库交互所需要的python包
python
pip install pymysql==1.0.2 -i https://pypi.tuna.tsinghua.edu.cn/simple/
# 如果后边的代码运行提示找不到sqlalchemy的包,和pymysql一样进行安装即可
pip install sqlalchemy==2.0.0 -i https://pypi.tuna.tsinghua.edu.cn/simple/

python
import pandas as pd
data = pd.read_csv('./csv示例文件.csv',sep=',',index_col=[0],encoding='gbk')
print(data)
'./csv示例文件.csv':文件路径。./ 表示当前 Python 脚本所在的目录。
sep=',':指定分隔符为英文逗号。虽然 CSV(Comma-Separated Values)默认就是逗号,但显式写出来可以增强代码可读性。如果你的文件是制表符分隔的(.tsv),这里需要改成 sep='\t'。
index_col=0:将第 0 列(即第一列)设置为行索引。这意味着文件中的第一列数据不会进入表格的"数据区",而是变成最左边的行标签。这里写成列表形式 0 是为了保持语法一致性------因为如果将来想用多列做复合索引(MultiIndex),可以写成 0, 1。
encoding='gbk':指定文件编码为 GBK。这是中文 Windows 系统下用记事本或 Excel 保存 CSV 时最常见的编码。如果不加这个参数,Pandas 默认用 utf-8 解码,碰到中文就会报 UnicodeDecodeError 或读出乱码。

创建数据库操作引擎对象并指定数据库
需要安装pymysql,部分版本需要额外安装sqlalchemy
python
# 导入sqlalchemy的数据库引擎
from sqlalchemy import create_engine
# 创建数据库引擎,传入uri规则的字符串
engine = create_engine('mysql+pymysql://root:1234@127.0.0.1:3306/test?charset=utf8')
'mysql+pymysql://...':数据库URL格式(RFC-1738风格)。
- mysql:数据库类型。
- pymysql:DBAPI驱动。
- root:用户名。
- 1234:密码(硬编码风险)。
- 127.0.0.1:主机(本地主机)。
- 3306:端口(默认MySQL)。
- test:数据库名称。
- ?charset=utf8:查询字符串参数(字符集)
将数据写入MySQL数据库
python
data.to_sql('test_pdtosql',engine,index=False,if_exists='append')
- .to_sql():Pandas 方法,将 DataFrame 写入 SQL 数据库。
- 'test_pdtosql':目标 SQL 表名。
- engine:SQLAlchemy 连接引擎(之前讨论过)。
- index=False:不写入 DataFrame 的索引(与 to_csv 行为相同)。
- if_exists='append':如果表存在,追加数据;如果表不存在,则创建它。
此时我们就可以在本地test库的test_pdtosql表中看到写入的数据

从数据库中加载数据
读取整张表, 返回dataFrame
python
# 指定表名,传入数据库连接引擎对象
data = pd.read_sql('test_pdtosql',engine)

使用SQL语句获取数据,返回dataframe
python
# 传入sql语句,传入数据库连接引擎对象
pd.read_sql('select name,AKA from test_pdtosql', engine)

JSON
read_json
pandas.read_json(path_or_buf=None, orient=None, typ='frame', lines=False)
-
将JSON格式准换成默认的Pandas DataFrame格式
-
orient : string,Indication of expected JSON string format.
-
'split' : dict like {index -> index, columns -> columns, data -> values}
- split 将索引总结到索引,列名到列名,数据到数据。将三部分都分开了
-
'records' : list like {column -\> value}, ... , {column -\> value}
- records 以
columns:values的形式输出
- records 以
-
'index' : dict like {index -> {column -> value}}
- index 以
index:{columns:values}...的形式输出
- index 以
-
'columns' : dict like {column -> {index -> value}}
,默认该格式
- colums 以
columns:{index:values}的形式输出
- colums 以
-
'values' : just the values array
- values 直接输出值
-
-
lines : boolean, default False
- 按照每行读取json对象
-
typ : default 'frame', 指定转换成的对象类型series或者dataframe
read_json案例
新闻标题讽刺数据集,格式为json。is_sarcastic:1讽刺的,否则为0;headline:新闻报道的标题;article_link:链接到原始新闻文章。存储格式为:
python
{"article_link": "https://www.huffingtonpost.com/entry/versace-black-code_us_5861fbefe4b0de3a08f600d5", "headline": "former versace store clerk sues over secret 'black code' for minority shoppers", "is_sarcastic": 0}
{"article_link": "https://www.huffingtonpost.com/entry/roseanne-revival-review_us_5ab3a497e4b054d118e04365", "headline": "the 'roseanne' revival catches up to our thorny political mood, for better and worse", "is_sarcastic": 0}
读取
orient指定存储的json格式,lines指定按照行去变成一个样本
python
data = pd.read_json('./train.json',orient='records',lines=True)
lines=True:告诉 Pandas,这个文件不是单个大的 JSON 对象,而是每行一个独立的 JSON 对象(JSON Lines 格式)。如果没有这个参数,Pandas 会尝试把整个文件当成一个 JSON 数组或字典来解析,遇到换行就会报错。
orient='records':指定文件中每一行的 JSON 对象的结构是"记录(record)"类型,即 {"列名1": 值1, "列名2": 值2, ...} 这种键值对形式。这个参数告诉 Pandas 如何把 JSON 对象映射到 DataFrame 的行和列。

to_json
DataFrame.to_json(path_or_buf=None,orient=None,lines=False)
- 将Pandas 对象存储为json格式
- path_or_buf=None:文件地址
- orient:存储的json形式,{'split','records','index','columns','values'}
- lines:一个对象存储为一行
存储文件
python
data.to_json('./test.json',orient='records')
python
[{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/versace-black-code_us_5861fbefe4b0de3a08f600d5","headline":"former versace store clerk sues over secret 'black code' for minority shoppers","is_sarcastic":0}, {"article_link":"https:\/\/www.huffingtonpost.com\/entry\/roseanne-revival-review_us_5ab3a497e4b054d118e04365","headline":"the 'roseanne' revival catches up to our thorny political mood, for better and worse","is_sarcastic":0},{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/versace-black-code_us_5861fbefe4b0de3a08f600d5","headline":"former versace store clerk sues over secret 'black code' for minority shoppers","is_sarcastic":0},{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/roseanne-revival-review_us_5ab3a497e4b054d118e04365","headline":"the 'roseanne' revival catches up to our thorny political mood, for better and worse","is_sarcastic":0},{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/versace-black-code_us_5861fbefe4b0de3a08f600d5","headline":"former versace store clerk sues over secret 'black code' for minority shoppers","is_sarcastic":0},{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/roseanne-revival-review_us_5ab3a497e4b054d118e04365","headline":"the 'roseanne' revival catches up to our thorny political mood, for better and worse","is_sarcastic":0},{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/versace-black-code_us_5861fbefe4b0de3a08f600d5","headline":"former versace store clerk sues over secret 'black code' for minority shoppers","is_sarcastic":0},{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/roseanne-revival-review_us_5ab3a497e4b054d118e04365","headline":"the 'roseanne' revival catches up to our thorny political mood, for better and worse","is_sarcastic":0},{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/versace-black-code_us_5861fbefe4b0de3a08f600d5","headline":"former versace store clerk sues over secret 'black code' for minority shoppers","is_sarcastic":0},{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/roseanne-revival-review_us_5ab3a497e4b054d118e04365","headline":"the 'roseanne' revival catches up to our thorny political mood, for better and worse","is_sarcastic":0},{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/versace-black-code_us_5861fbefe4b0de3a08f600d5","headline":"former versace store clerk sues over secret 'black code' for minority shoppers","is_sarcastic":0},{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/roseanne-revival-review_us_5ab3a497e4b054d118e04365","headline":"the 'roseanne' revival catches up to our thorny political mood, for better and worse","is_sarcastic":0}]
修改lines参数为True
python
data.to_json('./test.json',orient='records',lines=True)

总结
希望本文能成为你数据处理工具箱里最趁手的那把锤子。遇到任何具体的数据读写或运算问题,欢迎随时回来翻查这张"参数地图"。