常见问题与解决方案
- 问题目录:
-
- 1. 时间变量的操作
- 2. 索引的重建与设置
- 3. 数据的排序
- 4. 数据类型的转化
- 5. 异常处理 -跳过异常继续执行
- 6. CSV 与 Excel的 批量转换
- 7. 文件操作
- 8. 数据读入与写入
- 9. 缺失值问题 np.nan,None,NaT
- 10. 使用Python输出回归表格
- 11. 特殊结构数据整理
- 12. 估计系数联合检验(Wald tests via statsmodels)
- 13. Python 与 STATA 时间日期转换问题
- 14. Python执行面板数据的Hausman检验
- 15. Fama Macbeth回归、滚动回归等等
- 16. 事件研究法 event study
- 生
- 创
- 创
- 如
- 注
- K
- 新
- U
- F
- 导
问题目录:
Python,作为当今主流的编程语言,受到全世界爱好者的追捧。如果你是一名科研小白,导师也许要求你使用它来完成一些任务。确实,入门容易,看看市面上种类繁多的教科书就行,但是,能够做到灵活运用又是谈何容易,Python语句编写的灵活性常常让很多的文科生想死的感觉都有。以下的内容就是鄙人在讲授相关课程时学生容易产生疑问的知识点,不是很全面,还在持续的更新之中… 。
1. 时间变量的操作
我们从在线API接口、外部Excel 都可以获得数据,读入到pandas之后,时间变量的操作对于后续的计算工作十分重要。
主要的时间模块有包括time、datetime和calendar。
在Python中表示时间的方式:
- 时间戳:10位整数位和若干小数位,例如 1551153156.6358607
- 元组(struct_time): 含有9个元素的元组,例如 (tm_year=2011, tm_mon=9, tm_mday=28, tm_hour=10, tm_min=0, tm_sec=0, tm_wday=2, tm_yday=271, tm_isdst=-1)
- 格式化字符串: 格式化的时间字符串, 例如 ‘2019-02-26 12:45:46’
- time模块,以元组(struct_time)为核心实现时间戳和格式化时间字符串的相互转换。
- datetime模块,以datetime类实例对象为核心实现时间戳和格式化时间字符串的相互转换。
import time
#1.时间戳------->时间元组:
time1 = time.time() #显示的是时间戳
tuple = time.gmtime(time1) # UTC时间 时间元组
print(tuple)
#time.struct_time(tm_year=2021, tm_mon=11, tm_mday=3, tm_hour=16, tm_min=9, tm_sec=20, tm_wday=2, tm_yday=307, tm_isdst=0)
tuple1 = time.localtime(time1) # UTC + 8 时间 时间元组
print(tuple1)
#time.struct_time(tm_year=2021, tm_mon=11, tm_mday=4, tm_hour=0, tm_min=9, tm_sec=20, tm_wday=3, tm_yday=308, tm_isdst=0)
#2.时间元组-------->时间戳:
tuple2 = time.localtime()
time2 = time.mktime(tuple2)
print(time2)
#1635955760.0
#3.时间元组--------->字符串:
tuple = time.localtime()
strTime = time.strftime("%Y-%m-%d %H:%M:%S",tuple)
print(strTime)
#2021-11-04 00:09:20
strTime1 = time.strftime("%Y{y}%m{m}%d{d} %H{h}%M{m1}%S{s}",tuple).format(y="年",m="月",d="日",h="时",m1="分",s="秒") #'2021年11月02日 23时49分53秒'
print(strTime1)
#2021年11月04日 00时11分49秒
#4.字符串---------->时间元组:
tupleTime = time.strptime("2018年01月05日","%Y{y}%m{m}%d{d}".format(y="年",m = "月",d="日"))
print(tupleTime)
#time.struct_time(tm_year=2018, tm_mon=1, tm_mday=5, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=4, tm_yday=5, tm_isdst=-1)
- 时间元组(time.struct_time)
时间元组是一个比较重要的类型,通过时间元组我们可以获取,年月日时分秒,星期几,一年中的第几天等信息。
- 时间格式化
时间格式化是非常常用的一个功能,不管是从字符串到struct_time、date、datetime,还是从struct_time、date、datetime到字符串都需要用到。
格式化主要涉及到2个函数:
strftime:str表示字符串,f是format,time是时间,就是时间格式化为字符串
strptime:str表示字符串,p是parse,time是时间,就是字符串解析为时间
time和datetime都有这2个函数。
参考文献:
python 之 时间戳
Python中的时间元组与时间日期
Python3 日期和时间
Python日期时间(详细)
在实战中,数据常常存储在DataFrame之中,时间 date变量 可以是 作为index存在的,也可以是作为一个单独的变量存在的。格式为:2021-11-10 或者 20211110 或者2021/11/10 或者2021-11-10 00:00:00 等等样子。
首先,我们在 IPYTHON的命令窗口 In 1: 输入 df.dtypes(假设数据对象是df) 或者输入 df.info(),查看各个变量的个数,以及各个变量的属性。
如果date是字符型则显示为 object,
如果是数字型则显示为 int64 或者 float64,
如果是日期型则显示为 datetime64[ns]。
a.如果时间 date变量 是 作为index存在的(一般情况下通过 API提取的数据存在这样的情况,并且这时的date是时间型datetime64[ns]),下面我们要提取它的年月日。
df[‘year’] = df.index.year
df[‘month’] = df.index.month
df[‘day’] = df.index.day
b.如果是date是 数字型变量(20101203),显示为 int64 或者 float64。
df[“year”] = df[“date”].apply(lambda x: int(str(x)[:4])) #year 数字型
df[“year2”] = df[“date”].apply(lambda x: str(x)[:4]) #year2字符型
df[“month”] = df[“date”].apply(lambda x: int(str(x)[4:6]))
df[“day”] = df[“date”].apply(lambda x: int(str(x)[6:]))
c.如果是date是 字符型变量(“20101203”),显示为 object。
方法一:
import pandas as pd
from datetime import datetime
df[“date2”]=pd.to_datetime(df[“date”]) #字符型转化为时间型 datetime64[ns]
df[“year”] =pd.to_datetime(df[“date”]).dt.year #year数字型
df[“month”] =pd.to_datetime(df[“date”]).dt.month
df[“day”] =pd.to_datetime(df[“date”]).dt.day
方法二:
df[“year”] = df[“date”].apply(lambda x: int(x[:4])) #year数字型
df[“month”] = df[“date”].apply(lambda x: int(x[4:6]))
df[“day”] = df[“date”].apply(lambda x: int(x[6:]))
方法三:使用astype
df[‘date’].astype('datetime’64)
方法使四:用datetime
df[‘date’] = df[‘date’].apply(lambda x: datetime.strptime(x,’%Y-%m-%d’))
将日期转换为月份M、季度Q
df[‘period’] = df[‘date’].dt.to_period(‘M’)
d.如果date是日期型,则显示为 datetime64[ns]。
df[“year”] =pd.to_datetime(df[“date”]).dt.year #year数字型
df[“month”] =pd.to_datetime(df[“date”]).dt.month
df[“day”] =pd.to_datetime(df[“date”]).dt.day
e.如果date是python将excel读取的日期文本数字 转为日期(5位数字时间戳)。
如果时间戳是很长的位数,则:
- df[‘gtime’]=pd.to_datetime(df[‘gtime’],unit=‘s’))
#以上以默认1970-01-01为0点位
或者:
- df[‘time_stamp’]=pd.to_datetime(df[‘time_stamp’],unit=‘s’,origin=pd.Timestamp(‘2018-07-01’))
#这个的意思是将time_stamp这列的时间戳转换为日期格式,单位是秒(unit=‘s’),计算的日期是从2018年的7月1号开始,即从2018年的7月1号开始加上时间戳的那么多秒。
下面以excel读入时间数据(时间变为看似浮点型的数字了,并且是5位数字时间戳,开始的时候确实有点懵逼-^^-)为例来讲解:
#这列fin46本来在excel中是日期,读入Python后变为数字了,并且还有很多的缺失值nan
#如果直接使用时间转换函数,可能转不了,需要先将nan转为数值0
df_final['fin462']=df_final['fin46'].fillna(0)
from datetime import datetime
#以下是时间转换函数
def date_change(stamp):
delta = pd.Timedelta(str(stamp)+'D')
real_time = pd.to_datetime('1899-12-30') + delta
return real_time
#套用以上函数,转为 2021-11-16 00:00:00 字符型格式
df_final['fin463']=df_final['fin462'].apply(date_change)
#去掉时分秒
df_final["fin463"] = df_final["fin463"].dt.date
#或者代码
df_final["fin4633"] = df_final["fin463"][0].strftime("%Y-%m-%d")
#将日期 fin463 转换为月份、季度
df_final['period'] = df_final['fin463'].dt.to_period('M')
df_final['period2'] = df_final['fin463'].dt.to_period('Q')
#把一些本来是缺失的时间变为 空值
df_final.loc[df_final['fin462'] == 0,'fin463'] = None
#字符型转化为时间型 datetime64[ns]
df_final["date2"]=pd.to_datetime(df_final['fin463'])
#删除中间变量,因为他们已经无用武之地
del df_final['fin462']
del df_final['fin463']
#生成三列:年月日
df_final["year"] =pd.to_datetime(df_final["date2"]).dt.year #year数字型
df_final["month"] =pd.to_datetime(df_final["date2"]).dt.month
df_final["day"] =pd.to_datetime(df_final["date2"]).dt.day
参考文章:
https://blog.csdn.net/weixin_41261833/article/details/104839119
https://vimsky.com/examples/usage/python-pandas-period-strftime.html
https://vimsky.com/zh-tw/examples/usage/python-pandas-datetimeindex-strftime.html
https://www.cnblogs.com/shadow1/p/10951979.html
https://www.cnblogs.com/nxf-rabbit75/p/10660317.html
https://blog.csdn.net/u010591976/article/details/104253489?ivk_sa=1024320u
参考文章:
a = "44042"
import pandas as pd
def date(stamp):
delta = pd.Timedelta(str(stamp)+'D')
real_time = pd.to_datetime('1899-12-30') + delta
return real_time
print(str(date(a)).split(" ")[0])
原文链接:https://blog.csdn.net/qq_57173722/article/details/121030038
io = "中国数据.xlsx"
dt = pd.read_excel(io, sheet_name = 0)
dt1 = pd.read_excel(io, sheet_name = 1)
def date(para):
if type(para) == int:
delta = pd.Timedelta(str(int(para))+'days')
time = pd.to_datetime('1899-12-30') + delta
return time
else:
return para
dt['日期'] = dt['日期'].apply(date)
dt
还有这种时间显示的格式,pandas 读excel,日期变成了数字,pandas方法解决:
import pandas as pd
data = pd.read_excel('文件路径')
data['发货日期'] = data['发货日期'].fillna(method='ffill') # 因为有合并单元格,
data
def date(para):
delta = pd.Timedelta(str(int(para))+'days')
time = pd.to_datetime('1899-12-30') + delta
return time
data['发货日期'] = data['发货日期'].apply(date)
data
计算两个日期的时间(天数)间隔。
import time
def demo(day1, day2):
time_array1 = time.strptime(day1, "%Y-%m-%d")
timestamp_day1 = int(time.mktime(time_array1))
time_array2 = time.strptime(day2, "%Y-%m-%d")
timestamp_day2 = int(time.mktime(time_array2))
result = (timestamp_day2 - timestamp_day1) // 60 // 60 // 24
return result
day1 = "2018-07-09"
day2 = "2020-09-26"
day_diff = demo(day1, day2)
print("两个日期的间隔天数:{} ".format(day_diff))
#或者:
def is_leap_year(year):
if (year % 4 == 0 and year % 100 != 0) or year % 400 == 0:
return 1
else:
return 0
def get_days(year, month, day):
days = 0
month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
if is_leap_year(year):
month_days[1] = 29
for i in range(1, year):
year_day = 365
if is_leap_year(i):
year_day = 366
days += year_day
for m in range(month - 1):
days += month_days[m]
days += day
return days
def get_result(start_time, end_time):
res = end_time - start_time
return res
year1, month1, day1 = 2018, 7, 9
year2, month2, day2 = 2020, 9, 26
days1 = get_days(year1, month1, day1)
days2 = get_days(year2, month2, day2)
day_diff = get_result(days1, days2)
print("两个日期的间隔天数:{} ".format(day_diff))
2. 索引的重建与设置
关键词:reset_index
reset_index可以还原索引,重新变为默认的整型索引。
df.reset_index(level=None, drop=False, inplace=False, col_level=0, col_fill=”)
常用的是:
df.reset_index(drop=False, inplace=True)
level控制了具体要还原的那个等级的索引;
drop为False则索引列会被还原为普通列,否则会丢失(True);
inplace=True时表示当前操作对原数据生效.
a.如果数据框df 索引 和 变量 都存在一个 date, 重建索引时要使用:
df.reset_index(drop=True,inplace=True)
这样date就能够顺利从index角色变为 普通变量的角色,方便 再次重新编制索引了。
b.如果数据框df 索引 与变量不存在重复, 重建索引时要使用:
df.reset_index( inplace=True) #索引变为普通变量
df.reset_index(drop=True, inplace=True) #原索引被删除了
当然,前期在重建索引时,最好不要删除原索引,后期可以随时删除:
df.drop(“date”,axis=1,inplace=True)
或者:
del df[“date”] #都能够删除这个原来的索引date.
关键词:set_index
DataFrame可以通过set_index方法,可以设置单索引和复合索引。
DataFrame.set_index(keys, drop=True, append=False, inplace=False, verify_integrity=False)
常用的是:
df.set_index(“code”,drop=False, inplace=True)
append添加新索引,
drop默认为False,True代表不删除作为新索引的列(变量),就是说一个字段 同时出现在 index 和 普通变量(列)之中。
inplace为True时,表示当前操作对原数据生效。
3. 数据的排序
要对pandas.DataFrame和pandas.Series进行排序,可以使用sort_values()和sort_index()方法。
a.按元素排序sort_values()(如果要更改原始对象,则参数inplace=True)
df_s = df.sort_values(‘state’) #按照一个变量排序
df_s = df.sort_values(‘state’, ascending=False)#按照一个变量排序,降序排
df_s = df.sort_values([‘age’, ‘state’], ascending=[True, False]))#按照多个变量排序,降或升序排都可以设置
df_d .sort_values(by=1, axis=1, ascending=False, inplace=True)#按照列来排序
b. 按索引排序(行名/列名)sort_index()
与sort_values()一样,默认值为升序。如果要使用降序,请将升序参数设置为False。
df_s = df.sort_index(ascending=False)
按列名列排序(参数axis),意义不大。
df.sort_index(axis=1, ascending=False, inplace=True)
c.多层索引的取值
loc使用的是标签索引,iloc使用的是位置索引。但是,iloc的取值并不会受多层索引影响,只会根据数据的位置索引进行取值。
s.loc[‘张三’]
s.loc[‘张三’,‘期中’]
s.loc[:,‘期中’]
s.iloc[0]
df.loc[‘张三’].loc[‘期中’]
df.loc[(‘张三’,‘期中’)]
多层索引的排序:
DataFrame按行索引排序的方法是sort_index(),df.sort_index()中的level参数可以指定是否按照指定的层级进行排列,第一层级索引值为0,第二层级索引值为1。df.sort_index(level=0,ascending=False).
4. 数据类型的转化
在实际的数据处理中,常见的数据类型包括了:numpy中的array、list、tuple、dict、pandas中的series、pandas中的dataframe。我们在套用他人的代码的时候,很多同学经常出错,原因就是别人代码输入端的规定数据类型和你的数据类型不一样,对象不一样,对象的属性和方法就出现了很大的差异,那程序当然运行不了呀。所以,你需要理解别人的代码,然后把我们自己的数据转化为 合格的数据类型。
a. DataFrame 转化为 List 类型
import pandas as pd
import numpy as np
from pandas import DataFrame
data_file = ‘d:/Users/qiguan/Downloads/data.xlsx’ #data_file 数据文件路径
data = pd.read_excel(data_file, index_col=None)#读取文件数据
data_array = np.array(data)#首先将pandas读取的数据转化为array
data_list =data_array.tolist() #然后转化为list形式
b. 把DataFrame转成Series类型,改变列中值的类型方法
b1. 使用 pd.Series把dataframe转成Series
import pandas as pd
df_series = pd.Series(df[‘Value’].values, index=df[‘Date’])
b2.使用astype改变列中的值的类型,注意前面要有np
import numpy as np
df[‘列名’] = df[‘列名’].astype(np.int64)
c. DataFrame类型转换成Numpy中array类型
import numpy as np
import pandas as pd
df=pd.DataFrame({‘A’:[1,2,3],‘B’:[4,5,6],‘C’:[7,8,9]})
c1.使用DataFrame中的values方法
np1 = df.values #type(np1) 查看类型为 numpy.ndarray
c2.使用Numpy中的array方法
np2 = np.array(df) #type(np2) 查看类型为 numpy.ndarray
2种方法效果相同,都能实现DataFrame到array的转换
5. 异常处理 -跳过异常继续执行
python一般使用try…except…处理异常,这样子的话,保障程序在遇到意外情况的时候,能够继续执行下去。当然,这个办法也有缺陷,就是丢失掉了一些数据,失去了改正的机会。要是想改正,我们就必须让程序返回错误的信息是什么才好下手去找错。
比如,很多时候代码只要有一个异常,程序就不继续执行了。异常情况是有很多的,有的你想也想不到。那么,当循环中出现异常时,如何跳过循环中的异常继续执行。比如当我move一个文件的时候,如果目标文件不存在,程序可跳过异常,继续执行,下面是一种可行的方法:
import pandas as pd
dates=range(20161010,20161114)
pieces=[]
for date in dates:
try:
data=pd.read_csv('A_stock/overview-push-%d/stock overview.csv' %date, encoding='gbk')
pieces.append(data)
except Exception as e:
pass #存有异常,但是跳过现在的错误的当前循环,继续执行下一步循环。
continue #无论是否有异常,都将继续执行 continue后面的命令,但是这里没有了后续命令,所以这儿的pass continue结构可以修改,即 pass改为continue,不过,如果原始的continue后面有语句则不同了。
data=pd.concat(pieces)
下面的代码相对完善一点:
try:
#x=1/0 #这个错误对应于 except Exception as e:
print('========>1')
name
print('==========>2')
l = [1, 2, 3]
# l[100]
print('==========>3')
d={
}
d['name']
print('=============>4')
except NameError as e:
print('----------->', e)
print(1)
except IndexError as e:
print('----------->', e)
print(2)
except KeyError as e:
print('----------->', e)
print(3)
except Exception as e:#异常不是上面的几种类型,但仍存有异常,则执行这个语句
print('统一的处理方法',333)
else: #所有的异常都没有用发生,则执行下面的语句
print('在被监测的代码块没有发生异常时执行')
finally: #不管上面的语句是否正确,都能执行下面的语句。
print('不管被监测的代码块有无发生异常都会执行')
print('执行接下去的代码')
try except 与pass continue结合编写代码:
- (1)为了跳过for循环里的某次循环,以下代码当某次循环发生错误时,执行except代码块,continue跳过该次循环:
x=5
for i in range(x):
try:
i += 1
print(i)
except:
pass #这儿pass可以换为 continue
print("kk:",i)
1
kk: 1
2
kk: 2
3
kk: 3
4
kk: 4
5
kk: 5
- (2)还可以写成这样,遇到错误执行except代码块,pass忽略错误并继续往下运行,略有不同的就是无论程序错误与否都会运行到continue这一行代码:
x=5
for i in range(x):
try:
i += 1
print(i)
except:
pass
continue
1
2
3
4
5
如果continue后面有语句情况就不一样了。
x=5
for i in range(x):
try:
i += 1
print(i)
except:
pass
continue
print("kk:",i)
continue不管程序是否出现异常,都将屏蔽后面的语句。
1
2
3
4
5
修改一下:
x=5
for i in range(x):
try:
i += 1
print(i)
except:
continue
print("kk:",i)
1
kk: 1
2
kk: 2
3
kk: 3
4
kk: 4
5
kk: 5
- (3)还有一种用法就是遇到错误时直接中断整个for循环:
try:
for i in range(x):
i += 1
print(i)
except:
pass
pass, continue 与条件语句的结合:
var = 10
while var > 0:
var = var -1
if var == 5:
pass
print ('当前变量值 :', var)
print( "Good bye!")
当前变量值 : 9
当前变量值 : 8
当前变量值 : 7
当前变量值 : 6
当前变量值 : 5
当前变量值 : 4
当前变量值 : 3
当前变量值 : 2
当前变量值 : 1
当前变量值 : 0
Good bye!
var = 10