Pandas 数据处理三板斧:基本操作、运算与文件读写

前言

这是很多 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的形式输出
    • 'index' : dict like {index -> {column -> value}}

      • index 以index:{columns:values}...的形式输出
    • 'columns' : dict like {column -> {index -> value}}

      ,默认该格式

      • colums 以columns:{index:values}的形式输出
    • '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)

总结

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