赞
踩
update:190705
某列。
aaa = df['a'] = df.a = df.get('a')
某行
df[0:100],返回前100行。 直接括号[]里面写条件,优先级似乎是先匹配列,再匹配行。容易出问题,不推荐这种写法。
等价于 df.ix[0:100] 。
不等价于 df.loc[0:100]。 使用loc会包含第101行,即index=100的行,即最后一行,总共返回0~100,计101行。
df.irow(i) ,i行,不常用,不推荐。
df.iloc[i] , i行,返回series。
df.iloc[i:j],(i,j-1)行,返回dataframe。
某行某列
按offset df.iat[0,0],第一行第一列 #iat是特化的单元素访问方法,如果只需要对单元素进行取值、赋值的操作,用起来就很舒服。
df.loc[0,[0]]
df.ix[0,[0]]
按name df.loc['hello',['world']] ,'hello'行,'world'列。 特色就是目标列需要用一个list来装。
df.at[0,'world'],at理论上只支持name访问单个元素。但是由于我们日常使用时,不定义行的index时,默认的行name其实就是012345这些数字。
- #补充一下最常用的loc
- a=df.loc[0,['cre_time']]
- b=df.loc[0,'cre_time']
-
- print(type(a))
- print(type(b))
-
- #输出
- <class 'pandas.core.series.Series'>
- <class 'pandas._libs.tslibs.timestamps.Timestamp'>
-
- #可以看出,loc在访问单列时,若不加括号,效果等同于.at
多行多列
使用ix,对列同时支持name和offset。
N行N列 df.ix[0:3,[0,1,2]] 前3行和前3列。
N行N列 df.ix['one':'two',[0,1] 使用index的name代替offset。
N行1列 df.ix[[1, 2], [0]]
1行N列 df.ix[0,[2,3,4]]
列比较蠢,需要多一个括号来装,还不支持冒号slice语法。
使用loc,对列只能使用列name。
N行N列 df.loc[0:3,['hello','world']]
使用iloc,对列只能使用offset。
N行N列 df.iloc[0:3,[0,1,2]]
总结:
at与iat只能取单个。
ix与loc俩兄弟可以取多行,多行包括单行。
loc与iloc,这俩兄弟取多行时,会返回最后一行。而ix不会,直接使用[]也不会。
at与iat的关系,同loc与iloc。不加i表示只支持用name,加了i表示只能用offset(或者说以相对位置作为index)。
取行,支持 【单行,枚举多行,slice】 3种操作。
取列,仅支持【单列,枚举多列】2种操作。
无论什么函数,都不允许对列进行slice操作。
注意1:
用多行多列的函数访问单个元素时,容易各种报错。
举例,df.iloc[0,[0]],访问某个单元格,但是返回是dataframe或者series类型的,某些对单个元素才合法的操作(e.g.赋值),此时不合法。
因此,访问某个单个元素时,使用 df.at 与 df.iat 是好习惯。
- #报错x:df.loc[0,['happy']] = 'hello'
- #推荐√:df.iat[0,0] = 'hello'
- #不推荐√: df.loc[0,'happy'] = 'hello'
哭着回来提醒一下,iat的处理速度不知道比loc高到哪里去了。
处理1200w行的数据,用loc告诉我需要100小时,iat变成9分钟,这差距。
注意2:
用name访问单行/单列时,若索引指向的行/列不存在,则新建一个。
e.g. 我们常用 df['aa']=[1,2,3],本质上就是df['aa']指向了一个不存在的列,则新建之,并用传入的值来初始化。
很实用的特性。详见下文“逐行逐列添加数据”。
先查重
df.duplicated()
返回一系列的bool值,表示第i行是否为重复行。
#想按每列去重,好像可以设置axis,待证。
确认有重复值存在了,再删除重复项
- #全部列进行比较,全部列的值都相同的2行才判定重复
- df.drop_duplicates()
-
- #只对指定列进行比较
- df.drop_duplicates(['happy'])
-
- #默认的方向是自前向后,所以上数下第二行开始被判定为重复丢弃。
- #可以手动更改方向,保留last one,删除former one
- df.drop_duplicates(['happy'],keep='last',inplace=True)
-
- #inplace生效时原地修改,默认为False
判断存在
- df.isnull().sum()
- df.notnull()
填充0,或者丢弃
- df['happy']=df['happy'].fillna(0)
- df['happy']=df['happy'].dropna()
-
- #也可以不指定列,直接丢弃全部含空缺值的行
- df=df.dropna()
比较特殊一点的是,用另外一列的值去填na。
df['happy']=df['happy'].fillna(df['wow'])
- #暴力全修改,注意与现存的数量必须匹配
- df.columns=['aa','bb','cc']
-
- #rename传入字典,把cc列改为CC列
- df = df.rename(columns={'cc':'CC'}) #有inplace参数
df["Status"] = df["Status"].astype("category")
备注:虽然astype()函数有inplace参数,但是在我的环境内测试,即使inplace=True也无法成功更改dtype。
不知是否为bug。(pandas == 0.23.4,numpy==1.15.4)
出于这个原因,推荐使用 = 赋值的形式。
df['term']=df['term'].map(str.strip)
本质上是pd.Series.map()函数的一个特殊应用场景。
关于map请看 《pandas map与apply》
- 大写
- df['term']=df['term'].map(str.upper)
- 小写
- df['term']=df['term'].map(str.lower)
- 首字母大写
- df['term']=df['term'].map(str.title)
同上,map的应用。
- df_new = df.set_index('new_index_col')
-
- df_new = df.set_index(['col1','col2'])
注意,这个操作可以用.reset_index(drop=False) 回溯。
完美回溯,无损回溯!
借用这个回溯功能,可以引出下一个非常实用的性能。
主要利用到.reset_index(drop=False)的能力。
- g =df.groupby(['id','time'])
- new_df = pd.DataFrame(g.size(),columns=['count'])
- new_df = ad_up.reset_index(drop=False)
-
- #得到一个新表
- 'id','time','count'
用合法的语句访问单行/单列时,若索引指向的行/列不存在,则新建一个。
实例
- #预定义列,希望一行一行的添加进来
- df = pd.DataFrame(columns=['aa','bb'])
-
- names= ['peter','david']
- for i in range(2):
- key = boys[i]
- #此处我们用.loc访问index=key的一整行(省略列索引即可达到此效果)
- df.loc[key] = [i,i+1]
- #但由于index=key的这行不存在,所以会新建'peter'行,.etc
-
- print(df)
打印结果
aa bb peter 0 1 david 1 2
可是日常需求中,一般人名需要单独作为一列。使用上面说的.reset_index()即可
df= df.reset_index(drop=False)
index aa bb 0 peter 0 1 1 david 1 2
改columns就很简单了。
预定义行,希望一列一列地加数据同理。
注意:
当df为空时,实际上第0行是不存在的,所以使用df.iloc[0] = [....]添加第0行,会报错。single position index is out of bound.
也就是说,这种方法只对使用name形式的访问生效,即df.loc[0]。 此时的0并非offset,而是某行的name。
同理,创建不存在的列 df['hello'] = [...],同样是以列名进行访问,所以能够生效。
- #想拆分df['target']这列
- #保留原来的index需要专门指定index
- new_df = pd.DataFrame(
- [x.split('-') for x in df.target],
- columns=['people','age'],index=df.index)
-
- #按左表的行索引合并
- df = pd.merge(df,new_df,left_index=True)
- bins = [0, 5, 10, 15, 20]
- level_name = ['A', 'B', 'C', 'D']
- df['level'] = pd.cut(df['value'], bins, labels=level_name)
-
- #依次对df['value']列进行比较
- #如果落在左闭右开区间内[,)
- #则匹配对应的level_name
注意,虽然在python里面字符串是可以比大小的,但是实测dataframe的某列若为字符串形式的,哪怕是字符串型的数字,应用pandas.cut函数也会报奇怪的错误。
如果是字符串数字,请自行处理,或者自定义一个cut。
pd.cut()返回的series,类型是category,枚举型。
删除行,drop()
- data = data.drop([3,4])
- data.drop([3,4],inplace=True)
删除列,del(),pop()
- del data['age']
- data
-
-
- _ = data.pop('age') #pop后原df不保留该列
-
-
- #也可以用drop删除列
- df.drop(columns=['hello','world'], axis=1, inplace=True)
result = pd.merge(df1, df2, on='uid', how='left/right/inner/outer’,shuffixes=('_x','_y')
tips:
如果2个表存在重复的列名,就会由shuffixes来为重复列名添加后缀,这样很麻烦。
我们需要手动删除一列,再对另一列改名。
其实有避免这种重复劳动的解决方案。
- #排除重复列名,再进行merge
-
- def single_merge(df1,df2,on='uid',how='left'):
- s1 = set(df1.columns)
- s2 = set(df2.columns)
- s3 = s2-(s1&s2)
- s3.add(on)
- cols_to_use = list(s3)
-
- res = pd.merge(df1,df2[cols_to_use],on=on,how=how)
- return res
-
-
-
- train_csv = single_merge(train_csv,listing_info,on='listing_id',how='left')
series和dataframe都有
.add
.sub
.multiple
.div
注意1:
如果是add或者sub另外一个series,则要考虑行index对齐的问题,若两个series的index完全不一致,则全部nan。被这个坑了。
使用前可以将其中之一reset_index(drop=True),或者将被加/减数list()一下。
注意2:
跟numpy里面的四则运算的函数名字区别!
np.add(a1,a2)
np.sub(a1,a2)
np.multiply(a1,a2) ,注意numpy的乘法是multiply!
np.divide(a1,a2) #python3中的np.divide == np.true_divide,且不能用 a=np.array([1,2,3]) ,a.divide()会报不存在
还有一些np.abs()之类的隐藏坑,pandas里面是没有的貌似。
时间戳:定义为1970年之后的秒数
- import time,datetime
-
- #1970年秒数转time结构体
- time_struct = time.localtime(1462482700)
- print(time_struct)
- #time.struct_time(tm_year=2016, tm_mon=5, tm_mday=6, tm_hour=5, tm_min=11, tm_sec=40, tm_wday=4, tm_yday=127, tm_isdst=0)
- #这是个time结构体,可以直接访问 .tm_year等属性获取对应值
-
-
- #结构体转字符串
- time_string = time.strftime("%Y-%m-%d %H:%M:%S", time_struct)
- print(time_string)
- #2016-05-06 05:11:40
-
-
- #字符串转datetime对象
- datetime_obj = datetime.datetime.strptime(timeDateStr,"%Y-%m-%d %H:%M:%S")
- print(datetime_obj)
- print(type(datetime_obj))
- #2016-05-06 05:11:40
- #<class 'datetime.datetime'>
- #你别看打印出来跟string没什么区别,类型已经改了。
-
- #datetime对象转time结构体
- struct_time = datetime_obj.timetuple()
-
- #time结构体转时间戳 (秒数)
- time_stamp = time.mktime(struct_time)
-
- #datetime对象转字符串
- time_string = datetime.datetime.strftime(datetime_obj,"%Y-%m-%d %H:%M:%S")
- #等价于
- time_string = datetime_obj.strftime("%Y-%m-%d %H:%M:%S")

直接取数
- #datetime对象
- year = datetime_obj.year
- month = datetime_obj.month
- day = datetime_obj.day
- hour = datetime_obj.hour
- minute = datetime_obj.minute
- second = datetime_obj.second
-
-
- #time_struct同理,直接.访问属性即可。
补充:datetime对象相减会返回timedelta类的对象。
- start_time ='20190305051140'
- end_time ='20190308051145'
-
- start_obj = datetime.datetime.strptime(start_time,"%Y%m%d%H%M%S")
- end_obj = datetime.datetime.strptime(end_time,"%Y%m%d%H%M%S")
-
- i_am_time_delta = end_obj - start_obj
-
- print(i_am_time_delta)
- # 3 day, 00:00:00
-
- #timedelta比较特殊一点
- #其内部只储存days,seconds,microseconds
-
- days = i_am_time_delta.days
- seconds = i_am_time_delta.seconds
-
- #虽然timedelta打印出来是 3 day, 00:00:00 ,这样子的。
- #但后面的时分秒是用seconds算出来的
- #内部并不存在 .hour 和 .minute 属性。
-
-
- #但在构造函数里面,我们却可以指定hours 和 minutes !
-
- time_delta_1 = datetime.timedelta(days = 1) #set .days to 1
-
- time_delta_2 = datetime.timedelta(hours = 0.5)
- print(time_delta_2.seconds)
- #半个小时,30分钟,1800秒。 打印出来刚好是1800
-
- time_delta_3 = datetime.timedelta(hours = 1, minutes = 1 ,seconds = 1 )
- print(time_delta_3.seconds)
- #得到3600+60+1=3661秒
-
-
- #所以说,如果想对一个datetime类对象,加个1天,就可以
- time_obj = time_obj + datetime.timedelta(days = 1)
- #返回的类型,还是datetime.datetime类对象
- #减一天,加一个小时,以此类推

#本质上跟c里的时间处理差不多。《C++中日期处理总结》
#想看更多关于时间的api推荐这篇:http://www.cnblogs.com/lhj588/archive/2012/04/23/2466653.html
自带函数
- import pandas as pd
-
- pd.to_datetime()
-
- #将形如xx的字符串
- #2018-02-04 08:28:15
- #转为datetime类
-
- df = pd.DataFrame({'id':['aa','bb','cc'],
- 'time':['2018-02-04 08:28:15',
- '2018-02-04 09:30:11',
- '2018-02-04 10:31:23']})
-
- df['datetime'] = pd.to_datetime(df['time'])
-
- #df.dtypes
- #
-
-
- #得到datetime类之后,可以用.dt直接访问属性,拿到月日
- df['month'] = df['datetime'].dt.month
- df['mday'] = df['datetime'].dt.day
-
- #此外,官方示例还提供了
- #s.dt.hour
- #s.dt.second
- #s.dt.quarter
- #s.dt.date #2018-02-04
-
-
-

读取csv文件时,自动解析日期
- import pandas as pd
-
- #将time这一列解析为datetime
- df = pd.read_csv('mydata.csv',header=0,date_parser = 'time')
-
-
- #多列
- df = pd.read_csv('mydata.csv', parse_dates=['auditing_date', 'due_date', 'repay_date'])
小技巧:
由于数字运算比字符串运算更快捷。
所以用数字存储month和day,然后
month_day=month*100+day
这样得到的数字直接表示日期。比如1月5号=105, 12月31日=1231。
- import pandas as pd
-
-
- memory = df.memory_usage().sum() / 1024 ** 3 #单位GB
- print('Data occupies {} GB memory.'.format(memory))
pandas:对dataframe进行groupby后求众数mode
df.to_csv('a.csv',header=True)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。