pandas使用总结大全-增加、删除、去重、表连接等

Pandas数据骚操作


Pandas介绍

  • [Pandas在处理表格数据已经分装的很好了,学会谷歌很关键]
    Pandas作在为python处理表格(数据能在本地电脑进行增删除操作,一般: 0-5G以内 )数据分析的大杀器,在目前国内数据挖掘比赛以及工作中常用工具, 朝天椒 使用其进行了快一年的工作实践以及一些数据挖掘的比赛,在工作实践中时常比较各种操作的优劣势、请教队友、同事的code以及学习方法,发现最好的学习方法就是给脑洞大开的产品经理清洗复杂数据以及业务逻辑,当对常用的接口有一定的了解之后,解决问题的方法就是谷歌和查看Pandas_API的官方文档,本文的意义在于总结工作中常用操作以及收集各路大神code中的一些骚操作,使得入门者能够快速的使用pandas高效处理数据。

Pandas数据格式

  • DataFrame: 为多行多列数据
  • Series:一列数据,由默认index和values组成
  • 针对DataFrame格式的数据,当对其进行操作时,有行和列之分,大部分的函数都有一个参数控制是对行进行操作还是列进行操作:axis

Pandas与文件

pandas支持各种类型的文件格式的读写操作例如:csv、txt、json、execl等,实际工作中一般以CSV文件格式为主,故介绍读写CSV文件的常用参数:

  • sep : 数据以什么样的分隔符进行隔开;
  • header : 当数据中的没有列名时,如果该参数为默认,读取数据时会将第一行数据设置为列名,因此需要将该参数设置为 None 就会将自动调加[0-(df.shape1-1)]的列名,如果你想要不那么不美观可以将 predix 参数设置为 aa ,则列名前面会增加aa字符串;
  • usecols、nrows、skiprows : 读取设定的行数和列数,当数据量特别大的时候,但是没有服务器,可以对其进行截断读取;
  • dtype : 设置列的数据类型,pandas的数据类型和语言差不多(object(string), int, float等) engine :当文件的名字为中文名字时,例如: 哈哈.csv , 需要将其设置为 python 才可进行读取,不然会报错 。
  • quoting: 当读取csv文件时,如果数据中有"等特殊符号,则可能会出现读取数据少了很多,这个时候就需要加上这个参数保证数据没有出错,quoting=3
  • 如果读取的时候出现一列中有多种数据类型一般都是有问题的,排查的方法就是将那列相关的数据打印出来看是哪种符号出错了
  • 遇到pandas读取出现utf-8的编码问题,可以使用shell中的iconv将数据转为utf-8,iconv -f utf-8 -t utf-8 > aa,然后read_csv的时候加上参数quoting=3, engine=‘python’, error_bad_lines=False
import pandas as pd 
# 读取csv文件的接口函数,给出目前用到的参数接口, 如果使用jupyter notebook进行数据 
#分析,当忘记接口参数时,可以使用命令  ?pd.read_csv()进行参数查看 
df = pd.read_csv('test.csv', sep='\t', header='infer',
              names=None, usecols=None, prefix=None, 
              dtype=None, engine='python', skiprows=None,  nrows=None, 
              enconding='utf-8')

pandas查看统计数据的各个统计指标的方法

state = [] 
for col in df.columns: 
        state.append((col, 
        df[col].nunique(), 
        df[col].isnull().sum()/df[col].size),
        df[col].value_counts(normalize=True,dropna=False).values[0], 
        df[col].dtype)) 
df_state = pd.DataFrame(state,
        columns=['columns', 'unique_values','loss_ratio', 'the_big_ratio', 'type']) 
df_state.sort_values('loss_ratio', ascending=False)

Pandas的常用统计方法

  • 数据的常用操作: 是否在某个集合里面isin, 与&, 或|, 非~, 等于==, 大于>, 小于<,是否为空isnull,是否不为空notnull, 重复值duplicated,是否只有一种情况is_unique
  • 常用数据统计信息(数值型数据): 最大值 max , 最小值min,中位数median, 方差var,标准差std, 偏差skew,不重复的个数nunique,相关系数corr, 协方差矩阵cov, 非空值的个数count,值的个数(series)values_count,求和sum, 包括空值的大小size,移动shift,差分diff, 调用方法,代码中 axis 参数控制按行( 1 )还是按列( 0 )操作:
  • 数据的描述信息:魔鬼函数describe()
  • 各行列的数据类型:家底函数info()
  • 对数据翻转:df.T
    import pandas as pd 
    inport numpy as np 
    rng=np.random.RandomState(0) 
    df=pd.DataFrame({'key':list('ABCABC'),     
       'data1':range(6), 
       'data2':range.randint(0,10,6)}) print(df) 
    df.min(axis=0), df.max(axis=0), df.nunique(axis=0)
    df.describe() 
    df.info() 

Pandas对数据的基本操作

  • 查找:
    1.切片方式: 类似python中list的操作方法: df[3:]
    2.iloc函数操作方法: df.iloc[:, [1,2,3]], 按照行列切片的方式进行选择数据
    3.loc函数操作方法: df.loc[:, ‘列名’], 行按照切片的方式进行选择,列要按照列名进行选择
    4.按条件查找方法: df[条件], 例如查找为空的数:df[df[‘a’].isnull()],这里要注意一点的是,如果数据类型是Series格式的,它支持numpy那种数据过滤方法,例
    如:df[df>3]
    5.这里有一点就是有时数据需要输出偶数列的数据,有用到这种写法df.iloc[::2, :],其中第一个里面为::2代表的意思是从开始到最后,每隔2输出数据。
  • 删除:
    1.删除空值: df.dropna()
    2.删除以行列数据: df.drop(),其中axis=0,1用于调节按行还是按列,如果想要批量的删除行数据,可参考操作:drop_index= df[条件].index.tolist(),df =df.drop(drop_index, axis=0)
    3.按条件删除数据:df = df[条件]
  • 插入:
    1.插入一行或一列数据:df.insert()
    2.将表中数据的某个值替换为其它的值:df.replace(old, new)
  • 是否包含:
  1. df[df[‘商品名称’].str.contains(“四件套”)]
  • 排序:
  • 对DataFrame类型的数据的行列进行排序: df.sort_values([‘a’, ‘b’, ‘c’], ascendig= [False, False, True] ), 对列a,b,c按照不同的排序方式进行排序。
  • 列名的重新命名:
    1.df.rename({‘old_name’:’new_name’}, axis=1, inplace=True) 对文件的某些列进行重新命名
    2.df.columns = [‘a’, ‘b’] 直接对整个文件的列进行重新命名

Pandas对空值(NaN)的骚操作

  • 我们在实际工作以及数据挖掘的一些比赛中,数据的缺失是大概率的事,对于数据分析与数据建模时,缺失值的分析与处理对后续的结论十分重要,故下面介绍,个人目前为止在空值上遇到的一些常用骚操作。
  • 查看数据中行与列的空值比例表中为空的数据(有时候做数据分析的时候当处理完空值时,需要查看是否还存在空值)
  • 空值的填充
  • 查看一列中的空值数据,一种是df[‘a’].isnull()还有一种方法是pd.isnull(df[‘a’]),当只在一列中进行操作时建议使用第一种方法,当需要进行多列交叉操作时,建议使用第二种方法。
import pandas as pd import numpy as np # 查看各行各列的空值
1.	查看表中各行各列中得缺失比例
列:df.count(axis=0)/df.shape[0],或者 df.count(axis=0)/df.loc[:,0].size行:df.count(axis=1)/df.shape[1],或者 df.count(axis=1)/df.loc[0,:].size
2.	某列中为空的数据
df[df['clos_name'].isnull()]
# 查看表中是否还存在空值
df[df.isnull().values]  
# 操作解释,对pandas数据支持True, 和False的形式进行提取数据, 
df.isnull().values是一个与df相同行和列的array格式,因此,可以通过df[条件]  提取出为True测数据 
# 空值的填充函数df.fillna()
1.df.fillna(df.mean(), axis=0),一次对所以的空值按照列的均值进行填充
2.df.fillna({'col1':df['col1'].mean(), 'col2':[df['col2'].median()]})

Pandas对重复数据的骚操作

  • 有时候在工作中从平台数据上提取上千万行不同的数据时,由于提取的失误,可能会越到
    重复的数据,当有重复的数据时对后面的表拼接,以及groupby操作会带来麻烦,个人目前遇到的重复值的一些骚操作。
  • 删除重复值
  • 当数据量很大时,我们有时候想要知道哪些数据是重复的,好来查找重复的原因
 # 删除数据中的重复项数据 
 df.drop_duplicated() # 有subset, keep等参数可以选择,
 # 对哪些列重复数据 进行操作,保留最重复项中的哪一个 
 # 输出所以数据中重复的数据 
 df[df.duplicated()], 
 #原理和上述输出空值差不多,都是将重复的数据转为True和False来提取为True的数据

Pandas对索引以及数据的行列转换骚操作

  • 有时候在做数据分析的时候,可能数据的shape不是我们想要的形式,不要慌,神奇的行列互换骚操作帮你解忧
  • 将数据的列旋转为行:stack
  • 将数据的行旋转为列:unstack
  • 在介绍上述的两个函数之前,先得对pandas数据格式得索引有一定得了解回比较容易
    发挥这两个函数得强大功能,个人感觉可以将其理解为数据的一种Hashmap,如下图片中左边的红色框中为一层索引 key-value的不同之处,右边的为两层索引,需如要果注使意用的是行索列引转可换以函重数复不,设这置个索和引字典的中话的,会使用默认的索引(0,1,2…)这样也发挥不出开列转行函数的作用,大家如果用过pandas里面的s神奇函数pivot, 可以去看看里面的核心代码就是这两个函数的转换!
    在这里插入图片描述
    在这里插入图片描述
# 一行变多行
  df_bb = df['core_query'].str.split('#', expand=True).stack()
  df_bb = df_bb.reset_index(level=1, drop=True)
  df_bb.name = 'core'
  df = df.join(df_bb)
# 行列翻转函数 
 df = pd.DataFrame(np.arange(6).reshape((2,3)), 
             columns=pd.Index(['one', 'two', 'three'], name='number')) 
 df.insert(2, 'flag', ['x','y']) 
 df.insert(2, 'state', ['a','b']) 
 result = df.set_index(['state', 'flag'])
 # 设置多层索引  result.unstack(level=0) 
 #将第2层索引翻转为列,-1为第一层索引  
 # 这个翻转函数在进行特征工程的时候经常会用到: 
 1. 当有两层行索引的时候,如果想要去掉设置的索引改为默认的直接重设即可:
 df.reset_index()
 2. 当有两层列索引的时候,往往进行特征提取的时候,需要将多张表进行meger或者concat,这个时候表的columns都是单层的,
 这个时候可以使用ravel骚函数或者将其转为元组类型的list,将多层的表转换为单层的表:
 pair_cols= df.columns.ravel() 
 df.columns = [str(i) + '_' str(j) for i, j in pair_cols]
  • 对于列的展开,一般可以使用pivto函数
  • 一行转多行: 这里面比较好用的就是str.split(‘,’, expand=True)对分割后的数据进行扩充
   df = pd.Dataframe({'a':[1,2,3], 'b':[2,3,4], 'c':['a, b,c', 'b,c', 'd,e']})
   df = df.set_index(['a', 'b'])['c'].str.split(',', expand=True).stack().reset_index(drop=True, level=1).reset_index().rename(columns={0:'c'})

Pandas对字符串类型列的骚操作

  • pandas将字符串类型的series数据封装的已经很好了,基本字符串该有的增删查改调控等操作都有相应的函数接口,目前工作中还没有遇到那些函数解决不了的问题,以后遇到了在更新内容,当遇到字符串相关的问题时,请点击这里即可:字符串
  • 这里介绍一些比较常用的方法,这些方法在进行数据处理时,特别的方便有用,但是前提是要先变为string,具体有这些,如果实在没有的话就去上面的那个连接里面去找就ok了:
   1. 是否全是数据、字母、以及字母和数字:isdigit(),isalpha(),isalnum()
   2. 某个字符的个数:count(), 是否包含某些值:contains(),长度:len()
   3. 正则的提取:extract(), 补零操作:zfill()

Pandas对某列中不同数据类型的骚操作

  • 在实际工作中,由于数据采集的失误或者人工处理的时候不当,会造成原始数据类型经常会遇到一列数值型数据中,混杂一些字符串类型的数据,当我们要对这列数据进行统计运算时,就会报相应的错误,当遇到这样问题的时候,如果我们是在进行数据分析,需要找出具体是哪些行存在这样的问题,从而去修改原始数据的采集,而在进行数据建模或者特征提取时,需要对其进行删除或者采用均值数据进行修改,具体的骚操作方法如下:
 # 找出数值型数据中混杂的字符串数据的操作方法 
 df[pd.isnull(pd.to_numeric(df['clos1'], errors='coerce'))]
 操作解释,使用pd.to_numberic(df['clos1'], errors='coerce')函数将不是数值  型的数据赋值为NaN,
 关键在于设置参数errors,然后使用pd.isnull()函数将为NaN的数据转换为TrueFalse标签通过[]方式进行提取 
  • 征工程中经常需要对数据类型进行转换pandas中astype可以为你解忧,在nlp比赛中各列的数据差异比较大时,需要选择所需的数据类型则可以使用select_dtypes:
# 如果col1列为数值的字符串类型,可以用astype(float32)转为浮点型 
df["col1"] = df["col1"].astype(float32) 
# 如果col不是字符串类型,但是想使用字符串的运算,可以用astype(str)转为字符串类型 df["col1"] = df["col1"].astype(str) 
# 选择各列数据类型为数值型的数据,以及删除某个类型的数据 
need_type = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64'] df = df.select_dtypes(indclude=need_type) 
delete_type = ['int'] 
df= df.select_dtype(exclude=delete_type) 

Pandas之grouped最强骚操作

  • 如果要说上面介绍的一些pandas的基本操作大部分execl厉害的人也能实现,个人感觉pandas处理数据贼有魅力的地方在于它的聚合分组统计操作,这也是在数据建模中特征提取用的最多的地方,在特征提取时,经常需要提取样本分组的统计信息特征,因此,把这方面的骚操作掌握好了,不仅可以提升数据分析的质量,同时两个不同的操作在效率上也是数倍甚至几十倍的差距,在介绍groupby之前先介绍几个骚函数:
  • map : 只能对一列数据进行操作,且不能和groupby进行结合操作
  • agg: 能够与groupby结合操作,但是时一列一列的输出数据的,因此,改方法不能修改在groupby后修改数据,但是它的优点在于可以对多个列数据进行多个不同的基本统计信息(sum, count, min, max等)
  • transform: 能够与groupby结合操作,这个函数的优点就是不改变数据的形状来进行分组统计,数据即是多行多列也是一行一列进行输出的,但是虽然是多行多列的输出,不能够在transform内部调用某列进行操作,只能先选择某列在进行操作。
  • apply: 能够与groupby结合操作,输出了多行多列的数据,因此可以对数据提取某列进行操作,上述骚函数中,apply函数的功能最为强大,只有你想不到的,没有它做不到的。
# 查看groupby后内部数据结构是什么样的操作方法
1.apply: df.groupby('a').apply(lambda x: print(x))
2.agg: df.groupby('a').agg(lambda x: print(x))
3.transform: df.groupby('a').transform(lambda x: print(x))
对比分析
函数应用场景优点缺点
map单列数据进行简单操作快速功能有限,不能和groupby结合
agg提取数据各列的统计信息支持多列不同操作,快速进行数据统计不能进行列交叉操作
transfrom小量数据,不想改变数据形状不改变数据类型速度贼慢
apply一切agg解决不了的问题设计性强需要对过程结果很熟悉
  • 上述骚函数操作比较:
    单列数据处理的比较map和np.where(),当数据量很小时,随便用哪种操作影响不大,但是当数据量大的时候,就需要你在时间和空间复杂度中去选择哪个,np.where函数的执行速度会比map和apply函数快上好几倍,其是通过空间换时间的做法,因此,在使用时需要考虑电脑内存,个人暂时还没遇到使用这个函数内存崩了的情况
# 例如当我们对表中某列数据按阈值进行分0和1类别时,可用如下操作
1.df['a'] = df['a'].map(lambda x: 1 if x > 5 else 0)
2.df['a'] = np.where(df['a']>5, 1, 0)
  • 多列数据处理比较apply与np.where(), 性能比较和单列一样,有一点的需要注意的是,apply函数使用多列进行交叉操作时,需要设置参数 axis=1 ,这个很关健,千万记得在多列交叉操作时,要设置axis参数
# 例如当我们对表中将列a为空的赋值为列b的值,其它的保持不变,具体操作如下
1. df['a']=df.apply(lambda x: x['b'] if pd.isnull(x['a']) else x['a'], axis=1) 
2. df['a'] = np.where(pd.isnull(df['a']), df['b'], df['a'])
  • Groupby
    在进行特征工程时,经常需要按照一定的规则进行统计特征提取,这个gropuby操作和hadoop的mapreduce有一定的相似,groupby可以理解为对数据进行拆分再进行应用再进行合并,当理解了之前介绍的几个骚函数以及一些常用的统计函数然后如果能想象的到groupby之后的数据结构,基本就可以开始你无限的骚操作了,不管是解决产品经理的数据报告需求还是特征提取基本问题不大了,下面介绍一些个人比较喜欢用的操作:
  • 对Dataframe数据进行Groupby之后,可以直接一些简单的统计操作,基本上该有的统计函数都有封装,如果只要统计某列,只需将groupby后的数据取出那一列进行相应的操作就可以,groupby’后的属性函数请点击查看
 # 按照列a数据分组统计其它列的均值 
   df.groupby('a').mean() 
 # 按照列a数据分组统计其列b的均值 
   df.groupby('a')['b'].mean()
  • 这里需要注意的一个问题是当索引(index)为时间戳(datetime)时,如果时间中有重复的值或者没有,都可以通过参数level来对groupby进行求和,非常的方便:
df = pd.DataFrame({'values':np.range(5)},
      index=[datetime(2012, 1, 1), datetime(2012,1,1),
      datetime(2012, 1, 2), datetime(2012, 1, 2)])
df_mean = df.groupby(level=0).mean()
  • 一个基本操作的优雅性与效率
df = pd.DataFrame({'key1':['a', 'a', 'b', 'b', 'a'],
                    'key2':['one', 'two', 'one', 'two', 'onw'],  'data1':np.random.randn(5), 
                    'data2':np.random.randn(5)}) 
# 对上述的表按照key1,key2分组统计data1的均值的两种写法:
1.df['data1'].groupby([df['key1'], df['key2']]).count()
2.df.groupby(['key1', 'key2'])['data1'].count()
经过对上述的两段代码进行性能测试可以发现,第二段代码相对于第一段代码性能
更优,在执行的时间复杂度上有一定的优势。第一段代码可以解释为,取df表中
data1字段按照key1,key2字段进行统计,而第二段代码是先对df表中的key1,
key2字段进行分组,然后取data1字段进行统计,个人更习惯于第二段代码不仅更好理解,同时写起来更加的优雅。 
  • groupby结合上述几个骚函数进行分组统计信息的使用总结,如果能使用lambda表达式完成的,尽量使用lambda表达式而不去写一个函数
 按照列a数据分组统计其列b的均值,求和并修改名字且名字前缀为hello_
 df.groupby('a'['b'].agg({'b_mean':'mean','b_sum':'sum'}).add_prefix('hello_') 
   其中add_prefix属性用于给列添加前缀,如果是要对行添加前缀则需要使用apply函数  
 # 将groupby与apply结合起来进行自定义函数设计(需要传入参数的写法),不要传入 
 # 参数使用lambda表达式即可完成 
 1. 按照列a进行groupby取列b中值最大的n个数
 def the_top_values(data, n=3, cols_name='b'):
   return data.sort_values('b')[:n] 
 df.groupby('a').apply(the_top_values, n=3, clos_name='b
  • 在进行特征工程时,我们经常需要对一种重要的数值型数据进行分箱操作,因为分箱后能大幅度提升模型的拟合效果以及过拟合的危险,特征工程中对于数值型数据进行分箱/离散化操作以及操作后统计特征的优雅骚写法:
  • 对于分箱操作,在处理连续数据的特征工程时经常会用到,特别是在用户评分模型里面用的贼多,但是使用最优分箱进行数值离散化比较多,由于本文不是重点介绍特征工程的,后续会写相关的文档,因此,这里不重点进行介绍,读者如果感兴趣可以去查阅相关的知识,也可以关注我的公众号和微信获取code和data。
 例如想要对数值型数据a分成4个箱子,然后分别统计每个箱子里面b列的最大值,均值以及个数
 def help_static(group):
    return {'min':group.max(), 'max':group.mean(),'count':group.count()} 
 bins_1 = pd.cut(df['a'], 4, labels=False) #为等距分箱 
 bins_2 = pd.qcut(df['a'], 4, labels=False) #等频分箱 
 temp = df['b'].groupby(bins).apply(help_static).unstack()  
 操作介绍,首先定义箱子规则bins,然后取df['b']按照箱子分组统计每个箱子  面b的统计特征。 
 然后再将temp与df进行拼接,就可以得到每个箱子里面的统计特
  • 分组对空值NaN进行填充
# 对于空值,在进行特征工程时,如果空值缺比较多的时候,常将这一列删除,如果缺的20%左右,要不就不对其进行处理,
#将它当做一种情况看待,或者对空值进行填充,为了更加的使填充值得误差尽可能得小,如果一个id有多条样本,则可以对其进行分组后在填充,不然就用整体分布值进行填充。 
# 对列a分组后对列b中的空值用用中位数填充 
fuc_nan = lambda x: x.fillna(x.median()) 
df.groupby('a')['b'].apply(fuc_nan).reset_index().drop('level_1', axis=1)
 # 对某列数据按照线性或者多项式的方法进行缺失数据的填充 
func_nan = lambda x: x.interpolate() 
df.groupby('a').['b'].apply(fuc_nan).reset_index().drop('level_1', axis=1) 
  • agg对数值型列进行多方式统计, 这里需要注意一点的就是,通过agg进行一列的多统计特征的时候,最后的输出结果是多个multiindex的columns,这个时候需要对其进行一下列名转换
 df = df.groupby('ip').agg({
                             'a' : ['sum', 'max', 'min'],
                             'b': ['sum', 'max', 'min'],
                             'c': lambda x: len(x)
                          })
 df.columns = [i[0] + '_' + i[1] for i in df.columns]
 df = df.reset_index()
  • pandas进行数据分析与特征提取的时候,groupby加上apply操作拥有无限的可能,只有你不会优雅用的,没有操作不出来的

Pandas多个文件的拼接骚操作

  • 在进行数据分析与特征工程时,经常需要将多张表进行各种拼接连接,利用pandas进行表连接与sql写法差不多,总结起来就是按行还是按列连接,选一个字段,所以这方面美啥太多问题,只要注意几个地方,就问题不大
    其中文件融合的操作中,有几个参数用的比较少,但是经常可以完成很骚的操作:
    1.validate:用于验证两张表融合字段是否存在相同的值(one-one, one-many, many-one, many-many), 代表的是两张表融合字段是否必须独一无二。
    2.suffixes:用于对两种表中相同的字段调加不同的字段说明。
    将两张表按照某字段进行左右内外连接:pd.merge()
    不按照字段将表进行按行按列拼接:pd.concat()
# 将表trian和表test按照列'a'进行左连接
1.train.merge(test, on='key', how='left', validate='one-one')
2.pd.merge(train, test, on='key', how='left')
个人比较喜欢用第一种写法,看上去感觉漂亮一点,性能上没啥区别,看个人喜爱性能上没啥差别,个人比较喜欢用第一种,看上去简洁一点,  
但是第二种貌似容易理解一点, 看个人喜好 
pd.concat([train, test], axis=1, ignore_index=True) 
# 对表df1、df2按照两个不同的字段进行左右连接,并将两张表中重叠的字段  # 赋值为不同的列名 
df1.merge(df2, left_on='lkey', right_on='rkey',suffixes=('_left', '_right'))

Pandas对时间的骚操作

  • 如果要对时间序列相关的数据进行数据分析与挖掘,而时间做为一种特殊的数据格式,不同于字符串,整型的数据格式,但是它们之间又是有一定的联系,在介绍pandas时间处理的方法之前,首先介绍一下关于python的时间处理的相关知识以及常用的包:
  • 首先对于时间维度信息在进行数据分析以及特征工程的时候经常挖掘分析的时间维度信息如下:年、月、日、是否周末、是否节假日、一年中的第几周、一周中的第几天、距离节假日的时间距离、年月日结合相关业务操作的时间范围、针对业务特征日期的处理
  • 因此,对于上述时间维度的数据分析和挖掘,朝天椒将自己在时间维度上的一些处理骚手段总结如下:
  • python处理时间的常用包datetime
  • datetime数据格式为:datetime(year,month,day,hour,minute,second, microsecond), 然后可以通过相关的api得到一个时间戳的各个小字段。还有对于datetime类型的时间戳二者之间可以进行相互加,减等操作:
# 两个时间段的差值,可以通过api转换为天、分、秒等 
 time_range = datetime(2011, 1, 7) - datetime(2011, 1, 1) 
 time_range.day 
 # 在一个时间的基础上增加多少天的时间 
 time = datetime(2011, 1, 1) + datetime.timedelta(days=6) 
  • datetime格式的时间数据可以根据自己的需求进行修改,常用的两个函数为:strftime(),这个函数针对的格式为datetime类型的数据,strptime(),是将string类型的数据转化为datetime类型的时间格式数据, 因此输入时一个string, 有时间工作中经常使用二者相互进行转换。
 from datetime import datetime 
 now = datetime.now() 
 # 获取年、月、日等基本的时间属性 
 print(now.day now.year, now.month) 
 # 时间的格式化操作 
1.对datetime格式的时间数据进行格式转换为字符串形式
now = now.strftime('%Y-%m-%d %H:%M%S') # 这个可以根据需求进行取舍还有其中的时间连接形式也可以随意进行设置:'%Y/%m/%d'等形式
其中%F对应:'%Y-%m-%d‘, %D:'%Y/%m/%d', %w:第几周, %W:每年的第几周
2.将字符串类型时间类型转换为datetime形式的时间格式
nows = datetime.strptime(now, '%Y-%m-%d')
# 注意这里的时间连接格式要和字符串保持一致
  • 虽然strptime可以将string数据转换为datetime数据格式,但是每次都需要定义数据的格式,为了增加开发的速度可以使用dateutil.parser来一次性处理
# 通过parse一次性将string数据转换为datetime时间格式
from dateutil.parser import parse 
now = datetime.now().strftime('%Y/%m%d')  now = parse(now) 
  • pandas对时间处理的常用几个操作,以下的pd代表的时series数据格式:
    1.时间的标准化: pd.to_datetime(), 或者pd.Timestamp() , 其中pandas中的对应的datetime数据格式就是通过上面这两个函数进行转换的,当对时间转换为格式后,就可以对时间进行处理,以及相关的api的调用,常用的api和datetime基本没有什么偏差。
    2.时间范围: pd.date_range()
    3.时间频率采样操作: pd.resample()
    4.时间的移动: pd.shift()
  • 对于时间戳为索引的数据可以通过正常的pandas的index切片方式,也可以通过一些函数进行
1. 正常的切片的方式
# 对于TimeStamp的时间格式数据作为dataframe数据的索引,
# 由于timeseries时series的一个子类,因此,可以通过相index的方式进行索引, 
# 并且由于时间的特殊性,可以通过直接输入年或者年月的方式进行数据的索引 
df_time = pd.DataFrame({'values':np.random.randn(100)}, 
   index=pd.date_range('2018-12-01', periods=100))  df_time['2018'] # 取2018的数据 
df_time['2018-12'] # 取2018年12月份的数据 
df_time['2018-12-01':'2018-12-31'] # 取一段时间窗口的数据
2. 通过属性函数的方式
df_time.to_period('M') # 将datetime数据格式转换为年-月
df_time.to_period('M').to_timestamp() # 将不全的datetime数据格式补全  
  • pd.date_range(): 该函数主要参数有开始(start)、结束时间(end),多长时间范围periods,以及按什么频率(freq)方式进行时间移动,通过该函数得到的是一个pandas个数的datetime数据格式,因此可以直接使用datetime的相关属性函数对数据进行相关的操作
 # 默认按天进行移动,可以按月,年等,还可以具体多少天进行移动 
 tmp = pd.date_range(start='2018-01-01', periods=10, frep='3M') 
 tmp = tmp.strftime('%F').tolist()
  • pd.resample():神奇的对时间进行采样的函数, 该函数除了采样功能外,还可以进行一些关于时间的统计, 主要有加、减、乘等操作, 相关于一种快速的对时间按年月日等进行分组操作, 介绍几个重要的参数:
    1.colsed:如果为left就是将时间区间分为多少个区间,每个区间都是左闭右开,如果为right则是左开右闭
    2.label:如果就是选用区间的哪边作为结果的索引值
    3.rule:按什么方式进行采样,’3D’:三天
    4.how:通过什么样的方式, 这个可以通过参数控制, 也可以通过属性函数的写法,特别注意的一个是, 金融中有个函数可以对其进行快速的计算最大、最小值等’ohlc’
    5.fill_method:对缺失值进行填充的方法, ‘bfill’, 等
# 降采样的骚操作 
 import pandas as pd 
 df = pd.DataFrame({'values':np.arange(12)}, 
        index=pd.date_range('2018-01-01', periods=12)) 
 df_time = df.resample('3D', colsed='left').sum() 
 # df_time = df.resample('3D', colsed='left', how='sum') 
 df_time2 = df.resample('3D', colsed='right').sum() 
 # 升采样的骚操作 
 df = pd.DataFrame({'values':np.range(2)}, 
        index=pd.date_range('2018-01-01', periods=2)) 
 df_time = df.resample('6H').asfreq() #将时间按没6H的方式补全的方法, 
 df_time = df.resample('6H').ffill() #bfill为向后,ffill为向前 
  • 骚一:有时候工作工作中经常需要处理时间相关的数据,但是有时候数据的时间不连续,因此,我们为了查看数据是否不缺失日期,就可以使用resample进行骚操作:
# 查看数据是否时间不连续 
df = pd.DataFrame({'values':np.arange(12)}, 
   index=pd.date_range('2018-01-01', periods=12, freq='2D'))
tmp = df.resample('D').asfreq() 
tmp = tmp[tmp['values'].isnull()] 
  • 当索引为时间戳数据格式时,我们可以通过shift按照更加具体的多少天、小时、分钟来对数据进行平滑
df = pd.DataFrame({'values':np.arange(12)}, 
   index=pd.date_range('2018-01-01', periods=12, freq='2D'))
df = df.shift(freq='90T') # 对数据每隔90分钟进行一次平移 

Pandas的高效性能骚函数

  • pandas进行列的查询,经常会常使用df[条件]的方式,但是这种写法的性能不是很高, pandas基于Numexpr实现了两个高性能的函数,用于数据查询过滤query()和数据列值修改与增加新列eval(),这两个函数通过传入列名str的方式进行操作:
# 过滤表中列a的值大于3且列b的值小于5的数据的两种写法
1.	df[(df['a']>3) & (df['b']<5)]
2.	df.query('a>3 and b<5')
上述两种写法第二种写法的在速度可内存使用上远优于第一种写法,
其中第一个需要经历两个判断赋值和与操作,而第二个直接通过Numerxpr进行操作,而且第二种个人感觉更加的优美 
# 将表中列a和列b的数据相加且赋值为c,以及将列c的值加1的两种写法
1.	df['c'] = df['a'] + df['b']
2.	df.eval('c=a+b', inplace=True)
1.	df['c'] = df['c'] + 1
2.	df.eval('c+1', inplace=True)
其中上述的两组对比第二种写法相对于第一种在性能上直接成碾压的模式,
且写法更加的优美,所以建议大家使用在对表进行过滤修改时使用query和eval进行处理

Pandas特征工程中的几个骚函数

  • 下面介绍一个在进行特征工程时pandas常用的几个骚函数
  • pd.get_dummies:有时在进行特征工程时,当某列的值的种类不是大于20且不同的值的label差异性比较大时,像LR算法则一定需要将其进行one-hot编码,即使使用像xgb/gbm这样的算法,进行one-hot编码也会在拟合效果上有想不到的提升,当然如果对算法的速度有特别的要求,则需要去折中选择。
 # 对表列a中不同的值进行one-hot编码并添加列名前缀'a_'
 pd.get_dummies(df['a'], dummy_na=True).add_predix('a_')
  • pd.factorize: 这个函数主要对数据进行编码操作的,将类别数据转换为相关数值型数据
    cate, value = pd.factorize(df['a'])
  • pd.pivot_table:这个函数在时序回归的时候会用的比较多,可以快速的将原始数据转换为所需的时序形式,还有表不是你所需要的格式的时候,你将感受到这个函数的魅
    力,可以通过它来实现你想要的,其内部的原理就是上面介绍过的unstack和stack函数
 # 将表转为双层索引a,b列名为c且没列值为列d的和 
 df = pd.DataFrame({"a": ["foo", "foo", "foo", "foo", "foo",
                    "bar", "bar", "bar", "bar"], 
                    "b": ["one", "one", "one", "two", "two", 
                    "one", "one", "two", "two"], 
                    "c": ["small", "large", "large", "small",
                     "small", "large", "small", "small", "large"], 
   "d": [1, 2, 3, 4, 5, 6, 7, 8, 9]}) 
 pivot_table(df, values='d', index=['a', 'b'], 
 columns=['c'], aggfunc=np.sum ) 
  • diff(),在时序问题中,有时需要提取不同时间的差值特征,比如说前一天和后一天的差值,这是可以采用diff方法,其用法如下:
# 瞬间移动大法diff操作,可以通过preiods和axis参数来控制移动的大小  
df = pd.DataFrame({'a': [1, 2, 3, 4, 5, 6], 
                    'b': [1, 1, 2, 3, 5, 8], 
                    'c': [1, 4, 9, 16, 25, 36]})
# axis表示按行还是按列相减,periods表示相减所隔的天数  
df.diff(axis=1, periods=1) 
  • quantile(), 分位数计算方法
DataFrame.quantile(q=0.5, axis=0, numeric_only=True, interpolation=”linear”) 参数含义  
q: 分位数,默认为0.5即中位数  
求解步骤:
1.	先求出q分位数所在原数组的位置,pos=1+(n-1)*q,该位置位于两个数据i,j之间
2.	pos的小数部分记作fraction
3.	求q分位数的值v=i+(j - i)fraction*

df = pd.DataFrame(np.array([[1, 1], [2, 10], [3, 100], [4, 100]]))  print(df.quantile(0.1) 
 # 输出 
 a  1.3 
 b  3.7 
 Name:0.1, dtype: float64 
 # 计算过程 
 计算位置pos=1+(4-1)*0.1=1.3,可知该分位数位于第一个数据与第二个数据之间  fraction取pos的小数部分0.3 
 q分位数值v=1+(2-1)*0.3=1.31+(10-1)*0.3=3.7 
  • rank: 在特征工程时,对于数值性特征,离散化的可能性又不大,同时这列数据的大小与label也一定的线性相关性,往往可以对该列提取排序特征,并且实践中该特征带来的效果往往还不错,因此rank就可以很容易的实现我们的想法:
# 对数值型数据列a提取其对应的排序特征 
 df['rank'] = df['a'].rank(method='min') 
 # 其中该函数的重要参数就是method,用于选择当数值一样的时候,排序值使用哪个 
  • rolling: 这个函数在时间序列回归问题的特征提取中会用的到,对于时序问题,我们经常采用移动滑窗的方式进行特征提取,这种方式提取特征后效果很大幅度的提升,当然这个窗口大小的设计以及窗口开始与结束时间的选择特别的重要,现在很多时序回归方面的数据挖掘比赛top1花费大量功夫在窗口的设计上,后续会在公众号上更新该方面的优质代码解读与数据,这里不进行过多的描述
  • 特别需要注意的是,如果想要观察两个时间序列的相关系数或者相关性的变化情况,可以通过rolling加上corr()的操作来进行画图观看:
# 按照窗口为5的大小提取label的均值
df['label'].rolling(5).mean() 
这个rolling函数只是选定窗口的作用,后面可以连接各种统计函数, 
例如均值,方差,相关系数、协方差,中位数等,用于提取这个窗口内统计信息。
 # 两个时间序列的相关系数的操作方法
  • pd.ewma()指数加权函数, 通过一个衰减因子来控制权重的大小
df = pd.ewma(df.values, span=60)

pandas中内存性能优化

  • replace: 这个函数是用来对dataframe数据结果中的某些数据进行替换,通常将的用法为df[‘clos_name’].repalce(cols_dict), 但是这个函数特征的损耗内存,一旦数据量比较大的时候往往会出现相关的内存溢出的问题,一种方法就是通过map的方式进行处理,但是map需要所有的数据全在字典里面,不然会将不存在的数值赋值为空,其它一个方式就是用时间来进行换取,具体如下
    # 换算相关的列的值
    cate_dict = {2: 22, 3:33}
    df_train['cols'] = [cate_dict.get(x, x) for x in df_train['cols']]

pandas中melt的用法

  • 数据分析的时候经常要把宽数据—>>长数据,有点像你们用excel 做透视跟逆透视的过程, 基本的想法就是将多列合并成一列, 具体的用法如下:
  d = {'col1': ['a','a','a','b','b'], 'col2': [2,2,2,2,2],'col3':['c','c','c','d','d']}
  df = pd.DataFrame(data=d)
  # 设置 id_vars=['col2'] ,则不需要转换的列是col2 。所以col1跟col3 合并成了一列
  pd.melt(df,id_vars=['col2'])

pandas高效连接数据库

  • 在连接数据库时,可以将数据转换为dataframe格式,可以方便快速的连接数据库,具体如下:
# 由于python2和python3使用数据库有较大的差异,在python3中可以使用如下方法:
import pymysql 
from sqlalchemy import create_engine

# 创建一个数据库连接引擎
def connet_mysql(host='0.0.0.0',
                 port=5474, user='tanyunfei', password='tyf1994127', db='b2brec', 
                 ):
    """
        连接mysql代码
    """
    try:
        utf_flag = "charset=utf8"
        engine = create_engine(f"mysql+pymysql://{user}:{password}@{host}:{port}/{db}?{utf_flag}")
    except Exception as e:
        print("the error is :", e)
    return engine

# 对数据进行写入
 # 导入数据去mysql
engine = connet_mysql()
with engine.begin() as conn:
    df_res.to_sql(name=table_name, con=conn, if_exists=update_flag, index=False)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

财天椒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值