闲来无事,整理一下数据分析/处理的代码,python使用这一块最多的两个简单的库,就是numpy和pandas库。 当初作为数模新人,还没有AI,自己摸索整理了一堆代码命令,但是没总结乱七八糟,所以今天总结一下, 做成一个对比表格,可以更加直观他们两个在同一个功能上的代码怎么敲,也算是对我那段三年建模经历的总结。(致失去的青春,致迷茫的数模人,致自由,Passion! )
下面是表格的内容总结,比较基础,后续我更新一下:相关性分析与特征处理(特征选择( 过滤式、包裹式和嵌入式),特征变换),有监督学习(分类,回归),无监督学习(聚类),启发式算法(模拟退火,遗传算法,粒子群,差分进化,鲸鱼算法),主成分分析。 还有一些结果指标和数据可视化(sns和matplotlib)。 算是走完数据分析建模画图全程吧。
!!!注意,本人是个懒人,想要看上面哪个内容,评论区催一下哈哈。对了,下面表格代码看不懂的,附上个国内AI网站,给你登录就可以用,不会就问。通义tongyi.ai_你的全能AI助手-通义千问
1. 数据导入和导出
- CSV数据导入和导出
- Excel数据导入和导出
- HDF5文件的读写
2. 数据操作
- 表的链接和合并
- 数据筛选
- 字符串处理
- 类型转换
3. 数据结构操作
- 创建和访问数据框
- 行列的插入和删除
- 索引整理
4. 数据处理技巧
- 数据去重
- 处理异常值
- 数据归一化
- 处理缺失值
- 数据编码和分箱
5. 高级数据操作
- 数组排序
- 分组统计
- 时间序列处理
- 多级索引
6. 特殊操作
- 批量替换
- 数据透视表
- 日期差计算
- 数据变换函数
- 数据的链接和分割
作用 | 代码 |
csv数据导入 | #注明有些csv使用gbk编码的,平时的读取是默认utf8编码,所以需要转换 df1 = pd.read_csv("d2.csv", encoding='cp936') df1 = pd.read_csv("d2.csv", encoding='cp936', index_col=0) |
csv数据导出 | df.to_csv('G:/第13周Python上课资料/d1.csv', encoding = 'GBK') df1 = pd.read_csv("d2.csv", encoding='cp936', index_col=0) |
excel数据导入 | df2 = pd.read_excel("mobile.xlsx",index_col=0, sheet_name='二季度') |
excel数据导出 | df2.to_excel("a1.xlsx", sheet_name='二季度') 3.两个一起 with pd.ExcelWriter(r'D:\桌面\今天任务\2020C题再开启\修改项目\附件4.xlsx',engine='openpyxl') as w: data_2_1.to_excel(w,sheet_name='附件1',index=False) data_2_2.to_excel(w,sheet_name='附件2') result.to_excel(r"D:\桌面\要交的作业\公司的.xlsx",index=False,header=False) |
读/写HDF5文件 | #写,若store.h5文件不存在,则先创建;若已存在,则打开此文件 store = pd.HDFStore('store.h5') store['dfa'] = df1 # 将df1保存到文件中,键名dfa store['dfb'] = df2 # 将df2保存到文件中,键名dfb store.close() # 关闭文件 |
读/写HDF5文件 | # 读出已保存的数据可以使用下面的命令。 store = pd.HDFStore('store.h5') # 打开文件 df3 = store['dfa'] # 根据dfa键名取出数据 df4 = store['dfb'] # 根据dfb键名取出数据 |
表的链接 | # 8.5.5 数据框连接 ''' Pandas提供了merge()方法用于连接不同数据框的行,类似于数据库的两个表连接查询: select sno, name from tb1, tb2 where tb1.sno = tb2.sno ''' df1 = pd.DataFrame({'color':['r', 'b', 'w', 'w'], 'c1':range(4)}) df2 = pd.DataFrame({'color':['b', 'w', 'b'], 'c2':range(2, 5)}) ''' df1和df2有同名列color,pd.merge()自动将同名列作为连接键, 横向连接两个数据框的color值相等的行。连接时丢弃原数据框的索引。 ''' df4 = pd.merge(df1, df2, on='color') df3 = pd.merge(df1, df2) ''' 两个数据框列名不同时,用 left_on 和 right_on 参数分别指定。 下例指定c1, c2列为键,表示当df1表的c1列值等于df2表的c2列值时满足连接条件。 pd.merge(df1, df2, left_on='c1', right_on='c2') ''' pd.merge(df1, df2, left_on='c1', right_on='c2') ''' pd.merge默认做inner内连接,还可指定left /right/outer 等连接方式, 这些连接方式与数据库中的连接规则是类似的。 ''' df2 = pd.DataFrame({'color':['b', 'w', 'g'], 'c2':range(2, 5)}) pd.merge(df1, df2, how='left') # 包含左表所有的行 pd.merge(df1, df2, how='right') # 包含右表所有的行 pd.merge(df1, df2, how='outer') # 包含两表所有的行 ''' 与连接有关的另一个方法是pd.concat(),它合并两个数据框。 ''' np.random.seed(7) df1 = pd.DataFrame(np.random.rand(4).reshape(2, 2), columns=['c1', 'c2']) df2 = pd.DataFrame(np.random.rand(4).reshape(2, 2), columns=['c1', 'c2']) pd.concat([df1, df2], ignore_index=True) # 默认沿纵向合并,行数增加 pd.concat([df1, df2], axis=1) # axis=1沿横向合并,列数增加 #合并多个DataFrame dfs_list = list(dic.values()) # 创建一个空的 DataFrame merged_df = dfs_list[0] # 循环逐步合并多个 DataFrame for i, df in enumerate(dfs_list[1:], start=1): merged_df = pd.merge(merged_df, df, on=['代码', '年份'], how='left', suffixes=('', f'_{i}')) |
数据初步处理 | numpy代码 | Pandas |
范围内随机整数 | # 读出已保存的数据可以使用下面的命令。 store = pd.HDFStore('store.h5') # 打开文件 df3 = store['dfa'] # 根据dfa键名取出数据 df4 = store['dfb'] # 根据dfb键名取出数据 | |
范围内随机小数(保留小数) | ##100个1-10的随机数 保留两位小数 random_numbers_1=["{:.2f}".format(random.uniform(1,10)) for i in range(100)] random_numbers_2= [round(random.uniform(-5, -3), 2) for _ in range(100)] random_numbers_3=[[round(random.uniform(-5,-3),2)for i in range(10)] for j in range(10)] | |
范围内不重复的随机整数和小数 | card=np.arange(1, 55,0.1) # 一副牌 np.random.shuffle(card) #洗牌 | |
筛选数据 | >>> a[np.where(a > 5)] # 等价于 a[a>5] x=np.array((70, 75, 92, 68, 89)) # 评分1 y=np.array((75, 69, 93, 70, 85)) # 评分2 np.where(x>y, x, y) # 取x/y两两比较的较大值 np.where(x>y, 1, 0) # x>y则取1, 否则取0 #第二行的第三列 data[1,2] #获取第三列 data[:,np.newaxis,2] | * 布尔 方框选择 1. da_group_drop = da_group_drop[da_group_drop['date']>='2014-11-28'] 2. num_a = data[(data.behavior_type != 2) & (data.behavior_type != 3)]['item_id'].nunique() 3. SJ = SC[SC['user_id'].isin(JG['user_id'] .values.tolist())] #收藏并且加购的表格 4.JJ = JG[~JG['user_id'].isin(SC['user_id'] .values.tolist())] #仅加购的表格 * np.where 得到索引值 |
字符串处理 | # 8.5.8 字符串处理 ''' Pandas为字符串提供了形如 “obj.str.方法()” 的一系列命令支持, 这些方法一般在数据清洗、转换时使用。 ''' ser1 = pd.Series(['Beauty and the Beast', 'Captain America: Civil War', 'Jurassic World', 'Toy Story']) help(ser1.str) ns1 = ser1.str.len() # 返回字符串长度 ns2 = ser1.str.split() # 分割字符串 ns3 = ser1.str[:6] # 字符串切片 ns4 = ser1.str.contains('War') # 测试电影名中是否包含War ns5 = ser1.str.lower().str.contains('war') # 转小写再测是否含war ns6 = ser1.str.replace(' ', '-') # 字符替换,用横线- 替换空格 | |
类型转换 | ##变成list类型 * attr = pv_daily.date.astype('str').to_list() |
数据一点基础命令 | 介绍 | Pandas |
创建数据框 | ''' DataFrame(数据框)是Pandas最重要的数据结构。 数据框可视为由行和列构成的二维表格,每行或每列都可视为一个Series。 DataFrame既有行索引(index)又有列索引(columns) ''' | data = {'apple': [1100,1050,1200], 'huawei': [1250,1300,1328], 'oppo': [800,850,750]} df1 = pd.DataFrame(data, index=['一月', '二月', '三月']) df2 = pd.DataFrame({'apple': {'一月':1100, '二月':1050, '三月':1200},\ 'huawei': {'一月':1250, '二月':1300, '三月':1328},\ 'oppo' : {'一月':800, '二月':850, '三月':750}}) df1 = pd.DataFrame.from_dict(HanLP.keyphrase_extraction(doc.paragraphs[i].text), orient='index', columns=['Score']) df1 = df1.sort_values(by='Score', ascending=False).reset_index() df1.columns = ['关键词', '权重'] df_1 = pd.concat([df_1, df1],ignore_index=False) ''' 数据框可视为二维表格,有index(行)和columns(列)两个重要属性。 在创建数据框时,可以指定index和columns。 ''' frame = pd.DataFrame(np.arange(12).reshape(3, 4), index=['a','b','c'], columns=['c1', 'c2','c3','c4']) |
数据筛选 | ||
访问/修改数据 | 数据行列 只要有一个是文字,索引就用iloc,不用loc ''' Pandas提供了三种基本数据结构 Series:带标签的一维数组 DataFrame:带标签的二维数组(即表格) Panel:带标签的三维数组(若干表格的叠加面板) 主要使用Series和DataFrame。 ''' | data = {'apple': [1100,1050,1200,1300], 'huawei': [1250,1300,1328,1450,], 'oppo': [800,850,750,720]} df = pd.DataFrame(data, index=['一月', '二月', '三月', '四月']) a1 = df['apple'] a2 = df.apple b = df[['apple', 'huawei']] df['apple'] = 100,200,300 df['apple'] = [101,201,301] df['apple'] = (102,202,303) print(date1_2_duplicate_drop.loc[:,'发票号码'])#用索引名 print(date1_2_duplicate_drop.iloc[:,0])#用数字 a3 = df['一月'] # 错误,访问一行不能用 df['一月'] a4 = df.loc['一月'] df.loc['一月'] = 1212,1563,802 a5 = df.iloc[0] a6 = df.loc['一月':'二月'] a7 = df.iloc[0:2] a8 = df[df.apple>1200] a9 = df[(df.apple>1200) & (df.huawei>1300)] df.iat[1,2] df.at['一月','huawei'] df.query('huawei > 1300') #series对象具有values和index属性 s1 = pd.Series([10,20,30], index=['a','b','c']) v1 = s1.values index1 = s1.index # 5) 获得/修改series对象中的标签 s1 = pd.Series([10,20,30], index=['a','b','c']) a1 = s1.index[1] # 获得标签 s1.index[1] = 'x' # 将报错,标签不能单个修改 s1.index = ['a1', 'b1','c1'] # 但允许对标签一次性全部赋值修改 s1.index = ['a1', 'a1', 'c1'] s1.index.value_counts() # 统计每个索引出现的次数 |
行、列的插入和删除 | 行的插入 | df = pd.DataFrame({'姓名':['a','b'], '学号':['A1','A2'], '成绩1':[98,90], '成绩2':[87,80]}) rdf = df.append({'姓名':'d','学号':'A4','成绩1':89,'成绩2':78}, ignore_index = True) # 行的插入,返回一个新数据框 df = df.append({'姓名':'d','学号':'A4','成绩1':89,'成绩2':78}, ignore_index = True) # 行的插入,在原数据框中新增 |
行、列的插入和删除 | 行的删除 | rdf = df.drop(2) # 返回删除第2行后的新数据框,原数据框不变 df = df.drop(2) df.drop(1, inplace=True) # 直接再原数据框中删除第2行后 |
行、列的插入和删除 | 列的插入 | df = pd.DataFrame({'姓名':['a','b'], '学号':['A1','A2'], '成绩1':[98,90], '成绩2':[87,80]}, index = [0, 1]) df['性别'] = ['M', 'F'] # 新列赋值方式 df.insert(4, '平均成绩', (df.成绩1 + df.成绩2)/2) |
行、列的插入和删除 | 列的删除 | df.drop('平均成绩', axis = 1, inplace=True) rdf = df.pop('成绩1') del df['成绩2'] |
索引整理 | # 8.5.2 索引整理 ''' a)通过reindex()方法重建索引, 实现行列的取舍, 重建时保留指定标签的数据,抛弃未指定的标签。 ''' df = pd.read_excel("mobile.xlsx", index_col=0, sheet_name= '二季度') df2 = df.reindex(['一月', '二月']) df3 = df.loc[['一月', '二月']] df4 = df.loc[['一月', '二月', '四月']] # 报错 df5 = df.reindex(['一月', '二月', '四月']) df6 = df.reindex(['apple', 'huawei','mi'], axis=1) ''' b) rename()重命名 如果已有的列名或行索引不太合适,可使用rename()方法进行调整。 ''' df = pd.read_excel("mobile.xlsx", index_col = 0, sheet_name= '二季度') rdf1 = df.rename(columns = {'apple':'Apple', 'huawei':'HW'}) # 更改列名 df.rename(columns = {'apple':'Apple', 'huawei':'HW'}, inplace=True) # 更改列名 df.columns = ['Apple','HW', 'oppo'] rdf2 = df.rename(index = {'一月':'m1', '二月':'m2', '三月':'m3'}) # 更改索引 df.index = ['m1','m2', 'm3'] rdf3 = df.rename({'一月':'m1', '二月':'m2', '三月':'m3'}, axis = 0) ''' c) set_index()重新设定索引列 如果想用另一列做索引列,可用set_index()方法变更。 ''' df = pd.DataFrame({'姓名':['a','b'], '学号':['A1','A2'], '成绩1':[98,90], '成绩2':[87,80]}) df3 = df.set_index('学号') # 返回的新数据框将学号列设为索引 df.set_index('学号', inplace=True) # 在原数据框上修改 df3 = df3.reset_index() df4 = df3.set_index('姓名') |
数据中级处理 | 代码 | Pandas |
数据去重 | numpy.unique(ar, return_index=False, return_inverse=False, return_counts=False, axis=None) | * uv_daily = data.groupby('date')['user_id'] .apply(lambda s:s.drop_duplicates().count()) .rename('uv').reset_index() * uv_daily = data.groupby('date')['user_id'] .nunique().rename('uv').reset_index() ''' 数据中含有重复值时,使用下列方法处理。 s.duplicated(), s.drop_duplicates() ''' #重复值观察 date1_2_duplicate=date1_2.duplicated('发票号码').sum() date1_3_duplicate=date1_3.duplicated('发票号码').sum() #删除重复值 会影响索引 date1_2_duplicate_drop=date1_2.drop_duplicates('发票号码') date1_3_duplicate_drop=date1_3.drop_duplicates('发票号码') s = pd.Series(list('abacdefanla')) b = s.duplicated() # 检测重复值,返回布尔数组,重复值处显示True s1 = s.drop_duplicates() # 删除重复值,返回一个新对象 df = pd.DataFrame({'c1': ['a', 'a', 'b'], 'c2': ['a', 'b', 'b'], 'c3': ['a', 'b', 'x']}) b1 = df.duplicated() # 整行检测, 英标[ˈduːplɪkeɪtɪd] b2 = df.duplicated('c1') # 整列检测 df2 = df.drop_duplicates('c1') # c1列上删除重复值 |
数据异常值 | 3-Sigma规则 for col in data.select_dtypes(include=[np.number]).columns: mean = data[col].mean() std = data[col].std() upper_limit = mean + 3 * std lower_limit = mean - 3 * std # 找出异常值的索引并替换 data.loc[data[col] > upper_limit, col] = data[col].median() data.loc[data[col] < lower_limit, col] = data[col].median() 箱型图(IQR)方法 for col in data.select_dtypes(include=[np.number]).columns: Q1 = data[col].quantile(0.25) Q3 = data[col].quantile(0.75) IQR = Q3 - Q1 lower_limit = Q1 - 1.5 * IQR upper_limit = Q3 + 1.5 * IQR # 找出异常值的索引并替换 data.loc[data[col] > upper_limit, col] = data[col].median() data.loc[data[col] < lower_limit, col] = data[col].median() | #使用value counts()函数查石df1中"省份”的分布情况以以及查石表格台份这print(df1.['省份].value counts0) #使用replace0函数进行替换df1数据中拼写错误的值,并值给原数据 df1[省份]= df1[省份].replace(浙省,浙江省) #使用print0函数输出进行替换之后的df1中"省份”的数据 print(df1[省份]) #使用value counts0函数查看df1中"省份”的分布情况以及检查是否修改成功,并使用print0函数进行 输出 print(df1[’省份’].value_counts()) |
数据无量纲化(归一化) | from sklearn.preprocessing import MinMaxScaler data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]] import pandas as pd pd.DataFrame(data) #实现归一化 scaler = MinMaxScaler() #实例化 scaler = scaler.fit(data) #fit,在这里本质是生成min(x)和max(x) result = scaler.transform(data) result_ = scaler.fit_transform(data) scaler.inverse_transform(result) #将归一化后的结果逆转 #当X中的特征数量非常多的时候,fit会报错并表示,数据量太大了我计算不了 #此时使用partial_fit作为训练接口 #scaler = scaler.partial_fit(data) ###别的 import numpy as np X = np.array([[-1, 2], [-0.5, 6], [0, 10], [1, 18]]) #归一化 X_nor = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0)) X_nor #逆转归一化 X_returned = X_nor * (X.max(axis=0) - X.min(axis=0)) + X.min(axis=0) X_returned #### 数据无量纲化:数据标准化 当数据(x)按均值(μ)中心化后,再按标准差(σ)缩放,数据就会服从为均值为0,方差为1的正态分布(即标准正态分 布) from sklearn.preprocessing import StandardScaler data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]] scaler = StandardScaler() #实例化 scaler.fit(data) #fit,本质是生成均值和方差 x_std = scaler.transform(data) #通过接口导出结果 result=scaler.fit_transform(data) | |
数据缺失值处理 | import pandas as pd data = pd.read_csv(r"C:\work\learnbetter\micro-class\week 3 Preprocessing\Narrativedata.csv",index_col=0) data.head() data.loc[:,"Age"] = data.loc[:,"Age"].fillna(data.loc[:,"Age"].median()) #.fillna 在DataFrame里面直接进行填补 data.dropna(axis=0,inplace=True) #.dropna(axis=0)删除所有有缺失值的行,.dropna(axis=1)删除所有有缺失值的列 #参数inplace,为True表示在原数据集上进行修改,为False表示生成一个复制对象,不修改原数据,默认False # 1) nan缺失值处理(决策树填充) a = np.array([1, 5, np.nan, np.nan, 10]) a.sum() a.mean() s = pd.Series(a)#变成series后可忽略nan进行处理 s.sum() s.mean() b1 = s.isnull() b2 = s.notnull() b1 = s.isnull().sum()#计算缺失值个数 df = pd.DataFrame(np.arange(12).reshape(4, 3), index=list('abcd'),columns= list('xyz')) df.iloc[1:3, 0:2] = np.nan df.iloc[2, 2] = np.nan a1 = df.dropna() a2 = df.dropna(axis = 1) a3 = df.dropna(how='all') # 表示某行的所有数据都为nan才删除 a4 = df.dropna(thresh = 2) # 保留非nan值个数>=2的数据行/列 a41 = df.dropna(thresh = 1) # 保留非nan值个数>=1的数据行/列 df.fillna(0)#填充是按列来填充的 df.fillna(method = 'ffill')#用前一个值填充 df.fillna(method = 'bfill')#用下一个值填充 df.fillna(value = df.mean())#用平均值填充 #######一些例子 hh=data_touzi_all#放表名 all_1=hh.groupby(['基金代码_FdCd']).mean().reset_index() all_1 #空白值观察 print('数据表 初始数据信息') print(all_1.info()) print("初步空白值:\n{}".format(all_1.isnull().sum())) #缺失值处理 # 计算每列的缺失值比例 aa=all_1#存放数据 missing_percentages = aa.isnull().mean() # 找到缺失值比例大于60%的列 missing_above_60 = missing_percentages[missing_percentages > 0.6] # 删除缺失值比例大于60%的列 df = aa.drop(missing_above_60.index, axis=1) df=df.iloc[:,[0,6,8,9,10]] #删除空白值模块 按最高向下去掉空白值 missing_percentage = df.isnull().sum() / len(df) * 100 # 按照缺失值比例升序排序 missing_percentage_sorted = missing_percentage.sort_values(ascending=True) print(missing_percentage_sorted) # 删除缺失值最高的列,直到所有行都没有缺失值或者无法再删除 while True: # 找到第一个缺失值比例最高的列 col_to_drop = missing_percentage_sorted.index[-1] print(col_to_drop) # 如果该列存在缺失值,删除该行 if df[col_to_drop].isnull().sum() > 0: df.dropna(subset=[col_to_drop], inplace=True) # 重新计算每列缺失值比例 missing_percentage = df.isnull().sum() / len(df) * 100 # 按照缺失值比例升序排序 missing_percentage_sorted = missing_percentage.sort_values(ascending=True) # 如果所有行都没有缺失值或者无法再删除,则退出循环 if missing_percentage_sorted.iloc[-1] == 0 or len(missing_percentage_sorted) == 0: break print('删除空白值后') df.isnull().sum() x0_all=df | |
数据编码 (数据分箱) | 为了让数据适 应算法和库,我们必须将数据进行编码,即是说,将文字型数据转换为数值型 preprocessing.LabelEncoder:标签专用,能够将分类转换为分类数值 from sklearn.preprocessing import LabelEncoder data.iloc[:,-1] = LabelEncoder().fit_transform(data.iloc[:,-1]) preprocessing.OrdinalEncoder:特征专用,能够将分类特征转换为分类数值 from sklearn.preprocessing import OrdinalEncoder data_.iloc[:,1:-1] = OrdinalEncoder().fit_transform(data_.iloc[:,1:-1]) | # 8.5.6 数据分段 ''' 数据分段是将数据按指定的区间归类,以统计每个区间的数据个数。 例如将成绩分为优、良、中、不及格区间段。 数据分段的方法是pd.cut(),分段前要自定义数据区间段,并设置对应的标识文字。 ''' np.random.seed(7) score = np.random.randint(30, 100, size=100) # 生成100个随机整数 bins = [0, 59, 70, 85, 100] # 定义区间段 labels = ['不及格', '中', '良', '优'] # 设置各段的标识文字 scut = pd.cut(score, bins, labels=labels) # 将score按bins分段 s = pd.value_counts(scut) # 统计各类别的数据个数 |
多维数组转一维 | 数组.ravel() | |
数组排序 | b=np.random.randint(1, 20, size=10) c=b.copy() # 备份 b=np.sort(b)#从小到大排序 #数组排序不支持列表的reverse=True参数,要从大到小排如下所示: b_reverse=b[np.argsort(-b)] # 注意 -b #多维数组排序时可指定 axis=0(行) / 1(列),排序时默认按最大轴排序 np.random.seed(7) b=np.random.randint(1, 50, size=15).reshape(3, 5) np.sort(b) #默认按axis=1 ,在水平方向上排序 np.sort(b, axis=0) # 在竖直方向上排序 | # 8.5.4 排序和排名 # a)排序 * top10_Good = item_type_df .sort_values(by=4, ascending=False)[:10] s = pd.Series([2, 5, 1], index=['d', 'a', 'b']) ser1 = s.sort_index() # 按索引'a b d'排序,返回新对象,并不改变原对象 ser2 = s.sort_values() # 按数据值1 2 5排序 ser3 = s.sort_index(ascending=False) # 按索引逆序排 np.random.seed(7) arr = np.array(np.random.randint(1, 100, size=9)).reshape(3, 3) df = pd.DataFrame(arr.reshape(3, 3), columns=['x','z','y'], index=['a','c','b']) df.sort_index() df.sort_index(axis=1) df.sort_index(axis=1, ascending = False) # 按列名索引降序z y x排列 df.sort_values(by='y') # 按y列的数值排序 df.sort_values(by=['y', 'z']) # 先参照y列,再z列排序 df.sort_values(by='b', axis = 1) # 按b列的数值排序 # b) 排名 s = pd.Series([3, 5, 8, 5], index=list('abcd')) l = s.rank() # 排名,默认按数据值升序排名 l = s.rank(ascending=False) # 降序 l = s.rank(method='first') # 指定名次号的生成方法为first |
分组统计 | #-----> 8.6 分组统计 # 8.6.1 分组对象概述 ''' Pandas支持数据分组,功能类似数据库中的group by(分组统计) ''' df = pd.DataFrame({'color': ['red', 'white', 'black', 'red', 'black', 'red'], 'size':['s','m','b','s','m','b'], 'price': [10, 11, 12, 20, 21, 22], 'quantity': [1, 2, 3, 3, 4, 5]}) g = df.groupby('color') # 按color分组 for x in g: print(x) for name, group in g: print(name) # 输出组名 print(group) # 组内容 # 8.6.2 分组对象的统计方法 a1 = g.size() # 列出每个分组的数据条数 a2 = g.sum() # sum只对数值列求和,非数值列未显示 a3 = g.get_group('black') # 指定返回black组数据 a4 = g.head(2) # 取每个分组的头2个数据 a5 = g.nth(0) # 取每组的第0个数据 a6 = g.price.describe() # 对price列做describe,得到一组常用统计量 ''' 分组对象有一个aggregate合计方法(简写为agg),它允许传递多个统计函数, 因此可以一次性得到多个统计值。 ''' g.quantity.agg((np.sum, np.mean, np.max, np.min)) g.quantity.agg([('均值','mean'), ('最大值','max')]) # 定义列名 #自定义函数聚合 df = pd.DataFrame({'color': ['red', 'white', 'black', 'red', 'black', 'red'], 'size':['s','m','b','s','m','b'], 'price': [10, 11, 12, 20, 21, 22], 'quantity': [1, 2, 3, 3, 4, 5]}) g = df.groupby('color') # 按color分组 def squre_sum (x): s = 0 for i in x.values: s = s + i**2 return s g.quantity.agg(squre_sum) ##例子 groupby([列名1,列名2])['列名'].count()#聚合函数count() groupby('列名A').sum()#聚合函数sum() data.groupby('州')['州'].count().rename('哈哈').reset_index() ** ***重置索引 p1=p1.reset_index(drop=True) | |
时间序列 | #-----> 8.7 时间序列 ''' Pandas最初研发的目的是作为金融数据分析包,因此提供了丰富的时间序列处理方法。 时间序列做索引,运算时会自动按日期对齐。 ''' # 8.7.1 Pandas中的时间函数 ''' 拿到timestamp的年月日: date1['年的日期']=date1['开票日期'].dt.year date2['年的日期']=date2['开票日期'].dt.year date1['月期']=date1['开票日期'].dt.month date2['月期']=date2['开票日期'].dt.month a) to_datetime(): 将字符串转换为时间,识别不同格式的日期字符串。 ''' pd.to_datetime('2022-11-28') pd.to_datetime(['28/11/2022', '2022.11.28']) pd.to_datetime('2022-11-28 15:30:00') today = pd.datetime.now() t2 = today + pd.DateOffset(days=3) ''' b) date_range():用于产生指定日期段内的一系列日期时间值。 pd.date_range(起始日期, 结束日期, periods=周期数, freq=日期频率) ''' dt1 = pd.date_range('2019-02-01', '2019-02-28') # 默认频率1天 dt2 = pd.date_range('2019-02-01', '2019-02-28', freq='3D' ) # 频率为每3天 dt3 = pd.date_range('2019-01-01', periods=6, freq='3D') # 每3天1个日期 ''' 有时需要对日期序列做shift(移动)转换,以计算相邻日期间的数据变动。 ''' np.random.seed(7) dates = pd.date_range('2018-9-1', periods=4) # 生成4个日期索引值 s = pd.Series(np.random.rand(4), index=dates) s1 = s.shift(1) # 后移一个数据位 diff = s - s.shift(1) # ((s - s.shift(1)) / s.shift(1)).map(lambda x: format(x, '.2%')) # 变动百分比并格式化 # 8.7.2 时间频率变换 ''' 用时间作为索引时,可以方便地按时间段查看数据。 对时间序列数据可用resample()方法按不同频率进行重采样,然后对样本进行计算。 ''' np.random.seed(7) dates = pd.date_range('2018-1-1', periods=365) s = pd.Series(np.random.randn(365), index=dates) # 2018年模拟数据 data1 = s['2018-1'] # 选取2018年1月的数据 data2 = s['2018-02' : '2018-04'] # 选取2018年2月至4月的数据 data3 = s.resample("1M").mean() # 按月求均值 data4 = s.resample("10D").sum() # 每10天求和 data5 = s.resample("10D").agg([np.max, np.min]) # 每10天一次采样,返回每组样本的最大值、最小值 | |
多级索引 | # 8.5.7 多级索引 ''' Pandas支持一级索引,也支持多级索引(MultiIndex)。 多级索引可以更好地表达数据之间的联系。 ''' data = np.arange(2, 10).reshape(4, 2) df1 = pd.DataFrame(data, index=[list('AABB'), list('rgrg')], columns=['一月','二月']) mindex = pd.Index([('A', 'r'), ('A', 'g'), ('B', 'r'), ('B', 'g')], names=["Product", "Color"]) df2 = pd.DataFrame(data, index = mindex, columns=['一月','二月']) df1.loc['B'] # 查看B类产品 df2.loc[('B', 'r')] # 查看B类中的红色r产品 df2.loc[(slice(None), 'r'), :] # 查看所有的红色r产品 df2.loc['A'].sum() # A 类每个月数量和 df2.loc['A'].sum().sum() # 所有A类数量和 df2.loc[(slice(None), 'r'), :].sum().sum() # r类数量和 df2.groupby(level='Product').sum() df2.groupby(level='Product').sum().sum(axis=1) df2=df1.unstack() # 默认将内层的1级行索引转为列索引 df3=df1.stack() # 变为三级(0,1,2)索引了 df3.groupby(level=2).sum() |
一些特殊的操作 | 代码 | |
批量替换 | def live_year(x): if x < 365: return '不到1年' if x < 365 * 2: return '1-2年' if x < 365 * 3: return '2-3年' if x < 365 * 4: return '3-4年' if x < 365 * 5: return '4-5年' if x < 365 * 10: return '5-10年' return '10年以上' s = data.groupby(data['live_days'].apply(lambda x: live_year(x))).size() | # 增加 Country/Region 和 Province/State 的中文冗余列 Country/Region_zh 、Province/State_zh country_map = { 'Singapore Rep.': '新加坡', 'Dominican Rep.': '多米尼加', 'Palestine': '巴勒斯坦', 'Bahamas': '巴哈马', 'Timor-Leste': '东帝汶', 'Afghanistan': '阿富汗', 'Guinea-Bissau': '几内亚比绍', "Côte d'Ivoire": '科特迪瓦', 'Siachen Glacier': '锡亚琴冰川', "Br. Indian Ocean Ter.": '英属印度洋领土', 'Angola': '安哥拉', 'Albania': '阿尔巴尼亚', 'United Arab Emirates': '阿联酋', 'Argentina': '阿根廷', 'Armenia': '亚美尼亚', 'French Southern and Antarctic Lands': '法属南半球和南极领地', 'Australia': '澳大利亚', 'Austria': '奥地利', 'Azerbaijan': '阿塞拜疆', 'Burundi': '布隆迪', 'Belgium': '比利时', 'Benin': '贝宁', 'Burkina Faso': '布基纳法索', 'Bangladesh': '孟加拉国', 'Bulgaria': '保加利亚', 'The Bahamas': '巴哈马', 'Bosnia and Herz.': '波斯尼亚和黑塞哥维那', 'Belarus': '白俄罗斯', 'Belize': '伯利兹', 'Bermuda': '百慕大', 'Bolivia': '玻利维亚', 'Brazil': '巴西', 'Brunei': '文莱', 'Bhutan': '不丹', 'Botswana': '博茨瓦纳', 'Central African Rep.': '中非', 'Canada': '加拿大', 'Switzerland': '瑞士', 'Chile': '智利', 'China': '中国', 'Ivory Coast': '象牙海岸', 'Cameroon': '喀麦隆', 'Dem. Rep. Congo': '刚果民主共和国', 'Congo': '刚果', 'Colombia': '哥伦比亚', 'Costa Rica': '哥斯达黎加', 'Cuba': '古巴', 'N. Cyprus': '北塞浦路斯', 'Cyprus': '塞浦路斯', 'Czech Rep.': '捷克', 'Germany': '德国', 'Djibouti': '吉布提', 'Denmark': '丹麦', 'Algeria': '阿尔及利亚', 'Ecuador': '厄瓜多尔', 'Egypt': '埃及', 'Eritrea': '厄立特里亚', 'Spain': '西班牙', 'Estonia': '爱沙尼亚', 'Ethiopia': '埃塞俄比亚', 'Finland': '芬兰', 'Fiji': '斐', 'Falkland Islands': '福克兰群岛', 'France': '法国', 'Gabon': '加蓬', 'United Kingdom': '英国', 'Georgia': '格鲁吉亚', 'Ghana': '加纳', 'Guinea': '几内亚', 'Gambia': '冈比亚', 'Guinea Bissau': '几内亚比绍', 'Eq. Guinea': '赤道几内亚', 'Greece': '希腊', 'Greenland': '格陵兰', 'Guatemala': '危地马拉', 'French Guiana': '法属圭亚那', 'Guyana': '圭亚那', 'Honduras': '洪都拉斯', 'Croatia': '克罗地亚', 'Haiti': '海地', 'Hungary': '匈牙利', 'Indonesia': '印度尼西亚', 'India': '印度', 'Ireland': '爱尔兰', 'Iran': '伊朗', 'Iraq': '伊拉克', 'Iceland': '冰岛', 'Israel': '以色列', 'Italy': '意大利', 'Jamaica': '牙买加', 'Jordan': '约旦', 'Japan': '日本', 'Kazakhstan': '哈萨克斯坦', 'Kenya': '肯尼亚', 'Kyrgyzstan': '吉尔吉斯斯坦', 'Cambodia': '柬埔寨', 'Korea': '韩国', 'Kosovo': '科索沃', 'Kuwait': '科威特', 'Lao PDR': '老挝', 'Lebanon': '黎巴嫩', 'Liberia': '利比里亚', 'Libya': '利比亚', 'Sri Lanka': '斯里兰卡', 'Lesotho': '莱索托', 'Lithuania': '立陶宛', 'Luxembourg': '卢森堡', 'Latvia': '拉脱维亚', 'Morocco': '摩洛哥', 'Moldova': '摩尔多瓦', 'Madagascar': '马达加斯加', 'Mexico': '墨西哥', 'Macedonia': '马其顿', 'Mali': '马里', 'Myanmar': '缅甸', 'Montenegro': '黑山', 'Mongolia': '蒙古', 'Mozambique': '莫桑比克', 'Mauritania': '毛里塔尼亚', 'Malawi': '马拉维', 'Malaysia': '马来西亚', 'Namibia': '纳米比亚', 'New Caledonia': '新喀里多尼亚', 'Niger': '尼日尔', 'Nigeria': '尼日利亚', 'Nicaragua': '尼加拉瓜', 'Netherlands': '荷兰', 'Norway': '挪威', 'Nepal': '尼泊尔', 'New Zealand': '新西兰', 'Oman': '阿曼', 'Pakistan': '巴基斯坦', 'Panama': '巴拿马', 'Peru': '秘鲁', 'Philippines': '菲律宾', 'Papua New Guinea': '巴布亚新几内亚', 'Poland': '波兰', 'Puerto Rico': '波多黎各', 'Dem. Rep. Korea': '朝鲜', 'Portugal': '葡萄牙', 'Paraguay': '巴拉圭', 'Qatar': '卡塔尔', 'Romania': '罗马尼亚', 'Russia': '俄罗斯', 'Rwanda': '卢旺达', 'W. Sahara': '西撒哈拉', 'Saudi Arabia': '沙特阿拉伯', 'Sudan': '苏丹', 'S. Sudan': '南苏丹', 'Senegal': '塞内加尔', 'Solomon Is.': '所罗门群岛', 'Sierra Leone': '塞拉利昂', 'El Salvador': '萨尔瓦多', 'Somaliland': '索马里兰', 'Somalia': '索马里', 'Serbia': '塞尔维亚', 'Suriname': '苏里南', 'Slovakia': '斯洛伐克', 'Slovenia': '斯洛文尼亚', 'Sweden': '瑞典', 'Swaziland': '斯威士兰', 'Syria': '叙利亚', 'Chad': '乍得', 'Togo': '多哥', 'Thailand': '泰国', 'Tajikistan': '塔吉克斯坦', 'Turkmenistan': '土库曼斯坦', 'East Timor': '东帝汶', 'Trinidad and Tobago': '特里尼达和多巴哥', 'Tunisia': '突尼斯', 'Turkey': '土耳其', 'Tanzania': '坦桑尼亚', 'Uganda': '乌干达', 'Ukraine': '乌克兰', 'Uruguay': '乌拉圭', 'United States': '美国', 'Uzbekistan': '乌兹别克斯坦', 'Venezuela': '委内瑞拉', 'Vietnam': '越南', 'Vanuatu': '瓦努阿图', 'West Bank': '西岸', 'Yemen': '也门', 'South Africa': '南非', 'Zambia': '赞比亚', 'Zimbabwe': '津巴布韦', 'Comoros': '科摩罗' } province_map = { 'Anhui': '安徽', 'Beijing': '北京', 'Chongqing': '重庆', 'Fujian': '新疆', 'Gansu': '甘肃', 'Guangdong': '广东', 'Guangxi': '广西', 'Guizhou': '贵州', 'Hainan': '海南', 'Hebei': '河北', 'Heilongjiang': '黑龙江', 'Henan': '河南', 'Hong Kong': '香港', 'Hubei': '湖北', 'Hunan': '湖南', 'Inner Mongolia': '内蒙古', 'Jiangsu': '江苏', 'Jiangxi': '江西', 'Jilin': '吉林', 'Liaoning': '辽宁', 'Macau': '澳门', 'Ningxia': '宁夏', 'Qinghai': '青海', 'Shaanxi': '陕西', 'Shandong': '山东', 'Shanghai': '上海', 'Shanxi': '山西', 'Sichuan': '四川', 'Tianjin': '天津', 'Tibet': '西藏', 'Xinjiang': '新疆', 'Yunnan': '云南', 'Zhejiang': '浙江', 'Fujian':'福建', 'Taiwan': '台湾' } confirmed_data['Country/Region_zh'] = confirmed_data['Country/Region'].apply(lambda x: country_map.get(x, x)) deaths_data['Country/Region_zh'] = deaths_data['Country/Region'].apply(lambda x: country_map.get(x, x)) recovered_data['Country/Region_zh'] = recovered_data['Country/Region'].apply(lambda x: country_map.get(x, x)) confirmed_data['Province/State_zh'] = confirmed_data['Province/State'].apply(lambda x: province_map.get(x, x)) deaths_data['Province/State_zh'] = deaths_data['Province/State'].apply(lambda x: province_map.get(x, x)) recovered_data['Province/State_zh'] = recovered_data['Province/State'].apply(lambda x: province_map.get(x, x)) |
路径拼接 | path = os.path.join(os.path.join(os.getcwd(), "文件夹名"), inp_code + ".csv") | |
数据透视表 | # 8.6.3 数据透视表 ''' Excel中有一个数据透视表功能,Pandas提供了类似的命令pivot_table()。 ''' df = pd.DataFrame({'color': ['red', 'white', 'black', 'red', 'black', 'red'], 'size':['s','m','b','s','m','b'], 'price': [10, 11, 12, 20, 21, 22], 'quantity': [1, 2, 3, 3, 4, 5]}) df.pivot_table(index='color', values='quantity', aggfunc='sum') df.pivot_table(index='color', columns='size', values='quantity', aggfunc='sum') ''' values:需要汇总计算的列,可多选 index:行分组键,一般是用于分组的列名或其他分组键,作为结果DataFrame的行索引 columns:列分组键,一般是用于分组的列名或其他分组键,作为结果DataFrame的列索引 aggfunc:聚合函数或函数列表,默认为平均值 fill_value:设定缺失替换值 margins:是否添加行列的总计 dropna:默认为True,如果列的所有值都是NaN,将不作为计算列,False时,被保留 margins_name:汇总行列的名称,默认为All observed:是否显示观测值 ''' df = pd.read_excel("高考分数线1420.xlsx") # 每个地区的平均分数线 result1 = df.pivot_table(index='地区', values='分数线', aggfunc='mean') result1.sort_values(by = '分数线',ascending = False) # 每个地区的不同年份所有类别的平均分数线 result2 = df.pivot_table(index='地区', columns='年份', values='分数线', aggfunc='mean') # 不同地区、不同考生类别、不同年份的分数线 result3 = df.pivot_table(index=['地区', '考生类别'], columns='年份', values='分数线') | |
求日期差 | * buy_again_days1=buy_again_days.groupby('user_id') .date.apply(lambda x:x.sort_values().diff(1).dropna())//求日期差 | |
含对每个元素进行变换的函数 | df = pd.DataFrame(np.arange(9).reshape(3,3), index=list('abc'), columns=list('xyz')) df.sum() # 默认按axis=0 行求和 df.sum(axis=1) df.sum().sum() np.random.seed(7) ar=np.random.randint(0,11,size=(3,3)) df = pd.DataFrame(ar, index=list('abc'), columns=list('xyz')) f = lambda x: x.max() - x.min() t1 = df.apply(f) # 在axis=0(纵向)求 最大值-最小值 t2 = df.apply(f, axis=1) p = df.applymap(lambda x:str(x)+'︒c') # 在每个数据上变换 t3 = p.applymap(lambda x:int(x[:-2])) t4 = p.x.map(lambda x: x[:-2]+'度') | |
数据的链接和分割 | np.hstack((arr1, arr2)) np.vstack((arr2, arr3)) split_arrays = np.hsplit(array2, [2,4,6])#从第二列,4列,6列切开 split_arrays = np.vsplit(array2, [2,4,6])#从第二列,4列,6列切开 |
说点心里话:AI发展很快,不会你一问就可以得到结果了,但是不能每次都问吧?这就是这个文章存在的意义。