Pandas 数据处理
一、数据IO操作
pandas IO操作主要是读取和写入有特定格式的文件,如CSV文件、TXT文件:
# 本质上pd.read_csv和pd.read_tablepd.read_table的读取方式是一样的,区别只在于分隔符的不同
pd.read_csv('csv文件.csv', sep=',', header=None, index_col=0)
pd.read_table('txt文件.txt', header=None, sep=' ', index_col=0)
pd.read_csv('txt文件.txt', header=None, sep='-', index_col=0)
pd.read_csv('txt文件.txt', header=None, sep='\s+', index_col=0) # 特别的,如果文件中的分隔符是数量不等的空格,则可以使用‘\s+’来分隔
# 写入文件
data.to_csv('m_data.csv')
data.to_txt('m_data.txt')
读写 excel 文件:
# names参数在pd.read_csv和pd.read_table中同样适用
# sheet_name=‘子表名’或sheet_name=0,1,2,3....(字表索引)
data = pd.read_excel('excel文件.xlsx', header=None, names=['姓名','年龄','地址'], sheet_name='Sheet1')
# 写入文件
data.to_excel('m_data.xlsx')
二、数据探索
describe()
df = pd.DataFrame(data=np.random.randint(0, 10000, size=(10000, 4)), columns=list('ABCD'))
print(df)
>>输出结果:
A B C D
0 235 5192 905 7813
1 2895 5056 144 4225
2 7751 3462 9394 5396
3 5374 2962 2516 8444
4 3562 4764 8093 6542
... ... ... ... ...
9995 1955 1727 214 8554
9996 7270 394 3708 9126
9997 5708 1119 2991 5106
9998 6006 9326 2398 9332
9999 582 1060 3400 2763
[10000 rows x 4 columns]
result1 = df.describe()
print(result1)
>>输出结果:
A B C D
count 10000.000000 10000.00000 10000.000000 10000.000000
mean 4998.050200 5012.53500 4969.470800 5011.821100
std 2903.766726 2892.84581 2875.261794 2908.972103
min 0.000000 0.00000 2.000000 0.000000
25% 2435.750000 2473.75000 2490.750000 2485.000000
50% 5032.500000 5050.00000 4947.500000 5036.500000
75% 7542.000000 7505.00000 7481.250000 7513.250000
max 9998.000000 9999.00000 9999.000000 9999.000000
result2 = df.describe(percentiles=[0.99])
print(result2)
>>输出结果:
A B C D
count 10000.000000 10000.00000 10000.000000 10000.000000
mean 4998.050200 5012.53500 4969.470800 5011.821100
std 2903.766726 2892.84581 2875.261794 2908.972103
min 0.000000 0.00000 2.000000 0.000000
50% 5032.500000 5050.00000 4947.500000 5036.500000
99% 9886.010000 9901.02000 9896.010000 9905.030000
max 9998.000000 9999.00000 9999.000000 9999.000000
result3 = df.describe(percentiles=[0.99]).T
print(result3)
>>输出结果:
count mean std min 50% 99% max
A 10000.0 4998.0502 2903.766726 0.0 5032.5 9886.01 9998.0
B 10000.0 5012.5350 2892.845810 0.0 5050.0 9901.02 9999.0
C 10000.0 4969.4708 2875.261794 2.0 4947.5 9896.01 9999.0
D 10000.0 5011.8211 2908.972103 0.0 5036.5 9905.03 9999.0
info()
result = df.info()
print(result)
>>输出结果:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10000 entries, 0 to 9999
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 A 10000 non-null int32
1 B 10000 non-null int32
2 C 10000 non-null int32
3 D 10000 non-null int32
dtypes: int32(4)
memory usage: 156.4 KB
head()、tail()
result1 = df.head()
print(result1)
>>输出结果:
A B C D
0 235 5192 905 7813
1 2895 5056 144 4225
2 7751 3462 9394 5396
3 5374 2962 2516 8444
4 3562 4764 8093 6542
result2 = df.tail()
print(result2)
>>输出结果:
A B C D
9995 1955 1727 214 8554
9996 7270 394 3708 9126
9997 5708 1119 2991 5106
9998 6006 9326 2398 9332
9999 582 1060 3400 2763
result3 = df.tail(n=2)
print(result3)
>>输出结果:
A B C D
9998 6006 9326 2398 9332
9999 582 1060 3400 2763
sample()
result = df.sample(n=10)
print(result)
>>输出结果:
A B C D
8993 3251 4631 1932 2136
9753 7505 7822 4652 4019
6851 9831 2690 7266 5411
8044 141 5710 9001 2606
3594 951 297 9461 6519
7103 470 6780 1165 8743
3402 6804 1615 9748 1658
8361 2082 4687 868 9105
7230 9674 9832 3070 1007
9995 1955 1727 214 8554
三、空值处理
3.1 None和np.nan(NaN)
-
None是Python自带的,其类型为python object。因此,None不能参与到任何计算中。object类型的运算要比float类型的运算慢得多。
-
np.nan是浮点类型,能参与到计算中。但计算的结果总是NaN。在numpy中,可以使用np.nanxxx()函数来计算nan,此时视nan为0。
print(type(None))
>>输出结果:
NoneType
print(type(np.nan))
>>输出结果:
float
def get_sum(x):
return x.sum()
data1 = np.arange(1000000, dtype=object)
%timeit get_sum(data1)
>>输出结果:
23.2 ms ± 708 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
data2 = np.arange(1000000, dtype=np.float)
%timeit get_sum(data2)
>>输出结果:
1.21 ms ± 62.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
3.2 pandas自动把None处理成np.nan
-
np.nan 是 numpy 提供的一个常量,用于表达空值,是一个float类型。
-
NaN(not a number) 是一个符号,不是一个常量, pandas对象中,所有的 np.nan 和 None 显示的时候,都是以NaN显示。类似的还有NaT (not a time)。
df = pd.DataFrame(data=np.random.randint(0, 10, size=(10, 2)), columns=['A','B'])
print(df)
>>输出结果:
A B
0 5 1
1 2 0
2 9 6
3 2 8
4 5 8
5 4 3
6 4 1
7 5 5
8 0 7
9 0 6
df.loc[2] = None
print(df)
>>输出结果:
A B
0 5.0 1.0
1 2.0 0.0
2 NaN NaN
3 2.0 8.0
4 5.0 8.0
5 4.0 3.0
6 4.0 1.0
7 5.0 5.0
8 0.0 7.0
9 0.0 6.0
3.3 空值查找
isnull()、notnull()
df = pd.DataFrame(data=np.random.random(size=(10, 4)), columns=list('ABCD'))
df.loc[2] = np.nan
df.loc[4, 'B'] = np.nan
df.loc[5, 'D'] = np.nan
df.loc[9, ['A','B']] = np.nan
print(df)
>>输出结果:
A B C D
0 0.726244 0.078825 0.239853 0.870938
1 0.961002 0.205138 0.678396 0.366292
2 NaN NaN NaN NaN
3 0.820113 0.575757 0.302384 0.817682
4 0.897944 NaN 0.427351 0.036945
5 0.888940 0.932362 0.494705 NaN
6 0.056371 0.410048 0.992545 0.828778
7 0.431613 0.260433 0.779346 0.851420
8 0.325942 0.721456 0.177086 0.440415
9 NaN NaN 0.150183 0.720072
result1 = df.isnull().any() # 默认列方向的any操作
print(result1)
>>输出结果:
A True
B True
C True
D True
dtype: bool
result2 = df.isnull().any(axis=1)
print(result2)
>>输出结果:
0 False
1 False
2 True
3 False
4 True
5 True
6 False
7 False
8 False
9 True
dtype: bool
# 找出所有包含至少一个空值的行
result3 = df.loc[df.isnull().any(axis=1)]
print(result3)
>>输出结果:
A B C D
2 NaN NaN NaN NaN
4 0.295703 NaN 0.233566 0.557783
5 0.168698 0.298293 0.674066 NaN
9 NaN NaN 0.905542 0.187831
# 找出全都不为空的行
result4 = df.loc[df.notnull().all(axis=1)]
print(result4)
>>输出结果:
A B C D
0 0.971378 0.695311 0.453382 0.028843
1 0.081022 0.380908 0.161295 0.464460
3 0.321058 0.541224 0.456106 0.680896
6 0.965566 0.084760 0.107426 0.056833
7 0.195171 0.938648 0.759900 0.683615
8 0.197814 0.516687 0.076623 0.009585
# 查看某一列的空值占比
result5 = df.isnull().mean()
print(result5)
>>输出结果:
A 0.2
B 0.3
C 0.1
D 0.2
dtype: float64
3.4 空值填充
-
整个表格中的统一填充方法
df.fillna(value=0)
-
使用均值来填充空值
df.fillna(value=df.mean())
-
使用临近值填充,不需要再指定value
df.fillna(method='backfill', axis=1) df.fillna(method='ffill', axis=1,limit=1)
3.5 空值过滤
-
结合isnull、notnull、any all 来确定一个条件,然后再利用loc访问,实现过滤
df.loc[df.notnull().any(axis=1)]
-
dropna()
df.dropna(axis=0, how='any') df.dropna(axis=0, how='all', subset=['B','A'], inplace=True)
四、异常值处理
体育比赛里,最后算分的时候总会去掉一个最高分,去掉一个最低分,将剩下的分数进行去平均。因为一个非常夸张的异常值可能会造成对最后统计结果产生比较大的影响。所以,异常值处理,在统计数据的过程中是必然要做的一个操作。
4.1 异常值分析
使用describe()函数查看每一列的描述性统计量
4.2 处理异常值
-
不符合业务逻辑的异常值
cond = df['关注字段'] != '关注的内容' df.loc[cond]
-
使用均值和标准差进行判断
df = pd.DataFrame(data=np.random.randn(10000, 4), columns=list('ABCD')) # 异常值判断条件 exp_condition = (np.abs(df) > df.std()*3).any(axis=1) # 获取异常值对应的索引 exp_index = df.loc[exp_condition].index # 删除异常值对应索引的值 df1 = df.drop(labels=exp_index, axis=0)
-
使用上四中位数和下四中位数进行异常值判定
order = pd.read_excel('电商用户数据.xlsx') order.info() >>输出结果: <class 'pandas.core.frame.DataFrame'> RangeIndex: 28833 entries, 0 to 28832 Data columns (total 8 columns): 买家昵称 28833 non-null object 付款日期 28833 non-null datetime64[ns] 订单状态 28833 non-null object 实付金额 28833 non-null int64 邮费 28833 non-null int64 省份 28833 non-null object 城市 28832 non-null object 购买数量 28833 non-null int64 dtypes: datetime64[ns](1), int64(3), object(4) memory usage: 1.8+ MB order.describe(percentiles=[.99]) >>输出结果: 实付金额 邮费 购买数量 count 28833.000000 28833.000000 28833.000000 mean 126.266570 0.245240 1.510942 std 73.771696 1.386435 1.483478 min 30.000000 0.000000 1.000000 50% 115.000000 0.000000 1.000000 99% 269.000000 8.000000 6.000000 max 4225.000000 18.000000 100.000000 Q1, Q3 = np.quantile(order['实付金额'], q=[0.25, 0.75]) IQR = Q3 - Q1 BOTTOM = Q1 - 1.5*IQR UPPER = Q3 + 1.5*IQR condition = (order['实付金额'] > UPPER).values | (order['实付金额'] < BOTTOM).values exp_index = order.loc[condition].index order.drop(index=exp_index).describe() >>输出结果: 实付金额 邮费 购买数量 count 28811.000000 28811.000000 28811.000000 mean 125.846656 0.245427 1.491444 std 68.639111 1.386947 1.072723 min 30.000000 0.000000 1.000000 25% 72.000000 0.000000 1.000000 50% 114.000000 0.000000 1.000000 75% 178.000000 0.000000 2.000000 max 336.000000 18.000000 20.000000
五、重复值处理
df = pd.DataFrame(data=np.random.randint(0, 100, size=(10,5)), columns=list('abcde'))
df.loc[2] = df.loc[6]
df.loc[3] = df.loc[7]
df.loc[8] = df.loc[7]
df.loc[2, 'a'] = 100
print(df)
>>输出结果:
a b c d e
0 82 63 48 90 25
1 84 52 55 38 6
2 100 81 48 12 22
3 17 95 19 22 81
4 61 8 95 17 93
5 13 56 64 78 59
6 20 81 48 12 22
7 17 95 19 22 81
8 17 95 19 22 81
9 11 10 99 95 54
# 检查
condition = df.duplicated(keep='last', subset=list('bcde'))
# keep:保留首次出现的重复值first还是最后一次出现的重复值last
# subse:指定,用来判断重复值的列索引
>>输出结果:
0 False
1 False
2 True
3 True
4 False
5 False
6 False
7 True
8 False
9 False
dtype: bool
# 过滤
df.loc[(condition - 1).astype(bool)]
>>输出结果:
a b c d e
0 82 63 48 90 25
1 84 52 55 38 6
4 61 8 95 17 93
5 13 56 64 78 59
6 20 81 48 12 22
8 17 95 19 22 81
9 11 10 99 95 54
# 删除
df.drop_duplicates(subset=list('bcde'), keep='last',)
>>输出结果:
a b c d e
0 82 63 48 90 25
1 84 52 55 38 6
4 61 8 95 17 93
5 13 56 64 78 59
6 20 81 48 12 22
8 17 95 19 22 81
9 11 10 99 95 54
六、Pandas排序与随机抽样
排序
df1 = df.sort_values(by='a', ascending=False)
print(df1)
>>输出结果:
a b c d e
2 100 81 48 12 22
1 84 52 55 38 6
0 82 63 48 90 25
4 61 8 95 17 93
6 20 81 48 12 22
3 17 95 19 22 81
7 17 95 19 22 81
8 17 95 19 22 81
5 13 56 64 78 59
9 11 10 99 95 54
# 指定多条件排序
df2 = df.sort_values(by=['b','a'], ascending=True)
print(df2)
>>输出结果:
a b c d e
4 61 8 95 17 93
9 11 10 99 95 54
1 84 52 55 38 6
5 13 56 64 78 59
0 82 63 48 90 25
6 20 81 48 12 22
2 100 81 48 12 22
3 17 95 19 22 81
7 17 95 19 22 81
8 17 95 19 22 81
df3 = df2.sort_index(ascending=False)
print(df3)
>>输出结果:
a b c d e
9 69 16 67 25 89
8 4 19 2 56 0
7 4 19 2 56 0
6 60 52 51 15 13
5 19 8 60 96 55
4 82 48 54 68 5
3 4 19 2 56 0
2 100 52 51 15 13
1 80 87 26 82 15
0 20 96 63 93 23
随机取出行或列
df1 = df.sample(n=3, axis=1)
print(df1)
>>输出结果:
d b a
0 93 96 20
1 82 87 80
2 15 52 100
3 56 19 4
4 68 48 82
5 96 8 19
6 15 52 60
7 56 19 4
8 56 19 4
9 25 16 69
df2 = df.take([1,1,2,2,3,3], axis=1)
print(df2)
>>输出结果:
b b c c d d
0 96 96 63 63 93 93
1 87 87 26 26 82 82
2 52 52 51 51 15 15
3 19 19 2 2 56 56
4 48 48 54 54 68 68
5 8 8 60 60 96 96
6 52 52 51 51 15 15
7 19 19 2 2 56 56
8 19 19 2 2 56 56
9 16 16 67 67 25 25
七、索引设置
把指定字段设置为索引
df1 = df.set_index(keys=['a','b'])
print(df1)
>>输出结果:
c d e
a b
20 96 63 93 23
80 87 26 82 15
100 52 51 15 13
4 19 2 56 0
82 48 54 68 5
19 8 60 96 55
60 52 51 15 13
4 19 2 56 0
19 2 56 0
69 16 67 25 89
把指定索引设置为字段
df2 = df1.reset_index(level=-1)
print(df2)
>>输出结果:
b c d e
a
20 96 63 93 23
80 87 26 82 15
100 52 51 15 13
4 19 2 56 0
82 48 54 68 5
19 8 60 96 55
60 52 51 15 13
4 19 2 56 0
4 19 2 56 0
69 16 67 25 89
按照指定的索引,进行索引重置(如果原始索引中存在,则选择,如果不存在,则空值填充)
df3 = df2.reindex(labels=['b','c','d','f'], axis=1)
print(df3)
>>输出结果:
b c d f
a
20 96 63 93 NaN
80 87 26 82 NaN
100 52 51 15 NaN
4 19 2 56 NaN
82 48 54 68 NaN
19 8 60 96 NaN
60 52 51 15 NaN
4 19 2 56 NaN
4 19 2 56 NaN
69 16 67 25 NaN
多层索引的删除
df4 = df1.droplevel(level=-1,axis=0) # level:指定要删除的索引层级
八、映射处理
rename
df.rename(mapper=lambda x: str(x)+'产品', axis=1)
>>输出结果:
a产品 b产品 c产品 d产品 e产品
0 20 96 63 93 23
1 80 87 26 82 15
2 100 52 51 15 13
3 4 19 2 56 0
4 82 48 54 68 5
5 19 8 60 96 55
6 60 52 51 15 13
7 4 19 2 56 0
8 4 19 2 56 0
9 69 16 67 25 89
dic = {'a':'A', 'b':'B', 1:'HHH', 2:'GGG'}
df.rename(index=dic)
>>输出结果:
a b c d e
0 20 96 63 93 23
HHH 80 87 26 82 15
GGG 100 52 51 15 13
3 4 19 2 56 0
4 82 48 54 68 5
5 19 8 60 96 55
6 60 52 51 15 13
7 4 19 2 56 0
8 4 19 2 56 0
9 69 16 67 25 89
df.rename(columns=dic)
>>输出结果:
A B c d e
0 20 96 63 93 23
1 80 87 26 82 15
2 100 52 51 15 13
3 4 19 2 56 0
4 82 48 54 68 5
5 19 8 60 96 55
6 60 52 51 15 13
7 4 19 2 56 0
8 4 19 2 56 0
9 69 16 67 25 89
replace
df = pd.DataFrame(data=np.random.randint(0,100,size=(5,4)), columns=list('ABCD'))
>>输出结果:
A B C D
0 43 92 1 15
1 15 61 77 2
2 13 24 8 83
3 73 4 60 7
4 96 92 80 77
# list替换
df.replace(to_replace=[73, 77], value=['hello', 'hello world'], inplace=True)
>>输出结果:
A B C D
0 43 92 1 15
1 15 61 hello world 2
2 13 24 8 83
3 hello 4 60 7
4 96 92 80 hello world
# dict替换
df.replace(to_replace={83:'hehe', 43:'good'}, inplace=True)
>>输出结果:
A B C D
0 good 92 1 15
1 15 61 hello world 2
2 13 24 8 hehe
3 hello 4 60 7
4 96 92 80 hello world
# 特殊用法:指定列替换。字典的键是列名称,字典的值是该列里面的要替换的值
df.replace(to_replace={'A':'hello'}, value='hELLO')
>>输出结果:
A B C D
0 good 92 1 15
1 15 61 hello world 2
2 13 24 8 hehe
3 hELLO 4 60 7
4 96 92 80 hello world
# regex替换
df.replace(to_replace=r'h.*',value='H',regex=True, inplace=True)
>>输出结果:
A B C D
0 good 92 1 15
1 15 61 H 2
2 13 24 8 H
3 H 4 60 7
4 96 92 80 H
# 相邻值替换
df.replace(to_replace='H', method='bfill', limit=1)
>>输出结果:
A B C D
0 good 92 1 15
1 15 61 2 2
2 13 24 8 H
3 4 4 60 7
4 96 92 80 H
map,支持Series对象
D = df['B']
>>输出结果:
0 92
1 61
2 24
3 4
4 92
Name: B, dtype: int64
# 模糊匹配
def score_map(x):
if x >= 60:
return '及格'
else:
return '不及格'
D_re = D.map(score_map)
print(D_re)
>>输出结果:
0 及格
1 及格
2 不及格
3 不及格
4 及格
Name: B, dtype: object
# 精确匹配
map_dic = {
'及格':True,
'不及格':False
}
D_re.map(map_dic)
>>输出结果:
0 True
1 True
2 False
3 False
4 True
Name: B, dtype: bool