Tag Archives: pandas

Hello World

pandas日期的高效处理方法

每次碰到dataframe里有datetime字段,都会感觉很麻烦,明明知道pandas里有很多批量处理的方法,但一个datetime改字符串日期,之前试过过很多写法,都不成功,又不甘心用低效的apply,于是动个小聪明,直接前置到提取数据的sql里:SUBSTR(created,1,10) day ^_^
今天又碰到这类问题,数据来源十几张表,而且是之前现成的公共模块,不好随便改sql,无奈找pandas里的处理方法,这次居然轻而易举找到了:
df['day'] = df['created'].dt.strftime(‘%Y-%m-%d’)
嗯,其实就这么简简单单一行代码~~继而好奇进一步研究了这里面的“dt”对象,除了搭配strftime()做日期格式化,还可以直接dt.year/dt.month/dt/time/dt.quarter/dt.weekday,还有dt.dayofyear/dt.weekofyear,哈哈,没错,可以理解成里面藏了一个map
除了这些,还可以类似这么用:(df['日期1'] – df['日期2']).dt.days、(df['日期1'] – df['日期2']).dt.total_seconds()

Hello World

dataframe拆字段

比如,数据源某字段格式:“13/34”,来表示门店每日的新老用户数,现在要把它拆成两个字段,以便下一步分析使用。当然,我们首先肯定想到可以apply,可是如果数据量太大,apply就会变得很慢。那么,有没有更快的办法?
当然有了,毕竟pandas总不会让我们失望
df['new'], df['old'] = df['user_count'].str.split(‘/’, 1).str
简简单单一行代码就完成了

———
over, 参考:https://zhuanlan.zhihu.com/p/343895339

Hello World

pandas之pivot_table的使用

pivot_table是将多行数据转成多列的一个函数,作用类似exce的透视表,这里咱们先看一下它的实际处理效果:

再看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
#构建测试数据
df = pd.DataFrame({
	'品类': ['苹果', '橘子', '香蕉', '橘子', '香蕉', '橘子'],
	'日期': ['2023-10-21', '2023-10-21', '2023-10-21', '2023-10-22', '2023-10-23','2023-10-23'],
	'销量': [13, 24, 25, 27, 19, 21]
	},
	columns=['品类', '日期', '销量']
)
print(df)
#日期列转行 index 行索引,columns 要转为列名的行,values 要转为列值的行
df2 = pd.pivot_table(df, index=['品类'], columns=['日期'], values=['销量'])
df2.fillna(0, inplace=True)
print(df2)

———-
over,转载请注明出处:http://www.jiangkl.com/2023/10/pivot_table

Hello World

闪展腾挪,只为避开apply

apply是pandas一个强大的工具函数,可以逐行对数据进行操作。pandas的优点很多,比如代码简洁、相对直接遍历效率更高;但它的“效率高”是相对的,相对于merge之类的操作,apply的执行时间可能会高出两个数量级。比如下面这行:

1
2
  #为订单数据集增加以后一列:微信支付的金额
  df['pay_wx'] = df.apply(lambda x: (x.pay if x.chan == 'wx' else 0), axis=1)

从上面的代码看,逻辑非常简洁,但是实际测试,50万的数据量,要20秒。下面尝试改造一下

1
2
3
4
  df_wx = df[df['chan'] == 'wx']
  df_wx.rename(columns={'pay': 'pay_wx'}, inplace=True)
  df['pay_wx'] = df_wx['pay_wx']
  df.fillna({'pay_wx': 0}, inplace=True)

代码从一行变成了四行,不过执行效率可以高很多:50万数据,时间大约0.7秒
当然,方法不止一种,对于更见的判断条件,可以直接用merge操作:

1
2
3
4
5
6
7
8
9
10
  #合并某项分类依据
  df['color'] = df.apply(lambda x: ('红' if x.color == '粉红' else x.color), axis=1)
  #使用merge优化
  df_h = df[df['color'] == '粉红'][['id', 'color']]
  df_h['color'] = '红'
  df_nh = df[df['color'] != '粉红'][['id', 'color']]
  df_hs = pd.concat([df_h, df_nh])
  df_hs.rename(columns={'color':'color2'}, inplace=True)
  df = pd.merge(df, df_h, on='id', how='left')
  df['color'] = df['color2']

通过上面这种方法改造,执行时间和第一个方法接近,50万条数据大约0.8秒

———–
转载请注明出处:http://www.jiangkl.com/2022/12/no_apply

Hello World

pandas降低内存占用小技巧

这些年个人电脑的配置逐渐提高,服务器的配置反而停滞不前,自己手头的笔记本早就16G内存了,可公司用的阿里云的服务器,8G内存已经算“较高配置”了。。。
作为php、mysql之类的服务器,8G确实够用了,可做pandas数据分析,就不一定了,这不现在要做一个月度数据分析,要加载一个月的订单量,大概五千万量级,在本地虽然慢点,但结果都能跑出来,可到了服务器上,虽然linux开了虚拟内存,可不但比本地慢很多,还经常跑到半截被“killed”掉了。。。
“你被终结了,蠢货”,每到这个时候,就想起了星际里雷神的这句台词 O(∩_∩)O哈哈~
本地跑的时候,大概会占用12G内存,精简了不必要的字段以后,降低到了9G,还是不行,于是开始招其他能够降低内存占用的方法,比较有效的是修改数据类型,不过试了几次,int64改int16、int32,都没有效果,只有下面这个,让内存占从9G降低到了7、8G:
df['hour'] = df['hour'].astype(‘category’)
hour字段原本是字符串类型,直接.info(),显示是object,变成category以后,确实能节约不少空间
—————–先写到这里,后续验证有效的能减少内存占用的方法会持续更新(2021年12月21日17:07:05)