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