数据读取处理

1
2
3
4
5
6
7
iris = load_iris()
lable = iris.feature_names
target = iris.target
feature = iris.data
data = np.column_stack((feature,target))
lable.append('type')
df = pd.DataFrame(data,columns=lable)
1
2
a.reshape(-1,1)
a[:,np.newaxis]

选择列

1
tr.select_dtypes(include=['int64','float64'])

选择行

  • 可以通过 “.” 来操作 df.a
  • 也可以通过 “[]” 来操作 df['a']

数据格式化

  1. map、apply在用于Series时,对每一个值进行处理,两者并没有什么区别
  2. apply不仅可以用于Series,还可以用于DataFrame;而map只能用于Series。
  3. 一般情况下,apply应用更广泛,尤其是自定义函数带多个参数时,建议使用apply。
  4. applymap可以对多个Series进行操作,map和apply均不行。
  • apply /map/applymap 函数(常用方法)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def cal_interval(df,from_date,to_date):
    delta = 1
    try:
    f = datetime.datetime.strptime(df[from_date],"%m/%d/%Y")
    t = datetime.datetime.strptime(df[to_date],"%m/%d/%Y")
    delta = (t-f).days
    except:
    pass
    return 1 if delta<=0 else delta
    df['d'] = df.apply(cal_interval,axis=1,args=['Date Event Began','Date of Restoration'])
    1
    2
    date = pd.period_range(start = '1990-02-01',periods=100,freq='D')
    df = pd.DataFrame({'date':date,'val':np.random.randn(len(date)),'val2':np.random.randn(len(date))})
    date val val2
    0 1990-02-01 0.771114 0.223646
    1 1990-02-02 -0.630781 -1.231217
    2 1990-02-03 -0.435648 -1.324931
    3 1990-02-04 2.459657 1.195601
    4 1990-02-05 0.378009 2.207286
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    # apply默认是作用于列,要作用于行的话需要加上axis=1
    q2.apply(lambda x:x.原价==x.实价,axis=1)
    # 保留两位小数(类型变成Object)
    df.val.apply(lambda x: format(x,'.2f'))
    # 或者
    df.val.apply(lambda x: '{:.2f}'.format(x))
    # 四舍五入保留两位小数
    df.val.round(2)

    # 转为百分比,并保留2位小数 lambda 写法
    df.val.map(lambda x: "{:.2%}".format(x))
    # 或者
    q2_df[col].apply(lambda x:format(x,'.2%'))

    # 正常函数写法(不推荐)
    def turn_percentage(x):
    return '%.2f%%' % (x * 100);
    df.val.apply(turn_percentage)

    # 将获奖时间格式化为x月x日
    df.date.apply(lambda x:x.strftime('%m月%d日'))

    # 将Series中的数据和字符拼接
    df.val.apply(lambda x: f'随机数: {x}')

    # applymap可以对多个Series进行操作
    df[['val','val1']].applymap(lambda x:format(x,'.2f'))

    # 构建apply函数
    def judge_state(row):
    if row['Austin - EV'] <=0.01:
    return 'Off'
    elif row['Austin - EV']>0.01:
    return 'On'
    # 应用apply函数
    df_Austin_ev = df.apply(judge_state,axis = 1)

    # map传入字典 其余值均变为NaN
    df1 = pd.DataFrame({'A':['a','b','c','d']})
    df1.A=df1.A.map({'a':'A','b':'B'})


    # df使用apply还可以传其他参
    import statsmodels.api as sm
    def regress(data, yvar, xvars):
    Y = data[yvar]
    X = data[xvars]
    X['intercept'] = 1.
    result = sm.OLS(Y, X).fit()
    return result.params

    by_year.apply(regress, 'AAPL', ['SPX'])
  • groupby后的apply

1
2
3
4
5
6
7
8
9
10
11
12
13
# 数据是tg_id,month,q1-q96,求每个月q1-q96中最大的点
# 法1
df.groupby(['tg_id','month']).apply(lambda x:max(x.drop(['tg_id','month'],axis=1).apply(lambda x:max(x))))
# 法 2
df.groupby(['tg_id','month']).apply(lambda x:x.drop(['tg_id','month'],axis=1).apply(lambda x:max(x,axis=1))).reset_index().groupby(['tg_id','month']).apply(lambda x:x.drop(['tg_id','month'],axis=1).apply(lambda x:max(x)))
# 法3
val = [f'p{i}' for i in range(1,97)]
def cal_min(df):
return df[val].min().min()
q4.groupby(['tg_id','month']).apply(cal_max)
# 法4
q4.groupby(['tg_id','month']).apply(lambda x:x[val].max().max())

  • 将含有空白符的列转float

    1
    df.a.replace(r'^\s*$', np.nan, regex=True)

日期

  • 将日的数据转为以月为统计的数据
1
2
3
4
5
6
7
8
9
10
11
# 提取日期中的date
df['date'].dt.date
# 重采样 统计
df.resample('D').count()
#重采样 逐个显示
df.to_period("M")
# 异形日期转换
pd.to_datetime(work_index['日期'],format='%Y%m%d')
# 选择日期范围
bz = ['2022-2-14','2022-2-20']

CRUD

一般来说pandas操作都不会在原dataframe进行修改,通过inplace=True可以实现就地修改。

列操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# 重命名特定列名
df.rename(columns={'A':'a'},inplace=True)
# 重命名所有列名
df.columns = ['a','b','c']
# 取出特定类型的列名
obj_feature=df.dtypes[df.dtypes=='object'].index
# 更新列的类型
df['金牌数'] = df['金牌数'].astype(int)
# 插入list
df.a = df.a.astype('list')
df.iat[i,-1] = list(xxx)
'''
li
'''
# 连接两个列
df = pd.concat([tmp1,tmp3.to_frame(),tmp2],axis=1,ignore_index=True)

# 只取结果的交集
pd.concat([df1,df4],axis=1,join='inner')

# 只取包含 df1 索引的部分
pd.concat([df1, df4], axis=1).reindex(df1.index)
pd.merge(df1,df4,left_index=True,right_index=True,how='left')


# 新增列
df['new col name']=1

# 插入列
tmp3 = (df['春节期间(除夕至初六)用电量']-df['节前温度接近的一周用电量'])/df['节前温度接近的一周用电量']
tmp1 = df.iloc[:,:1]
tmp2 = df.iloc[:,1:]
df = pd.concat([tmp1,tmp3.to_frame(),tmp2],axis=1,ignore_index=True)
# 删除 df 的 7、8、9、10 列
df.drop(df.columns[[7,8,9,10]], axis=1,inplace=True)
# 提取第1,2,3,4列
df.iloc[:,0:4]
df.iloc[:,[0,1,2,3]]
# 提取 金牌数、银牌数、铜牌数 三列
df[['金牌数','银牌数','铜牌数']]
# 提取全部列名中以 “数” 结尾的列
df.loc[:, df.columns.str.endswith('数')]
# 改变列顺序
df = df[['A','D','B','C']]
# 单一一列提前可以
df.set_index('a').reset_index()
# 按列排序
df.max(axis=1)
#or
df.max(1)
# 统计出现最多的
tmp2 =df.groupby(['genreId']).agg(lambda x:x.mode())
# 方法二
df.groupby(['genreId','contentRating']).count()[['id']].idxmax(1)


行操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
'''
拼接行
'''

# 查看含有空值的行
df[df.isna().T.any()]
# 连接两个df
pd.concat([train,val],ignore_index=True)
# 等价于
df = pd.concat([train,val]).reset_index()
# or
train.append(val).reset_index()
# or
train.append(val,ignore_index=True)

# 根据 key 连接 left 和 right
pd.merge(left, right, on='key')
# 根据 key1 和 key2 连接 left 和 right
pd.merge(left, right, on=['key1', 'key2'])
# 根据left的key列和right的index合并
pd.merge(left1, right1, left_on='key', right_index=True)
'''
how 可以设置
right、left: 左外,右外
outer、inner: 全外连接,内连接

'''
pd.merge(left, right, how='left', on=['key1', 'key2'])
# 重新产生数据
left.join(right, on=['key1', 'key2'])

# 拼接 df1、df2、df3,同时新增一个索引(x、y、z)来区分不同的表数据来源
pd.concat([df1, df2, df3], keys=['x', 'y', 'z'])

# 插入行
df = pd.DataFrame({'A':[1,1,2,2,3,3],'B':[2,1,5,6,7,9]})
c = pd.DataFrame({'A':[5],'B':[5]})
a = df.iloc[:2,:]
b = df.iloc[2:,:]
df = pd.concat([a,c,b])

# 删除第一行
df.drop(1)
# 条件删除
df.drop(df[df.金牌数<20].index)
data = data.drop(index = data[(data.ZH_Term_len == 0)].index.tolist())
# 提取倒数后三列的10-20行
df.iloc[10:20,-3:]
df.loc[10:20, '总分':]
# 提取第 10 行
# DataFrame格式
a = df.loc[9:9]
# Series格式
a = df.loc[9,:]
# 提取第 10 行之后的全部行
df.iloc[9:,]
df.iloc[9:]
# 提取 0-50 行,间隔为 3
df[:50:3]
# 提取 金牌数 不等于 10 的行
df.loc[~(df['金牌数'] == 10)]
# 提取奇数行
df[[i%2==1 for i in range(len(df.index))]]
# 提取 中国、美国、英国、日本、巴西 五行数据 且 金牌数小于30
df.loc[(df['金牌数'] < 30) & (df['国家奥委会'].isin(['中国','美国','英国','日本','巴西']))]
# 包含某个字的行
df[df.国家奥委会.str.contains('国')]
# 提取 第 0-2 行第 0-2 列
df.iloc[0:2,0:2]
df.iloc[0:2,[0,1]]
# 使用 query 提取 金牌数 + 银牌数 大于 15 的国家
df.query('金牌数+银牌数 > 15')
# 使用 query 提取 金牌数 大于 金牌均值的国家
gold_mean = df['金牌数'].mean()
df.query(f'金牌数 > {gold_mean}')
# 指定位置插入行
df1 = df.iloc[:1, :]
df2 = df.iloc[1:, :]
df3 = pd.DataFrame([[i for i in range(len(df.columns))]], columns=df.columns)
df_new = pd.concat([df1, df3, df2], ignore_index=True)
# 调整 顺序
q4_df = q4_df.reindex([0, 1, 2, 3, 4, 5, 6, 7, 8, 22, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]).reset_index()
# 可以调整列的顺序
ans.reindex(['installs总数','contentRating最多的类型','contentRating最多类型百分比','score平均分'],axis=1)
# 换顺序
cpn_bz.iloc[[2,3]]=cpn_bz.iloc[[3,2]]

Create

  • 创建DataFrame
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 使用 list 生成
nums = np.array([i for i in range(1,31)]).reshape(10,3)
colu = [f'col_{i}' for i in range(3)]
inde = [f'row_{i}' for i in range(10)]
pd.DataFrame(data=nums,index=Finde,columns=colu)
# 使用 dict 生成,索引自动生成
hight = np.random.randint(158,180,10)
weight = np.random.randint(49,75,10)
pd.DataFrame(data={
'hight':hight,
'weight':weight,}
) # 这里没有设置索引,会自动生成
# 读取excel sheet_name默认是0,传入数字就是读取第x+1个sheet,传入字符串就是查找对于sheet的名字
df = pd.read_excel('data/2020年销售数据.xlsx',sheet_name=0)
# 读取csv文件,默认编码utf-8,遇到中文乱码可以试试看gbk
df = pd.read_csv('data/2018年北京积分落户数据.csv',encoding='gbk') # encoding参数指定数据的编码方式为utf-8


Del

  • 删除某列的数据

    • axis:轴。0 或 ‘index’,表示按行删除;1或’columns’,表示按列删除。
    1
    2
    3
    4
    # del 只能删一行
    del df['a']
    # 等价于
    df.drop('a',axis=1,inplace=True)

Update

  • where操作
1
2
# 如果一个国家的金牌数大于 30 则值为 是,反之为 否
df['金牌大于30'] = np.where(df['金牌数'] > 30, '是', '否')
  • 更新索引
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 索引从1开始
df.set_index(x for x in range(1,df.shape[0]+1))
# 使用某列作为索引,默认删除该列 即drop=True
df.set_index('date')
# 修改索引名 如果是多个索引可以通过[]传入
df.rename_axis('日期')
# 指定多个索引
df=df.set_index(['date','val'])
# 修改单个索引名
df.rename_axis(index={'val':'v'})
# 还原索引,使用pandas生成默认索引
df.reset_index()
# 删除索引
df.reset_index(drop=True)
  • replace
1
2
3
4
5
6
7
8
9
10
11
12
# 将金牌数列的数字 0 替换为 无
df['金牌数'].replace(0,'无',inplace=True)
#同时替换 1将 无 替换为 缺失值 2将 0 替换为 None
df.replace(['无',0],[np.nan,'None'],inplace = True)

# Series中replace字符串部分需要加上.str. 支持链式编程
df.employmentLength.str.replace('years','').str.replace('+','')

# lambda 和 str
df.price = df.price.str.replace('[$|,]','').astype('float')
# 等价于
df.price = df.price.apply(lambda x:x.replace('$','').replace(',','')).astype('float')
  • fill
1
2
3
4
5
6
7
8
'''
bfill 从后面往前填充
ffill 从前往后
默认列方向填充0,1使用行方向
'''

# 新增一列 最多奖牌数量 列,值为该国 金、银、铜 牌数量中最多的一个奖牌数量
df['最多奖牌数量'] = df.bfill(1)[["金牌数", "银牌数",'铜牌数']].max(1)

-

Retrieve

  • 随机返回n个样本
1
df.sample(n)
  • pivot与groupby
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
pd.pivot_table(df2,values = ['奖牌类型'],index = ['国家','运动类别'],aggfunc = 'count')
# 等价于
pd.DataFrame(df2.groupby(['国家','运动类别']).count()['奖牌类型'])
# 等价于
df2.groupby(['国家','运动类别']).count()[['奖牌类型']]

# groupby 联合 apply
q2['恋爱的男生比例'] = df[df['romantic']=='yes'].groupby('age').apply(lambda x:x.sex=='M').groupby('age').sum()/q2_rom.groupby('age').count()['sex']
# 相当于在[]里面写条件
df[df['smoker']=='yes'].groupby('age区间').count()
# count和sum有区别,一个是计算bool后求和,一个在条件筛选后求个数
df.groupby('age区间').apply(lambda x:x.smoker=='yes').groupby('age区间').sum()



# 把groupby的元素取出来
pieces = dict(list(df.groupby('key1')))
pieces['b']
# groupby 使用字典
by_column = people.groupby(mapping, axis=1)
by_column.sum()

  • unstack
1
2
3
4
5
6
7
8
9
10
11
12
13
# 计算前十名各国每日奖牌数量合计
# 注意:对于第一天没有数据的国家用0填充,其余时间的缺失值用上一日数据填充
countries = df2.groupby('国家').count().sort_values('奖牌类型',ascending=False).head(10).index.tolist()
tmp = df2[df2['国家'].isin(countries)]
tmp.groupby(['获奖时间','国家']).count()['奖牌类型'].unstack().cumsum().fillna(0)
# 对于两层的Series
data = pd.Series(np.random.randn(9),
index=[['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd'],
[1, 2, 3, 1, 3, 1, 2, 2, 3]])
# 选第二个索引值的操作:
data[:,2]
# 等价于
data.unstack().iloc[:,1]
  • 数据聚合
positionName companySize industryField financeStage companyLabelList firstType secondType thirdType createTime district salary workYear jobNature education positionAdvantage imState score matchScore famousCompany Hobby
0 数据分析 50-150人 移动互联网,电商 A轮 [‘绩效奖金’, ‘带薪年假’, ‘定期体检’, ‘弹性工作’] 产品|需求|项目类 数据分析 数据分析 2020/3/16 11:00 余杭区 37500 1-3年 全职 本科 五险一金、弹性工作、带薪年假、年度体检 today 233 15.101875 False ‘绩效奖金’
0 数据分析 50-150人 移动互联网,电商 A轮 [‘绩效奖金’, ‘带薪年假’, ‘定期体检’, ‘弹性工作’] 产品|需求|项目类 数据分析 数据分析 2020/3/16 11:00 余杭区 37500 1-3年 全职 本科 五险一金、弹性工作、带薪年假、年度体检 today 233 15.101875 False ‘带薪年假’
0 数据分析 50-150人 移动互联网,电商 A轮 [‘绩效奖金’, ‘带薪年假’, ‘定期体检’, ‘弹性工作’] 产品|需求|项目类 数据分析 数据分析 2020/3/16 11:00 余杭区 37500 1-3年 全职 本科 五险一金、弹性工作、带薪年假、年度体检 today 233 15.101875 False ‘定期体检’
0 数据分析 50-150人 移动互联网,电商 A轮 [‘绩效奖金’, ‘带薪年假’, ‘定期体检’, ‘弹性工作’] 产品|需求|项目类 数据分析 数据分析 2020/3/16 11:00 余杭区 37500 1-3年 全职 本科 五险一金、弹性工作、带薪年假、年度体检 today 233 15.101875 False ‘弹性工作’
1 数据建模 150-500人 电商 B轮 [‘年终奖金’, ‘做五休二’, ‘六险一金’, ‘子女福利’] 开发|测试|运维类 数据开发 建模 2020/3/16 11:08 滨江区 15000 3-5年 全职 本科 六险一金,定期体检,丰厚年终 disabled 176 32.559414 False ‘年终奖金’
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
'''
分组
'''
# 分组,但不作为索引
df.groupby("district", as_index=False)['salary'].mean()
# 分组 pandas.core.series.Series 格式
df.groupby("district")['salary'].mean()
df['salary'].groupby(df['district']).mean()
# 分组 pandas.core.frame.DataFrame 格式
df.groupby("district")['salary'].mean().to_frame()
df.groupby("district")[['salary']].mean()
df[['district','salary']].groupby('district').mean()

# 相同的结果
df['salary'].groupby([df['workYear'],
df['education']]).mean()
df.groupby(['workYear', 'education']).mean()['salary']
df.groupby(['workYear', 'education'])['salary'].mean()
df.groupby(['workYear', 'education'])['salary'].agg('mean')

# groupby 用字典
#将 score 和 matchScore 的和记为总分,与 salary 列同时进行分组,并查看结果
df.groupby({'salary':'薪资','score':'总分','matchScore':'总分'}, axis=1).sum()

# 分组计算不同行政区,薪水的最小值、最大值和平均值
df.groupby('district')['salary'].agg([min, max, np.mean])

# 对不同行政区进行分组,并统计薪水的均值、中位数、方差,以及得分的均值
df.groupby('district').agg(
{'salary': [np.mean, np.median, np.std], 'score': np.mean})

#对不同岗位(positionName)进行分组,并统计其薪水(salary)中位数和得分(score)均值
df.groupby('positionName').agg({'salary': np.median, 'score': np.mean})

'''
统计每个区不同大小公司个数
'''
# 方式1:groupby
df.groupby(['district','companySize'])['companySize'].count()
# 方式2:value_counts() 排序按照个数降序
df.groupby("district")['companySize'].value_counts()

# 查看group的结果
df.groupby(["district",'salary']).groups
# 将数据按照 district、salary 进行分组,并查看西湖区薪资为 30000 的工作
df.groupby(["district",'salary']).get_group(("西湖区",30000))

'''
我们将会用到 transform 而不是 apply或者mean。 原因是, transform 将会保持 dataframe 矩阵的形状(shape)(就是行列数不变)而 apply 会改变矩阵的形状。
'''
# 在原数据框 df 新增一列,数值为该区的平均薪资水平
df['该区平均工资'] = df[['district','salary']].groupby(by='district').transform('mean')

# 计算各行政区的企业领域(industryField)包含电商的总数
df.groupby('district')["industryField"].apply(lambda x: x.str.contains('电商').sum())

#通过 positionName 的长度进行分组,并计算不同长度岗位名称的薪资均值
df.set_index("positionName").groupby(len)['salary'].mean()

'''
where 等同于写在df[]中的条件
query 函数我类似sql语言中的where 相当于在df中写sql
filter 类似sql中groupby后的having
'''
# where
work_index.where(work_index['地市']=='厦门市')
# 等价于
work_index.query('地市=="厦门市"')
# 等价于
work_index[work_index['地市']=='厦门市']
# 等价于
work_index.loc[work_index['地市']=='厦门市']

# 提取平均工资小于 30000 的行政区的全部数据
df.groupby('district').filter(lambda x: x['salary'].mean() < 30000)

# 通过匿名函数分组 根据 createTime 列,计算每天不同 行政区 新增的岗位数量
pd.DataFrame(df.groupby([df.createTime.apply(lambda x:x.day)])[
'district'].value_counts()).rename_axis(["发布日", "行政区"])



# 通过 df2 计算获得奖牌最多的运动员
df2['运动员'].value_counts().sort_values(ascending=False).head(1)
#等价于
df.groupby('运动员').count()['奖牌类型'].sort_values(ascending=False).head(1)


# 查看各国在不同项目上的获奖牌情况
# 这里括号内要写df[]
df2['总奖牌数'].groupby([df2['国家'],df2['运动类别']]).count().to_frame()

df2.groupby(['国家','运动类别']).count()['总奖牌数'].to_frame()
pd.pivot_table(df2,values = ['奖牌类型'],index = ['国家','运动类别'],aggfunc = 'count')

# 按照列计算平均值
df.mean(axis='columns')
df.mean(axis=1) #不是0,1是算每列的均值然后然后合并为一行


# 自定义函数
def myfunc(x):
return x.max()-x.mean()

df.groupby('district').agg(最低工资=('salary', 'min'), 最高工资=(
'salary', 'max'), 平均工资=('salary', 'mean'), 最大值与均值差值=('salary', myfunc)).rename_axis(["行政区"])

# 计算 总分、高端人才得分、办学层次得分的最大最小值、中位数、均值
df.agg({
"总分": ["min", "max", "median", "mean"],
"高端人才得分": ["min", "max", "median", "mean"],
"办学层次得分":["min", "max", "median", "mean"]})
  • 查看数据信息
1
2
3
4
5
6
7
8
9
10
11
12
# 查看数据行列数
df.shape
# 查看数据量
df.size
# 查看 数值型 列的统计信息,计数、均值什么的
df.describe()
# 查看 离散型 列的统计信息,计数、频率什么
df.describe(include=['O'])
# 查看 全部 列的统计信息
df.describe(include='all')
# 去除重复的
df['a'].unique()
  • 查看统计数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 查看数据行列数
df.shape
# 查看数据量
df.size
# 查看 数值型 列的统计信息,计数、均值什么的
df.describe()
# 查看 离散型 列的统计信息,计数、频率什么
df.describe(include=['O'])
# 查看 全部 列的统计信息
df.describe(include='all')
# 计算 总分、高端人才得分、办学层次得分的最大最小值、中位数、均值
df.agg({
"总分": ["min", "max", "median", "mean"],
"高端人才得分": ["min", "max", "median", "mean"],
"办学层次得分":["min", "max", "median", "mean"]})
  • 查询
1
2
3
4
5
6
7
8
9
10
11
12
# 查询
df.query('金牌数+银牌数 > 15')
df_01.loc[df_01['行业(按行业大类)'].isin(['工业','建筑业'])]
df_01.loc[(df_01['行业(按行业大类)']=='工业')|(df_01['行业(按行业大类)']=='建筑业')]
df_01[df_01['行业(按行业大类)'].str.contains('工业|建筑业')]


# 提取全部列名中以 “数” 结尾的列
df.loc[:, df.columns.str.endswith('数')]
# 提取第1,2,3,4列
df.iloc[:,0:4]
df.iloc[:,[0,1,2,3]]
  • 查询类型
1
2
df4.select_dtypes(include=['int','float64'])
df4.select_dtypes(exclude=['int','float64'])
  • 数据展开
1
2
# 如果行A和行C存在[a,b,c]这样的列表,我们可以用
df5.explode(['A','C'])
  • 数据累加
1
2
df[list('ABCD')].cumsum()
df[list('ABCD')].cumsum(axis = 1)
  • 按时间进行筛选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
'''
一般来说可以把datetime作为索引,比较方便我们进行筛选操作
'''
# 将DateTime转成日期格式
df['DateTime'] = pd.to_datetime(df['DateTime'])
# 将日期设为index
df = df.set_index('DateTime')
# 筛选从2019年3月1号到2019年3月10号整十天的数据
df1 = df['2019-03-01':'2019-03-10']

'''
如果我们不想或者不好将datetime设置为索引,则可以使用如下方法
'''
# 设置开始时间
from_date = df['DATA_DATE']>='2021-01-01'
# 设置结束时间
to_date = df['DATA_DATE']<='2021-03-31'
# 筛选数据时间段
df = df[from_date&to_date]

# 计算日期加减:
beg = end - pd.Timedelta(days=6)
  • 排序问题
1
2
3
df = pd.DataFrame({'A':[1,1,2,2,3,3],'B':[2,1,5,6,7,9]})
# 先按着A列的值升序,再按着B的顺序降序
df.sort_values(['A','B'],ascending=[True,False])
  • 对df进行自定义排序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
'''
数据量小的情况
'''
df = pd.DataFrame({'A':[1,1,2,2,3,3],'B':[2,1,5,6,7,9]})
# 将索引0和索引3的顺序对调
indx = [3,1,2,0,4,5]
# 如果index过长,可以通过.index获取
df.index
# 使用reindex实现
df.reindex(indx)

'''
数据量大的情况
'''
#df[1:3] = df[3:1]


# index 索引重排序
frame.swaplevel('key1', 'key2')
# 对多个索引排序,按照名称
frame.sort_index(level=1)
# 按照索引值排序
frame.sort_index()

保存文件

1
2
3
4
5
6
# 不保存索引
data.to_csv("out.csv",encoding = 'utf_8_sig',index = False)
# 保存指定列
data.to_csv("out.csv",columns=['positionName','salary'])
# 小数点
mar.to_csv("2-1.csv", index=False, float_format='%.3f')

Tricks

  • 异常值分析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 先看数据,后面na_values后期填写
df = pd.read_csv('xx.csv',na_values=[])
# 每个col去看它的unique()值是否有非法字符,如果有就添加到na_values中
for c in df.columns:
print(df[c].unique())
# 使用head和info查看数据 数值型的数据
df.head()
df.info()
# 如果发现数值数据却是object类型,则转为int/float
df.a = df.a.astype('int')
# 如果提示错误,则可以从错误提示中找到非法字符

# 如果是需要 条件替换的时候
for i in range(1,15):
mean = df[~(df['v_'+str(i)]==0)]['v_'+str(i)].mean()
indx = df[df['v_'+str(i)]==0].index.tolist()
df.loc[indx,'v_'+str(i)] = mean
# 写成这样不行 因为取不到引用
df[df['v_'+str(i)]==0]['v_'+str(i)] = mean
#使用loc可以取 但是[]不行
print(df[~(df['v_'+str(i)]==0)].shape)
  • 数据分析&处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# isnull() is an alias for isna 
# 计算缺失值
df.isna().sum().sum()
# 每列有多少缺失值
df.isnull().sum()
# 查看缺失值
df[df.isnull().T.any() == True]
# 将评价人数列的缺失值,用整列的均值进行填充mean mode median
df['评价人数'] = df['评价人数'].fillna(df['评价人数'].mean())
# 现在将评分列的缺失值,替换为上一个电影的评分
df['评分'] = df['评分'].fillna(axis=0,method='ffill')
# 将评价人数列的缺失值,用上下数字的均值进行填充
df['评价人数'] = df['评价人数'].fillna(df['评价人数'].interpolate())
# 在填充 “语言” 列的缺失值,要求根据 “国家/地区” 列的值进行填充
df['语言']=df.groupby('国家/地区').语言.bfill()
# 查找重复值
df[df.duplicated()]
# 查找指定列的重复值
df[df.duplicated(['片名'])]
# 删除全部的重复值
df = df.drop_duplicates()
# 删除全部的重复值,但保留最后一次出现的值first/last/false
df = df.drop_duplicates(keep = 'last')
# 计算各省市出现的次数
df.省市.value_counts()

# fillna 传字典
pretreat=pretreat.fillna({'v_0':df_mean.v_0,
'v_1':df_mean.v_1,
'v_2':df_mean.v_2,
'v_3':df_mean.v_3,
'v_4':df_mean.v_4,
'v_5':df_mean.v_5,
'v_6':df_mean.v_6,
'v_7':df_mean.v_7,
'v_8':df_mean.v_8,
'v_9':df_mean.v_9,
'v_10':df_mean.v_10,
'v_11':df_mean.v_11,
'v_12':df_mean.v_12,
'v_13':df_mean.v_13,
'v_14':df_mean.v_14
})



'''
dropna: axis=1删除列,axis=0删除行
'''
# 删除整行缺失的数据,剩余缺失数据按0值进行填充
df2 = df2.dropna(how='all').fillna(0)
# 删除某列为空的行
df_initial.dropna(axis = 0, subset = ['客户ID'], inplace = True)
  • 哑变量操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
'''
哑变量操作
'''
cate = df.columns[df.dtypes == "object"].tolist()
# 或者自己指定想要成为哑变量的列
cate = ['col1','col2']
for c in cate:
df = pd.concat([df,pd.get_dummies(df[c],prefix=str(c))],axis=1)
df.drop(c,axis=1,inplace=True)

# 解决int不能哑变量问题,一行solution
pd.get_dummies(df,columns=['用电类别','用电类别','年','月']).info()

# 或者
data[['holiday','month','dayofweek']] = data[['holiday','month','dayofweek']].astype('object')
data = pd.get_dummies(data)
  • 统计空值
1
2
3
4
5
6
7
# 使用apply实现
df1 = pd.DataFrame({'A':['A','B',np.nan,np.nan],'B':[1,2,3,np.nan]})
df1.apply(lambda x:x.size - x.count())
# 使用isna、isnull实现
df1.isna().sum() #isna()返回的是个bool类型的矩阵,进行加和运算True默认为1,False默认为0,因此可以通过sum()函数来统计
# 统计每个空值的比例
df1.isna().mean() # mean() 相当于 True的个数/sum()的个数
  • 计算最近的数
1
2
# 通过abs来计算距离,然后通过sort_values来算最小的数
df.val.apply(lambda x:abs(x-1)).sort_values()

matplotlib

1
fig,axis = plt.subplots(figsize=(10,8))

Tips

屏蔽提醒

1
2
import warnings
warnings.filterwarnings('ignore')

显示中文

1
2
3
4
5
6
7
# win设置中文
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号

# mac设置中文
plt.rcParams['font.family'] = 'Heiti TC'#用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号

关于iloc和[]选择赋值失败问题

1
2
3
4
5
6
7
8
9
10
11
12
df['2018-07']['a'] 取出数字,不能赋值
df.loc['2018-07']['a']
df.iloc[10,1]
df.iloc[1][2]

df.iloc[-31:]['DailyElectricity']=0

df[-31:]['DailyElectricity']=0
'''均不能改变原df
因为他们仅仅是取出来的值,而不是引用'''

# 给一个Series赋值另外一个Series需要reset_index() (保证index相同)
  • Jupyter
1
2
3
4
5
np.add? # 显示帮助
np.add?? # 显示源代码
# fsting用法 python>=3.6
number = 7
f'My lucky number is {number}'