Python常见问题与解决方案

本文介绍了Python中处理时间变量的多种方法,包括时间戳、时间元组和格式化字符串之间的转换,以及在DataFrame中操作日期的实用技巧。此外,还探讨了数据排序、数据类型转化、异常处理、CSV与Excel文件转换、文件操作、数据读写和缺失值处理等常见问题的解决方案。
摘要由CSDN通过智能技术生成

问题目录:

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
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值