金融量化学习---Python, MySQL, Pandas

这里用来记录一些在金融领域,尤其是银行相关的资金、债券、票据中应用到的数据管理与分析, 编程等心得或笔记,以及个人的一点小小兴趣(易经八卦、藏密禅修)等

导航

pandas - dataframe 常用操作大全

目录

pandas文件 IO

读取excel

pd.read_excel

read_excel方法的常用参数详解

read_excel(
io, sheet_name=0, header=0, names=None, index_col=None, usecols=None, squeeze=False, dtype=None, engine=None,
converters=None, true_values=None, false_values=None, skiprows=None, nrows=None, na_values=None,
keep_default_na=True, verbose=False, parse_dates=False, date_parser=None, thousands=None,
comment=None, skip_footer=0, skipfooter=0, convert_float=True, mangle_dupe_cols=True, **kwds
)

pandas.read_excel(io,sheet_name = 0,header = 0,names = None,index_col = None,usecols = None,squeeze = False,dtype = None, ...)
dtype = {'a': np.float64, 'b': np.int32, 'Name': str, 'Value': float}

io
值为str类型,文件路径,必须传

sheet_name
值为str或int类型
int类型时,默认值0,表示Sheet1表,依次分别向后表示,不存在该sheet表时抛出IndexError错误: list index out of range
str类型时,必须输入sheet表的全名,不存在该sheet表时抛出xlrd.biffh.XLRDError错误: No sheet named <'x'>

header
值为int类型或list类型
默认值0,表示从第一行开始读,输入值大于列的长度时会抛出ValueError错误: Passed header=7 but only 6 lines in file
list内的值也必须在列的长度范围内,如[2, 7],超出会抛出IndexError错误: list index out of range

header=[1, 3]中的1表示按行索引读取第几行,3表示按行索引从第几行开始往后读取。
当输入的最后一个值为最后一行时,如:header=[2, 4],显示方式为:

        Empty DataFrame
        Columns: [(2, 4), (bob, peter), (19, 18), (man, man)]
        Index: []

当一列中含有空行时,header用list时不能包含空行

names
值为list或者str,默认None,一般使用list传参

指定表头的名称,list内的值跟表的列数要一一对应,即不能多也不能少,多或者少都会抛出ValueError错误: Number of passed names did not match number of header fields in the file
使用str类型传参时会循环出每一个字符在赋值给每一个表头,即不能多也不能少,多或者少都会抛出ValueError错误。
举栗子:

        pd.read_excel(f_path, sheet_name=0, header=1, names='asdf')
               a      s   d      f
            0  2    bob  19    man
            1  3  alice  21  woman
            2  4  peter  18    man
        字符重复时,会自动在后面追加数字,从1开始,如:names='aaaa'
               a    a.1  a.2    a.3
            0  2    bob   19    man
            1  3  alice   21  woman
            2  4  peter   18    man

index_col
值为int或str类型,默认None,指定第几列做为新的索引列
int时,按索引传参,超出列的长度后会抛出IndexError错误: list index out of range
str时,按第一行的列名传入,不存在该列名时抛出ValueError错误: Index age invalid

usecols
值为None、int、str、list类型,指定读取表格的指定列
None时,读取整个excel列
int时,读取从第一列开始到该数值(包含)结束的中间所有列
str时,只能按照excel的格式指定列,如"A: G",读取A列到G列的所有列, 本公式中用("A: G")而非 ["A: G"]
list时,list的元素只能是int型,如:[1, 4],表示读取list内指定的第一和第四列

skiprows
值为int类型,默认None,跳过指定行(包括)之前的行开始读取

传入的值从1开始的任意int类型,超出行的长度不报错,显示为空,如下:

            Empty DataFrame
            Columns: []
            Index: []
只剩最后一条数据时,显示如下:
            Empty DataFrame
            Columns: [4, peter, 18, man]
            Index: []

nrows
值为int类型,默认None,只取前n行数据,按索引传参

传入值为0时,只取第一行,显示如下:

            Empty DataFrame
            Columns: [1, jack, 22, man]
            Index: []

传入其余值时,只显示该值(包括)之前的行,超出行的长度后不报错,有多少行显示多少行

converters
值为dict类型,默认None,将指定的数据列转换为int、float、str等数据类型

            num name    age     gender
            001 jack    22      man
            002 bob     19      man
            003 alice   21      woman
            004 peter   18      man
如上:是Excel中的原本数据形式,但是当我们读取出来可能就不是这个样子了,num以0开头的都不显示,如下:
               num   name  age gender
            0    1   jack   22    man
            1    2    bob   19    man
            2    3  alice   21  woman
            3    4  peter   18    man
那这个时候就需要指定converters参数,将num列指定为str类型就可以了!可多个同时设置,如:converters={'num': str, 'age': str}

pandas读取excel文件时指定列的格式

import pandas as pd
list =pd.read_excel(file_name, dtype={'交易编号':str,'交易日期':'datetime64'},header =2)
pandas读取excel文件的所有sheetname
import pandas as pd
list =pd.read_excel(file_name,sheet_name =None).keys()  #直接读取文件即可,不指定sheet_name,然后使用keys()获得 dict形式的 sheetname
注意:sheet_name =None 一定要加上

读取excel文件sheetname的另一种方法

f = pd.ExcelFile(file_name)
f.sheet_names  # 获取工作表名称

输出excel

DataFrame导入MySQL数据库:df.to_sql()

DataFrame.to_sql (name,con,schema = None,if_exists ='fail',index = True,index_label = None,chunksize = None,dtype = None )
将存储在DataFrame中的记录写入SQL数据库。支持SQLAlchemy [R16]支持的数据库。可以新创建,附加或覆盖表。
参数
name:string SQL表的名称。
con:sqlalchemy.engine.Engine或sqlite3.Connection 使用SQLAlchemy可以使用该库支持的任何数据库。为sqlite3.Connection对象提供了旧版支持。
schema:string,optional指定架构(如果数据库支持)。如果为None,请使用默认架构。
if_exists:{'fail','replace','append'},默认'fail'如果表已存在的情况如下,fail:引发ValueError。
replace:在插入新值之前删除表。
append:将新值插入现有表。
index:布尔值,默认为True 将DataFrame索引写为列。使用index_label作为表中的列名。
index_label:字符串或序列,默认为None 索引列的列标签。如果给出None(默认)且 index为True,则使用索引名称。如果DataFrame使用MultiIndex,则应该给出一个sequence。
chunksize:int,可选. 行将一次批量写入的数量。默认情况下,所有行都将立即写入。
dtype:dict,可选. 指定列的数据类型。键应该是列名,值应该是SQLAlchemy类型,或sqlite3传统模式的字符串。
异常: ValueError异常 当表已经存在且if_exists为'fail'时(默认值)。

from sqlalchemy import create_engine
engine = create_engine("mysql+mysqldb://{}:{}@{}/{}".format('username', 'password', 'host:port', 'database'))
con = engine.connect()

df.to_sql(name='test', con=con, if_exists='append', index=False)

解决导入MySQL数据库时,数据类型改变的异常:

思路:通过建立一个字典,实现df和sql的对应

import sqlalchemy
from sqlalchemy.types import NVARCHAR,Float,Integer

dtype_dict = {'datefld': sqlalchemy.DateTime(), 
                   'intfld':  sqlalchemy.types.INTEGER(),
                   'strfld': sqlalchemy.types.VARCHAR(length=255),
                   'floatfld': sqlalchemy.types.Float(precision=3, asdecimal=True),
                   'booleanfld': sqlalchemy.types.Boolean
            }

data.to_sql(name='some_table', con=engine, if_exists='append', index=False, dtype = dtype_dict)

高级办法-自动识别并生成对应字典(推荐)

import sqlalchemy
from sqlalchemy.types import NVARCHAR,Float,Integer

#可以通过dir(sqlalchemy.types)查看它所包含的所有数据类型
def mapping_df_types(df):
    dtypedict = {}
    for i, j in zip(df.columns, df.dtypes):
        if "object" in str(j):
            dtypedict.update({i: NVARCHAR(length=255)})
        if "float" in str(j):
            dtypedict.update({i: Float(precision=2, asdecimal=True)})
        if "int" in str(j):
            dtypedict.update({i: Integer()})
    return dtypedict

mapping_df_types(data_list_new)
#输出: 
{'id': NVARCHAR(length=255),
 'branch': NVARCHAR(length=255),
 'trade_type': NVARCHAR(length=255),
 'counterparty': NVARCHAR(length=255),
 'currency': NVARCHAR(length=255),
 'amount': Integer(),
 'rate': Float(precision=2, asdecimal=True),
 'date_value': NVARCHAR(length=255),
 'date_maturity': NVARCHAR(length=255),
 'tenor': Integer(),
 'interests': Float(precision=2, asdecimal=True),
 'amount_total': Float(precision=2, asdecimal=True),
 'mature': NVARCHAR(length=255)}


**dtype Description**
bool_   Boolean (True or False) stored as a byte
int_    Default integer type (same as C long; normally either int64 or int32)
intc    Identical to C int (normally int32 or int64)
intp    Integer used for indexing (same as C ssize_t; normally either int32 or int64)
int8    Byte (-128 to 127)
int16   Integer (-32768 to 32767)
int32   Integer (-2147483648 to 2147483647)
int64   Integer (-9223372036854775808 to 9223372036854775807)
uint8   Unsigned integer (0 to 255)
uint16  Unsigned integer (0 to 65535)
uint32  Unsigned integer (0 to 4294967295)
uint64  Unsigned integer (0 to 18446744073709551615)
float_  Shorthand for float64.
float16 Half precision float: sign bit, 5 bits exponent, 10 bits mantissa
float32 Single precision float: sign bit, 8 bits exponent, 23 bits mantissa
float64 Double precision float: sign bit, 11 bits exponent, 52 bits mantissa
complex_    Shorthand for complex128.
complex64   Complex number, represented by two 32-bit floats (real and imaginary components)
complex128  Complex number, represented by two 64-bit floats (real and imaginary components)

输出excel

to_excel()

to_excel(self, excel_writer, sheet_name='Sheet1', na_rep='', float_format=None,columns=None, header=True, index=True, index_label=None,startrow=0, startcol=0, engine=None, merge_cells=True, encoding=None,
inf_rep='inf', verbose=True, freeze_panes=None)
常用参数解析

- excel_writer : string or ExcelWriter object File path or existing ExcelWriter目标路径
- sheet_name : string, default ‘Sheet1’ Name of sheet which will contain DataFrame,填充excel的第几页
- na_rep : string, default ”,Missing data representation 缺失值填充
- float_format : string, default None Format string for floating point numbers
- columns : sequence, optional,Columns to write 选择输出的的列。
- header : boolean or list of string, default True Write out column names. If a list of string is given it is assumed to be aliases for the column names
- index : boolean, default True,Write row names (index)
- index_label : string or sequence, default None, Column label for index column(s) if desired. If None is given, andheader and index are True, then the index names are used. A sequence should be given if the DataFrame uses MultiIndex.
- startrow :upper left cell row to dump data frame
- startcol :upper left cell column to dump data frame
- engine : string, default None ,write engine to use - you can also set this via the options,io.excel.xlsx.writer, io.excel.xls.writer, andio.excel.xlsm.writer.
- merge_cells : boolean, default True Write MultiIndex and Hierarchical Rows as merged cells.
- encoding: string, default None encoding of the resulting excel file. Only necessary for xlwt,other writers support unicode natively.
- inf_rep : string, default ‘inf’ Representation for infinity (there is no native representation for infinity in Excel)
- freeze_panes : tuple of integer (length 2), default None Specifies the one-based bottommost row and rightmost column that is to be frozen

DataFrame.to_excel(excel_writer, sheet_name='Sheet1', na_rep='', float_format=None, columns=None, header=True, index=True,
index_label=None, startrow=0, startcol=0, engine=None, merge_cells=True, encoding=None, inf_rep='inf', verbose=True, freeze_panes=None)

常用参数解析 :
excel_writer : 字符串或ExcelWriter 对象,文件路径或现有的ExcelWriter
sheet_name :字符串,默认“Sheet1”,将包含DataFrame的表的名称。
na_rep : 字符串,默认‘ ’,缺失数据表示方式
float_format : 字符串,默认None,格式化浮点数的字符串
columns : 序列,可选,要编写的列
header : 布尔或字符串列表,默认为Ture。写出列名。如果给定字符串列表,则假定它是列名称的别名。
index :布尔,默认的Ture,写行名(索引)
index_label : 字符串或序列,默认为None。如果需要,可以使用索引列的列标签。如果没有给出,标题和索引为true,则使用索引名称。如果数据文件使用多索引,则需使用序列。
startrow :左上角的单元格行来转储数据框
startcol :左上角的单元格列转储数据帧
engine : 字符串,默认没有使用写引擎 - 您也可以通过选项io.excel.xlsx.writer,io.excel.xls.writer和io.excel.xlsm.writer进行设置。
merge_cells : 布尔,默认为Ture编码生成的excel文件。 只有xlwt需要,其他编写者本地支持unicode。
inf_rep : 字符串,默认“正”无穷大的表示(在Excel中不存在无穷大的本地表示)
freeze_panes : 整数的元组(长度2),默认为None。指定要冻结的基于1的最底部行和最右边的列

多个DataFrame写入到Excel的不同的sheet

writer=pd.ExcelWriter("C:/Users/wlt/Desktop/XXX.xls")

mon1.to_excel(excel_writer=writer,sheet_name='201901')
mon2.to_excel(excel_writer=writer,sheet_name='201902')
mon3.to_excel(excel_writer=writer,sheet_name='201903')
mon4.to_excel(excel_writer=writer,sheet_name='201904')
mon5.to_excel(excel_writer=writer,sheet_name='201905')

writer.save()
writer.close()

多个DataFrame写入到Excel的同一个sheet

https://blog.csdn.net/midion9/article/details/89000131

读写csv

read_csv函数会读取逗号分隔文件,可以把set参数设置为 \t, 指明使用制表符分隔

df = pd.read_csv('../data/filename.csv', sep ='\t')

#写入csv文件时,不写入行名(用index参数控制)
df.to_csv('../data/filename.csv',index = False)

to_pickle 方法(二进制格式保存)

调用 to_pickle方法,将以二进制格式保存数据,文本编辑器打开时,只会看到乱码
pickle文件扩展名可以是: .p , .pkl, .pickle

#保存到 pickle文件
df.to_pickle('../data/filename.pickle')

#从 pickle文件提取
df = pd.read_pickle('../data/filename.pickle')

创建 DataFrame

创建 Series

Series有两列,一列是索引,一列是值

s1 = pd.Series(['AAA','BBB'],index=['id','name'])
Out: 
id      AAA
name    BBB
dtype: object

s1.index
Out[1]: Index(['id', 'name'], dtype='object')

s1.values
Out[2]: array(['AAA', 'BBB'], dtype=object)

s1.keys()  #keys是Series对象的一个方法,它是index属性的别名
Out[3]: Index(['id', 'name'], dtype='object')

Series的属性和方法

Series的属性:loc, iloc, ix, dtype, dtypes, T, shape, size, values
Series的方法:append, corr, cov, describe, drop_duplicates, equals ,get_values, hist, min, max, mean, median, mode, quantile, replace, sample, sort_values, to_frame, transpose, unique

使用Series对象字典DataFrame

df = pd.DataFrame({'col1':['data1',1],'col2':['data2',2],'col3':['data3',3]},index=['id','name'])
Out: 
       col1   col2   col3
id    data1  data2  data3
name      1      2      3

Series的布尔子集

df.ages > df.ages.mean()   #提取 ages列中大于该列平均值的列,返回 bool

创建空 DataFrame

# 创建一个空的 DataFrame
df = pd.DataFrame(columns=['A', 'B', 'C', 'D'])

#以list为基础,创建 DataFrame
df = pd.DataFrame({'col_name':list})

pandas 索引操作

1. set_index() 直接把某列设为index

把没有index的 df 的某列设为index

df.set_index('col_name')

2. reset_index() 把某列设为index替代旧的index

在获得新的index,原来的index变成数据列,保留下来。
不想保留原来的index,使用参数 drop=True,默认 False。

df.reset_index(drop=True)

按索引操作dataframe

#先根据组合条件得到待删除行的index,保存为list, 再删除
delete_index = data_list[(data_list.机构 == 'NA') | (data_list.起息日<= date_end)].index.tolist()   #取得符合条件的行索引
data_list_new = data_list.drop(delete_index)

索引操作--改、查、高级索引

本段摘自:
版权声明:本文为CSDN博主「立Sir」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/dgvv4/article/details/121386642

首先,我们先定义两个变量ps1存放Series数据,pd1存放DataFrame数据,以便后续操作。

import pandas as pd
import numpy as np
ps1 = pd.Series(range(5),index=['a','b','c','d','e'])
pd1 = pd.DataFrame(np.arange(1,10).reshape(3,3),index=['a','b','c'],columns=['A','B','C'])

1. 索引操作 -- 改

1.1 对 Series 修改

利用标签索引修改: Series名[ 标签名 ] = 值
利用位置索引修改: Series名[ 位置数 ] = 值

# series修改
ps1['a'] = 999  #标签索引
ps1[1] = 888  #位置索引

将标签名'a'对应的值改成999,将位置索引1对应的值改为888。标签索引'a'对应的位置索引是0

1.2 对 DataFrame 修改

(1)利用标签索引修改一列数据: 变量名[ 列标签名 ] = 值/列表

#(1)利用索引修改一列的数据
pd1["A"] = 100
pd1["B"] = [9,99,999]
pd1["F"] = [8,8,8]    #索引名不存在,增加一列

(2)利用对象修改一列数据: 变量名.列标签名 = 值/列表

#(2)利用对象修改一列的数据  变量名.索引 = [数据]
pd1.A = 0
pd1.C = [1,11,111]

(3)利用高级索引修改一行数据: 变量名.loc[ 行标签名 ] = 值/列表
(4)利用高级索引修改某一个数据:变量名.loc[ 行标签名, 列标签名 ] = 值

#(3)loc 标签索引 
# 修改一行
pd1.loc['a'] = 777  # a索引对应的一行都变成777
#(4)修改单个数据 某行某列
pd1.loc['a','A'] = 1000

2. 索引操作 -- 查

2.1 对 Series 操作

(1)利用标签索引、位置索引查某个值: Series名[ 标签名 / 位置索引 ]

a1 = ps1['a']  #标签索引查值
a2 = ps1[0]    #位置索引查值

(2)利用切片索引查一块值:
标签索引切片,顾头顾尾: Series名[ 标签名1 : 标签名2 ]
位置索引切片,顾头不顾尾: Series名[ 位置索引1 : 位置索引2 ]

# 切片索引
a3 = ps1['b':'d']  #标签切片,顾头顾尾
a4 = ps1[1:4]  #位置切片,顾头不顾尾

(3)利用不连续索引查多个值:
使用标签索引: 变量名[[ 标签名1 , 标签名2 ]]
使用位置索引: 变量名[[ 位置索引1 , 位置索引2 ]]

# 不连续索引
a5 = ps1[['b','e']]  #标签索引,两个中括号,代表取的是b这一行和e这一行,是不连续的
a6 = ps1[[0,2,3]]  #位置索引

(4) 利用布尔索引取满足条件的值: 变量名[ 条件 ]
满足条件则为True,输出满足条件的值,如下式条件ps1>2。ps1中的值有0、1、2、3、4。其中对于ps>1这个条件。0,1,2都是False;3,4是True。因此输出的是3、4。

# 布尔索引
a7 = ps1[ps1>2]  #取出ps1中所有大于2的值

2.2 对 DataFrame 操作

(1)利用标签索引查某一列: 变量名[ 标签名 ]
(2)利用标签索引查多列: 变量名[[ 标签名1 , 标签名2 ]]

# 只能用标签索引操作,不能用位置索引
a8 = pd1["A"]  #标签索引,输出一列,返回series类型
a9 = pd1[["A","C"]]  #不连续索引取多列

(3)利用标签索引取某一个值: 变量名[ 列索引名 ][ 行索引名 ]

# 选取一个值
a10 = pd1['A']['a']

(4)利用切片索引查连续几行数据:
位置索引切片,顾头不顾尾: 变量名[ 位置索引1 : 位置索引2 ]
标签索引切片,顾头顾尾: 变量名[ 标签名1 : 标签名2 ]

# 切片处理,获取的是行
a11 = pd1[:2]  # 顾头不顾尾,获取前两行
a12 = pd1['a':'c']  # 顾头顾尾

3. 高级索引

3.1 loc 标签索引 --- 基于标签名的索引

(1)对 series 操作
利用标签索引切片: Series名[ 标签名1 : 标签名2 ]
利用高级索引切片: Series名.loc[ 标签名1 : 标签名2 ]
两种写法得到的结果相同

# 切片操作
a12 = ps1['a':'c']
a13 = ps1.loc['a':'c']

(2)对 DataFrame 操作
利用高级索引进行切片操作:
获取第几行第几列的某个值: 变量名.loc[ 行索引名 , 列索引名 ]
获取连续几行中某一列的数据: 变量名.loc[ 行索引名1 : 行索引名2 , 列索引名 ]
获取指定的某几行某几列的一块区域的数据:
变量名.loc[ 行索引名1 : 行索引名2 , 列索引名1 : 列索引名2 ]

# frame名.loc[行索引,列索引]
a14 = pd1.loc['a','A']     #取出第a行第A列的数
a15 = pd1.loc['a':'b','A']   #取出'a'到'b'行中第'A'列的数据
a16 = pd1.loc['a':'b','A':'C']  #取出'a'到'b'行中第'A'到'C'列的数据

3.2 iloc 位置索引

(1)对 Series 操作
利用位置索引切片: Series名[ 位置索引1 : 位置索引2 ]
利用高级索引切片: Series名.iloc[ 位置索引1 : 位置索引2 ]
位置索引切片顾头不顾尾,两种切片方法结果相同

# 对series操作
a17 = ps1[1:3]  #位置切片,顾头不顾尾
a18 = ps1.iloc[1:3]

(2)对 DataFrame 操作
列用高级索引进行切片操作:
获取第几行第几列的某个值: 变量名.iloc[ 行位置索引 , 列位置索引 ]
获取连续几行中某一列的数据: 变量名.iloc[ 行位置1 : 行位置2 , 列位置 ]
获取指定的某几行某几列的一块区域的数据:
变量名.iloc[ 行位置1 : 行位置2 , 列位置1 : 列位置2 ]
位置索引顾头不顾尾

# frame名.iloc[行索引,列索引]   顾头不顾尾
a19 = pd1.iloc[0,2]   # 获取第0行第2列的值
a20 = pd1.iloc[0:2,2]   # 获取第0到1行中第2列的值
a21 = pd1.iloc[0:2,1:3]  # 获取第0到1行中第1到2行的一块数据

增删改查操作

新增

使用字典为dataframe添加一条行记录

import pandas as pd
data = pd.DataFrame()
a = {"x":1,"y":2}
data = data.append(a,ignore_index=True)  #注意:ignore_index必须带上,否则会有错误提示
print(data)
     x    y
0  1.0  2.0

为一个dataframe添加一条带索引值的行记录

import pandas as pd
data = pd.DataFrame()  #得到一个空df
series = pd.Series({"x":1,"y":2},name="a")  #使用字典添加一条记录,索引值为'a'
data = data.append(series)
print(data)

     x    y
a  1.0  2.0

指定索引位置添加行记录(可用于修改已有的记录)

import numpy as np

df = pd.DataFrame(np.random.randint(1, 10, (3, 3)), index=['one', 'one', 'two'], columns=['col1', 'col2', 'col3'])

df: 
     col1  col2  col3
one     9     4     4
one     1     7     2
two     1     6     8

new_data = pd.Series({'col1': 'new', 'col2': 'new', 'col3': 'new'})

new_data: 
col1    new
col2    new
col3    new
dtype: object

df.iloc[0] = new_data #把记录插入在第一行的位置

df: 
    col1 col2 col3
one  new  new  new
one    1    7    2
two    1    6    8

删除

import pandas as pd
import numpy as np
 
a=np.array([[1,2,3],[4,5,6],[7,8,9]])
df1=pd.DataFrame(a,index=['row0','row1','row2'],columns=list('ABC'))
print(df1)
Out[0]: 
      A  B  C
row0  1  2  3
row1  4  5  6
row2  7  8  9

df2=df1.copy()

删除/选取某列含有特定数值的行

#df1=df1[df1['A'].isin([1])]
#df1[df1['A'].isin([1])]  选取df1中A列包含数字1的行
 
df1=df1[~df1['A'].isin([1])]
#通过~取反,选取不包含数字1的行
print(df1)
Out[1]: 
      A  B  C
row1  4  5  6
row2  7  8  9

删除/选取某行含有特定数值的列

cols=[x for i,x in enumerate(df2.columns) if df2.iat[0,i]==3]
#利用enumerate对row0进行遍历,将含有数字3的列放入cols中
print(cols)
Out[2]: 
['C']

#df2=df2[cols]   选取含有特定数值的列
df2=df2.drop(cols,axis=1) #利用drop方法将含有特定数值的列删除
print(df2)
Out[3]: 
      A  B
row0  1  2
row1  4  5
row2  7  8

用pandas删除全0行

from pandas import DataFrame
import numpy as np
 
df1 = DataFrame(np.arange(16).reshape((4,4)),index=['a','b','c','d'],columns=['one','two','three','four'])  # 创建一个dataframe
df1.loc['e'] = 0    # 优雅地增加一行全0
print(df1)
df1.ix[(df1==0).all(axis=1), :]    # 找到它
df2 = df1.ix[~(df1==0).all(axis=1), :]   # 删了它
print("======+=========")
print(df2)
 
'''
   one  two  three  four
a    0    1      2     3
b    4    5      6     7
c    8    9     10    11
d   12   13     14    15
e    0    0      0     0
======+=========
   one  two  three  four
a    0    1      2     3
b    4    5      6     7
c    8    9     10    11
d   12   13     14    15
'''

用pandas删除全0列

from pandas import DataFrame
import numpy as np
 
df1 = DataFrame(np.arange(16).reshape((4,4)),index=['a','b','c','d'],columns=['one','two','three','four'])  # 创建一个dataframe
df1.loc[:,['four']] = 0    # 将一列全部设置为0
print(df1)
df1.ix[:, (df1==0).all(axis=0)]    # 找到它
df2 = df1.ix[:, ~(df1==0).all(axis=0)]   # 删了它
print("======+=========")
print(df2)
 
'''
   one  two  three  four
a    0    1      2     0
b    4    5      6     0
c    8    9     10     0
d   12   13     14     0
======+=========
   one  two  three
a    0    1      2
b    4    5      6
c    8    9     10
d   12   13     14
'''

修改

修改DataFrame里的某个值统一修改为另一个值

df.replace('None',np.nan)

批量修改一个dataframe里某列中的值

先建一个字典,如下:
branches_dic = {'工商银行有限公司广州分行':'广州分行','工商银行有限公司深圳分行':'深圳分行','工商银行有限公司汕头分行':'汕头分行','工商银行有限公司上海分行':'上海分行'}
#使用下面的语句将其一次性全部替换:
for i,j in branches_dic.items():
    df.loc[df.分行名称==i,'分行名称']=j  #在df的分行名称一列中查找i,并且将它替换为j

写入合并单元格数据

import openpyxl
from openpyxl.utils import get_column_letter

# 创建一个新的工作簿
wb = openpyxl.Workbook()

# 获取第一个工作表
sheet = wb.active
sheet.title = "Sheet1"

# 合并单元格并写入数据
# 合并 A1 到 C1 单元格并写入值
sheet.merge_cells('A1:C1')
sheet['A1'] = 'Merged Cell A1 to C1'

# 合并 A2 到 B3 单元格并写入值
sheet.merge_cells('A2:B3')
sheet['A2'] = 'Merged Cell A2 to B3'

# 保存工作簿
wb.save('output_test.xlsx')

查询

loc 和 iloc 获取行子集

语法:df.loc[[行],[列]] , df.iloc[[行],[列]]
loc是基于索引标签获取行子集(行名),iloc是基于行索引获取行子集(行号)

df.loc[[0,99,999]]   #选择第1行,100行和1000行
df.iloc[-1]  #获取最后一行数据,如果是loc,则会报错,要写成:df.loc[df.shape[0]-1]
df.loc[:,['col1','col2']]   #提取'col1','col2'列的所有行
df.iloc[:,:3]   #提取前三列
df.iloc[:,list(range(3,6))]   #使用list,提取第3列(含)至第5列(含)
df.iloc[:,0:6:2]  #提取 0:6之间,步长为2的列,即第 0,2,4列

head() 和 tail()

获取 DataFrame的头部或尾部几条行子集

在一列中查找符合条件的值

data_list_new = data_list[~data_list['备注'].isin([条件])].reset_index()

查找一列中是否包含列表中的元素

currency = ['USD','HKD','EUR','JPY','GBP']
currency_join = '|'.join(currency)    #即:'USD|HKD|EUR|JPY|GBP'
df.col.str.contains(currency_join) #返回bool值

在一列中查找包含的字符串

sql_data_new = sql_data[sql_data.branch.str.contains(字符串)]
#其中,sql_data.branch.str.contains(字符串) 和这一句等效:
sql_data_new.loc[:,'trade_type'] =='字符串'   #也等于这一句: sql_data_new.trade_type =='字符串' ,返回bool值

查询列中符合条件的所有行记录

#使用数据帧的方法
df[(df.age>=25) & (df.address =='Hanoi')]

#使用Query函数
df.query('age>=25 & address =="Hanoi"')

#使用loc函数
df.loc[(df.age>=25) & (df.address =='Hanoi')]

当dataframe的索引列为日期时,如果要查找某个日期段的记录,可以用下面的命令:
df.loc[startdate:enddate]

#使用loc函数查询符合条件的列
df.loc[(df.age>=25),['name','gender','address']]

#在一列中查询datetime类型的数据
date_col = ff[ff.apply(lambda x: isinstance(x,datetime))] 
#type(x) == datetime 总是不成功,因为type不考虑继承,而isinstance考虑继承

筛选全为0的行

#筛选全为0的行
df.loc[~(df==0).all(axis=1)]
 
#筛选不全为0的行
df.loc[(df==0).all(axis=1)]

查询某一列中的最大值所对应的索引。

强大的pandas早就为我们写好了封装函数: idxmax()、idxmin()
举个栗子:
先随便生成一个数据结构test

test = {'year':[2016,2016,2017,2017,2017,2018,2018],
        'num':[2,5,4,7,8,90,78],
        'name':['a','b','c','d','e','f','g']}
test = pd.DataFrame(test)
输出结果:

 name   num     year
0   a   2   2016
1   b   5   2016
2   c   4   2017
3   d   7   2017
4   e   8   2017
5   f   90  2018
6   g   78  2018

调用函数dataframe.idxmax(axis=0,skipna=True), 参数axis指定寻找最值的方向,按照行的方式或者列的方式

test[['num','year']].idxmax(axis=0)
输出:

num     6
year    5
dtype: int64

就找到了以列为方式的最大的num的索引为6,year的索引为5

pandas 行操作

删掉dataframe里的空行

df=df[~(df['col'].isnull())] #删掉空行
df=dropna(axis=0)  #删除有空值的行,使用参数axis=0

如果是在读取Excel文件时就要删除空行,可以用以下命令dropna(axis=0):

data_list =pd.read_excel(file_path +'\\'+ file_name, header =0).dropna(axis=0)

删掉最后一行(或最后几行)

df.drop(df.tail(1).index)

pandas 列操作

删掉一列

df.drop(['列名'],axis=1, inplace = True)

将一列转化为str

代码如下:

# apply()方法
num[0] = num[0].apply(str)    # 这里num[0]:取的是第一列,在我的代码中实际意义是一列时间列,形如:2019-06-18

可能下面的方式更好:

num['时间'] = num['时间'].apply(lambda x: x.strftime('%Y-%m-%d'))         # 可以指定时间str的格式

将某一列设置为str,主要是将时间列转为str类型,然后提取某一天的所有数据。

插入一列

#按默认(最后一列)插入新列
data_list['new'] =''
#按列索引序号插入指定位置
data_list_new.insert(0,'id','')

Pandas 自定义分类

利用category排序

利用pd.Categorical()创建categorical数据,Categorical()常用三个参数
参数一 values,如果values中的值,不在categories参数中,会被NaN代替
参数二 categories,指定可能存在的类别数据
参数三 ordered, 是否指定顺序 作者:ingemar- https://www.bilibili.com/read/cv18341556 出处:bilibili

pandas.cut() 函数

语法:

pandas.cut(x,
           bins,
           right=True,
           labels=None,
           retbins=False,
           precision=3,
           include_lowest=False,
           duplicates='raise',
           ordered=True)


返回值
它返回一个数组,数组代表了 x 中每个元素的 bin 值,如果我们设置了 retbins=True,它也会返回 bins。

import pandas as pd

df = pd.DataFrame({
    'Name': ["Anish","Birat","Chirag","Kabin","Sachin"],
    'Age':  [23,34,38,45,27],
    'Score': [316, 322, 332, 330,325],
})

df['Age-Range'] = pd.cut(x=df['Age'], bins=[20,30,40,50])
print("DataFrame with Age-Range:")
print(df)

DataFrame with Age-Range:
     Name  Age  Score Age-Range
0   Anish   23    316  (20, 30]
1   Birat   34    322  (30, 40]
2  Chirag   38    332  (30, 40]
3   Kabin   45    330  (40, 50]
4  Sachin   27    325  (20, 30]

参考资料:
https://it.sohu.com/a/539565237_568359
https://blog.csdn.net/jianai858/article/details/79851890
https://www.cnpython.com/qa/92169
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Categorical.html

pandas的计算

小数位数的控制

官网:http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.round.html

控制台打印时显示的2位小数:

pd.set_option('precision', 2)
#或
pd.set_option('display.float_format',lambda x: '%.2f' % x)

id列只保留两位小数
df["id"]=df["id"].round(2)
单独列还可以dtype=np.int64指定,多个列用dtype={"id":np.int64,"name":str}
df_y = pd.DataFrame(np.random.choice(2, batch_size), dtype=np.int64, columns=["y"])
如果是所有列:借助demicals保持高精度

value_a = np.around(np.random.normal(0, 1, (batch_size, col)), decimals=5, out=None)某一列str转数字类型: pd.to_numeric(s)

实际修改数据精度:

df = pd.DataFrame(np.random.random([3, 3]),
  columns=['A', 'B', 'C'], index=['first', 'second', 'third'])
df
               A         B         C
first   0.028208  0.992815  0.173891
second  0.038683  0.645646  0.577595
third   0.877076  0.149370  0.491027

df.round(2)
           A     B     C
first   0.03  0.99  0.17
second  0.04  0.65  0.58
third   0.88  0.15  0.49

df.round({'A': 1, 'C': 2})
          A         B     C
first   0.0  0.992815  0.17
second  0.0  0.645646  0.58
third   0.9  0.149370  0.49

decimals = pd.Series([1, 0, 2], index=['A', 'B', 'C'])
>>> df.round(decimals)
          A  B     C
first   0.0  1  0.17
second  0.0  1  0.58
third   0.9  0  0.49

插值计算之一: pd.interpolate()

x = pd.Series([1,2,np.nan,np.nan,6])
print(x.interpolate())
#输出
0    1.000000
1    2.000000
2    3.333333
3    4.666667
4    6.000000
dtype: float64

插值计算之二:from scipy.interpolate import interp1d

import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
from scipy import stats

x = np.linspace(0,10,10)
y = np.exp(-x/3.0)
f = interp1d(x,y)
f2 = interp1d(x,y,kind='cubic')
xnew = np.linspace(0,10,40)
plt.plot(x,y,'o',xnew,f(xnew),'-',xnew,f2(xnew),'--')
plt.legend(['data','linear','cubic'],loc='best')
plt.show()

beta,alpha,r_value,p_value,std_err = stats.linregress(x,y)

print('beta:',beta)
print('alpha:',alpha)
print('r_value:',r_value)
print('p_value:',p_value)
print('std_err:',std_err)

运行结果:
beta: -0.0866897899932637
alpha: 0.7485702038527071
r_value: -0.9136257511776316
p_value: 0.00021916674187652294
std_err: 0.013638772033747677

列的计算

通过一列,判断生成另一列

df['B'] = df['A'].map(lambda a : 1 if a>0 else 0) #根据列A新增列B,A中大于0的值为1,否则为0

#df有四列,现在要用现金流,来生成两列‘流入’和‘流出’
df['流入'] = df.现金流.apply(lambda x: x if x>0 else 0)
df['流出'] = df.现金流.apply(lambda x: 0 if x>0 else x)

通过两列计算,生成新列

map和lambda的搭配使用,可以将两个等长的序列进行运算,生成新的序列。利用这个方法,可以利用DataFrame中已知列的数据生成新列。具体如下:

df['new_col']=list(map(lambda x,y: function(x,y), df['col1'], df['col2']))

通过以上操作,把col1和col2两个等长的序列代入了function(x,y)函数,两列中对应的数据两两计算,生成了map对象。
再用list()函数把map对象转化为序列,就可以填入DataFrame生成一个新列new-col了。

第三种情形:使用df.apply(lambda x: function(), axis = 1)

主要是DataFrame.apply函数的应用,如果设置axis参数为1则每次函数每次会取出DataFrame的一行来做处理,如果axis为1则每次取一列。
如代码所示,判断如果城市名中含有ing字段且年份为2016,则新列test值赋为1,否则为0.

import numpy as np 
import pandas as pd 
  
data = {'city': ['Beijing', 'Shanghai', 'Guangzhou', 'Shenzhen', 'Hangzhou', 'Chongqing'], 
 'year': [2016,2016,2015,2017,2016, 2016], 'population': [2100, 2300, 1000, 700, 500, 500]} 
frame = pd.DataFrame(data, columns = ['year', 'city', 'population', 'debt']) 
  
def function(a, b): 
  if 'ing' in a and b == 2016: 
    return 1 
  else: 
    return 0 
print(frame, '\n') 
frame['test'] = frame.apply(lambda x: function(x.city, x.year), axis = 1) 

一个例子,三种方法

链接:https://www.jianshu.com/p/94e00fda5f63
根据下面的数据集,添加一列qualifications 当满足sy 大于或等于5,assets大于等于1000000时为yes,否则为no。

data = {'name':['Tom','Bulbasaur','Charmander','Squirtle','Caterpie'],'sy':[1,3,5,6,3],'assets':[1000000,400000,2050000,170000,5600000]}
df = pd.DataFrame(data)
"""方法一:通过索引遍历每个值,再通过条件给新增位置赋值"""
for i in df.index:
    if (df.loc[i,'sy']>=5) & (df.loc[i,'assets']>=1000000):
        df.loc[i,'qualifications'] = 'yes'
    else:
        df.loc[i,'qualifications'] = 'no'

"""方法二:通过np的where方法判断赋值"""
df['qualifications'] = np.where((df['sy']>=5) & (df['assets']>=1000000),'yes','no')

"""方法三:用apply方法设置一个函数"""
def f1(d):
    if (d['sy']>=5) & (d['assets']>=1000000):
        return 'yes'
    else:
        return 'no'
df['qualifications'] = df[['sy','assets']].apply(f1,axis=1) # axis = 1是改变传入数据的轴向

根据两列,计算加权值

df:
| bond_code | our_side | price_clean | amount_par |
| --------- | -------- | ----------- | ---------- |
| 180016    | 买入       | 101.4015    | 10000      |
| 180016    | 买入       | 100.4935    | 2000       |
| 180016    | 买入       | 100.4935    | 2000       |
| 180016    | 买入       | 100.908     | 5000       |
| 180016    | 买入       | 101.0196    | 3000       |
| 180016    | 卖出       | 102.5296    | 10000      |
| 180016    | 卖出       | 103.0034    | 9000       |
| 180016    | 卖出       | 103.1334    | 2000       |
| 180016    | 卖出       | 101.4718    | 1000       |

#方法一(逐步计算):
grouped = df.groupby('our_side')
get_wavg = lambda g: np.average(g['price_clean'],weights=g['amount_par'])
wavg = grouped.apply(get_wavg)

#方法二(函数式):
def wavg(values,weights,by):
    return (values*weights).groupby(by).sum()/weights.groupby(by).sum()

wavg(df.price_clean,df.amount_par,df.our_side)

wavg:
买入   101.07
卖出   102.73
dtype: float64

pandas自动生成数据

根据列表生成随机数据

import numpy as np
countries = np.array(["US", "UK", "GR", "JP"])
key = countries[np.random.randint(0, 4, 20)]
#输出:
array(['JP', 'US', 'UK', 'US', 'US', 'JP', 'UK', 'GR', 'US', 'UK', 'UK',
       'US', 'UK', 'GR', 'US', 'UK', 'US', 'US', 'JP', 'JP'], dtype='<U2')

生成日期序列

dates = pd.date_range("20130101", periods=6)
#输出:
DatetimeIndex(['2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04',
               '2013-01-05', '2013-01-06'],
              dtype='datetime64[ns]', freq='D')

生成6*4的 dataframe

df = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=list("ABCD"))
#输出:
                   A         B         C         D
2013-01-01  1.433950 -0.238960 -0.927613 -1.151130
2013-01-02  2.245523 -1.033523 -0.870130 -0.520500
2013-01-03 -1.386891 -0.686143  1.122175  1.453693
2013-01-04  0.917329 -0.820655  0.972674 -0.819141
2013-01-05 -0.481533  1.008935 -0.536159 -0.555727
2013-01-06 -1.117042 -0.358691  1.661648 -0.861112

生成连续日期(日期列表,或月末日期列表)

startdate = '2020-01-01'
enddate ='2020-12-31'
day_list = pd.date_range(start_date,end_date,freq='D')
month_list =  pd.date_range(start_date,end_date,freq='M')

分别生成:

DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04',
               '2020-01-05', '2020-01-06', '2020-01-07', '2020-01-08',
               '2020-01-09', '2020-01-10',
               ...
               '2020-12-22', '2020-12-23', '2020-12-24', '2020-12-25',
               '2020-12-26', '2020-12-27', '2020-12-28', '2020-12-29',
               '2020-12-30', '2020-12-31'],
              dtype='datetime64[ns]', length=366, freq='D')

DatetimeIndex(['2020-01-31', '2020-02-29', '2020-03-31', '2020-04-30',
               '2020-05-31', '2020-06-30', '2020-07-31', '2020-08-31',
               '2020-09-30', '2020-10-31', '2020-11-30', '2020-12-31'],
              dtype='datetime64[ns]', freq='M')

#注意type:
type(month_list)
pandas.core.indexes.datetimes.DatetimeIndex

如果要把.DatetimeIndex转化为正常的list,则可以用以下命令:

month_list = pd.Series(month_list)

month_list
Out[100]: 
0    2020-01-31
1    2020-02-29
2    2020-03-31
3    2020-04-30
4    2020-05-31
5    2020-06-30
6    2020-07-31
7    2020-08-31
8    2020-09-30
9    2020-10-31
10   2020-11-30
11   2020-12-31

生成一列各类型都有的df

df2 = pd.DataFrame(
   ...:     {
   ...:         "A": 1.0,
   ...:         "B": pd.Timestamp("20130102"),
   ...:         "C": pd.Series(1, index=list(range(4)), dtype="float32"),
   ...:         "D": np.array([3] * 4, dtype="int32"),
   ...:         "E": pd.Categorical(["test", "train", "test", "train"]),
   ...:         "F": "foo",
   ...:     }
   ...: )

     A          B    C  D      E    F
0  1.0 2013-01-02  1.0  3   test  foo
1  1.0 2013-01-02  1.0  3  train  foo
2  1.0 2013-01-02  1.0  3   test  foo
3  1.0 2013-01-02  1.0  3  train  foo

pandas时间处理

排序

按各列名排序

data_list_new = data_list_new.sort_values(by=['起息日','机构','项目']).reset_index(drop= True)

pandas数据清洗

缺失值与空值处理

1.df.dropna()函数

相关概念
函数具体解释
空值:在pandas中,空值就是空字符串 “”
缺失值:np.nan(缺失数值),pd.naT(缺失时间),或None(缺失字符串)

DataFrame.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
函数作用:删除含有空值的行或列
axis:维度,axis=0表示index行,axis=1表示columns列,默认为0
how:"all"表示这一行或列中的元素全部缺失(为nan)才删除这一行或列,"any"表示这一行或列中只要有元素缺失,就删除这一行或列
thresh:一行或一列中至少出现了thresh个才删除。
subset:在某些列的子集中选择出现了缺失值的列删除,不在子集中的含有缺失值得列或行不会删除(有axis决定是行还是列)
inplace:刷选过缺失值得新数据是存为副本还是直接在原数据上进行修改。
data.dropna(how = 'all') # 传入这个参数后将只丢弃全为缺失值的那些行
data.dropna(axis = 1) # 丢弃有缺失值的列(一般不会这么做,这样会删掉一个特征)
data.dropna(axis=1,how="all") # 丢弃全为缺失值的那些列
data.dropna(axis=0,subset = ["Age", "Sex"]) # 丢弃‘Age’和‘Sex’这两列中有缺失值的行

例子:

df = pd.DataFrame({"name": ['Alfred', 'Batman', 'Catwoman'],"toy": [np.nan, 'Batmobile', 'Bullwhip'],
                  "born": [pd.NaT, pd.Timestamp("1940-04-25"),pd.NaT]})

df
Out[0]: 
       name        toy       born
0    Alfred        NaN        NaT
1    Batman  Batmobile 1940-04-25
2  Catwoman   Bullwhip        NaT

df.dropna()
Out[1]: 
     name        toy       born
1  Batman  Batmobile 1940-04-25

df.dropna(axis=1) #delete col
Out[2]: 
       name
0    Alfred
1    Batman
2  Catwoman

df.dropna(how='all') #所有值全为缺失值才删除
Out[3]: 
       name        toy       born
0    Alfred        NaN        NaT
1    Batman  Batmobile 1940-04-25
2  Catwoman   Bullwhip        NaT

df.dropna(thresh=2) #至少出现过两个缺失值才删除
Out[4]: 
       name        toy       born
1    Batman  Batmobile 1940-04-25
2  Catwoman   Bullwhip        NaT

df.dropna(subset=['name', 'born'])    #删除subset中的含有缺失值的行或列
Out[5]: 
     name        toy       born
1  Batman  Batmobile 1940-04-25

df.fillna()

DataFrame.fillna(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None, **kwargs)
函数作用:填充缺失值
value:需要用什么值去填充缺失值
axis:确定填充维度,从行开始或是从列开始
method:ffill:用缺失值前面的一个值代替缺失值,如果axis =1,那么就是横向的前面的值替换后面的缺失值,如果axis=0,那么则是上面的值替换下面的缺失值。backfill/bfill,缺失值后面的一个值代替前面的缺失值。注意这个参数不能与value同时出现
limit:确定填充的个数,如果limit=2,则只填充两个缺失值。

示例:

df = pd.DataFrame([[np.nan, 2, np.nan, 0],[3, 4, np.nan, 1],
                 [np.nan, np.nan, np.nan, 5],[np.nan, 3, np.nan, 4]],
                columns=list('ABCD'))
df
Out[0]: 
     A    B   C  D
0  NaN  2.0 NaN  0
1  3.0  4.0 NaN  1
2  NaN  NaN NaN  5
3  NaN  3.0 NaN  4

df.fillna(axis=1,method='ffill')  #横向用缺失值前面的值替换缺失值
Out[1]: 
     A    B    C    D
0  NaN  2.0  2.0  0.0
1  3.0  4.0  4.0  1.0
2  NaN  NaN  NaN  5.0
3  NaN  3.0  3.0  4.0

df.fillna(axis=0,method='ffill')   #纵向用缺失值上面的值替换缺失值
Out[2]: 
     A    B   C  D
0  NaN  2.0 NaN  0
1  3.0  4.0 NaN  1
2  3.0  4.0 NaN  5
3  3.0  3.0 NaN  4

df.fillna(0)
Out[3]: 
     A    B    C  D
0  0.0  2.0  0.0  0
1  3.0  4.0  0.0  1
2  0.0  0.0  0.0  5
3  0.0  3.0  0.0  4


values = {'A':0,'B':1,'C':2,'D':3}
df.fillna(value=values)   #不同的列用不同的值填充
Out[4]: 
     A    B    C  D
0  0.0  2.0  2.0  0
1  3.0  4.0  2.0  1
2  0.0  1.0  2.0  5
3  0.0  3.0  2.0  4

df.fillna(value=values,limit=1)   #对每列出现的替换值有次数限制,此处限制为一次
Out[5]: 
     A    B    C  D
0  0.0  2.0  2.0  0
1  3.0  4.0  NaN  1
2  NaN  1.0  NaN  5
3  NaN  3.0  NaN  4

df.isna()和df.isnull()

df.isna() 和 df.notna(),可以判断出None、pd.NaT、np.NaN 三种类型的缺失值;

  • 但是空字符串 “” 、0,不会认为是缺失值;
  • 另外对于4字符的字符串“None”、“null” ,也不会认为是缺失值。
  • df.isnull() 等同于 df.isna()
  • df.notnull() 等同于 df.notna()

缺失值和空值被转换后会怎么样?
字符串类型缺失值 None:
None 被 astype(str)转换后,会变成一个4字符的字符串"None" (注意它会被isna() 识别为 False, 相当于一个正常的字符串),极具迷惑性。
None 被 pd.to_datetime()转换后,仍然是一个NoneType类型的 None缺失值,没变。
None 被 astype(np.int64) 或 np.int32() 转换时,会提示int()函数不接受NoneType类型的参数,转换无法进行。
数值类型缺失值 np.NaN:

np.NaN 被astype(str)转换后,会变成一个3字符的字符串"nan"。
被 pd.to_datetime() 转换后,会变成 NaTType类型,即时间缺失值,仍然可以被isna()识别出来。
np.NaN 被np.int32() 转化时,会提示 float 类型的 NaN 不能被转换为 integer 类型,因为np.NaN 本身确实是个一个float类型。如果被np.float32() 转换后,则转换前后没有区别,仍然是 np.NaN 浮点型。
时间类型缺失值 pd.NaT:

pd.NaT 被astype(str) 转换后,会变成一个3字符的字符串"NaT"。
被 pd.to_datetime() 转换前后无变化,仍然是 NaTType类型的缺失值。
pd.NaT 被np.int32() 转化后,会变成一个巨长的整数。被np.float32() 转换时,会提示 NaTType类型的缺失值无法转换。

检查dataframe是否有空值

确定空值位置:
在导入dataframe之后,一个非常好的习惯就是及时检查一下每一列是否有空值,用下面的语句可以简单实现这个需求:

df.isnull().any()
#上面的这行代码可以返回各个列是否有空值的情况,结果如下:
    
A                False
B                True
C                True
D                False
dtype: bool

这样我们可以得知, B列和C列有空值存在, 在用到这两列数据的时候,需要考虑对空值的处理方法。

处理空值的两种办法:删除 or 填充

删除:删除空值主要使用下面这个语句:

df.dropna()
df.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
df.dropna(axis = 0, subset = ['A'] )   #subset非常有用,本句删除所有列A 空值所在行

axis代表删除整行or整列,默认axis = 0, 也就是删除行。
how默认为‘any’, 也就是删除任何含有空值的行/列。此外how = ‘all’, 则会删除全部为空值的行/列。
thresh可以用来限定删除有几个空值的行/列,如thresh = 3, 则删除有3个空值的行/列。

填充:填充空值主要使用下面这个语句:

df.fillna( )
df.fillna(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None, **kwargs)

value可以是一个值(标量),比如我们用一列的均值来填充该列的所有空值:

df['column_name'].fillna(value = df['column_name'].mean()]
#value 也可以是 dict, Series, 甚至 DataFrame,比如我们可以用字典来实现对不同的列填充不同的值:

df.fillna({'column_name_A': 0,'column_name_B': 100})

两个series相加,根据常识我们可以知道index不同的地方会变成空值,如下图

s1 = pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])
s2 = pd.Series([10, 20, 30, 40], index=['c', 'd', '```e', 'f'])
s1 + s2
a     NaN
b     NaN
c    13.0
d    24.0
e     NaN
f     NaN

如果我们希望空值的地方被原series中的值填充,即得到以下效果:

a     1
b     2
c    13
d    24
e    30
f    40

可以使用add而不是加号来进行:

s1.add(s2, fill_value = 0)

pandas格式处理

读取源文件sheet格式,复制到目标sheet中

import pandas as pd

def copy_excel_format(source_file, source_sheet_name, target_file, target_sheet_name):
    # 读取源 Excel 文件的指定工作表
    source_df = pd.read_excel(source_file, sheet_name=source_sheet_name)
    # 保存源工作表的格式信息
    source_format = source_df.style

    # 读取目标 Excel 文件的指定工作表
    target_df = pd.read_excel(target_file, sheet_name=target_sheet_name)
    # 将源工作表的格式应用到目标工作表
    target_df.style = source_format

    # 保存修改后的目标文件
    with pd.ExcelWriter(target_file, engine='openpyxl', mode='a') as writer:
        target_df.to_excel(writer, sheet_name=target_sheet_name, index=False)

# 调用函数,指定源文件、源工作表名称、目标文件和目标工作表名称
copy_excel_format('source.xlsx','sheet1', 'target.xlsx','sheet2')

pandas异常处理

SettingWithCopyWarning:

#新增一列type,将原df.trade_type中包含'买入返售金融资产'字符的,重新设定为'buy',否则就改成'sell'
sql_data_new['type']=np.where(sql_data_new.trade_type.str.contains('买入返售金融资产'),'buy','sell')

运行时,会遇到以下SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view
按照官网的解释,采用的方法是如下这样:

mask = sql_data_new.trade_type.str.contains('买入返售金融资产')
sql_data_new.loc[mask, 'types'] = 'buy'

尴尬就是得至少执行两次,才能分别赋值'buy','sell'

显示完整行或列

pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)

pd.read_excel ValueError

sql="SELECT * FROM {dbs} where buysell_type not like '%外汇兑换%'".format(dbs=db_name_spot)
custom_fx_list = pd.read_sql(sql,engine)

运行出现:ValueError: unsupported format character '?' (0x5916) at index 86
这种情况:%在字符串中作为格式化字符串的关键字,当其后为诸如n、c、s时进行正常转义;而出现上述代码时即返回错误。
解决方法:
1.使用%%,即表示非关键字的%(推荐);
2.使用%,有些情况下适用。
即:

sql="SELECT * FROM {dbs} where buysell_type not like '%%外汇兑换%%'".format(dbs=db_name_spot)
custom_fx_list = pd.read_sql(sql,engine)

参考资料

https://www.cnpython.com/qa/93519
pandas的新功能(不常用的用法,但很好用)
https://www.jb51.net/article/167136.htm

posted on 2021-02-05 15:21  chengjon  阅读(2912)  评论(0编辑  收藏  举报