需要解决的问题:
import pandas as pd
import numpy as np
df = pd.DataFrame([[1,np.nan,3],[4,5,6],[7,np.nan,9]],columns=['A','B','C'])
print(df)
怎样将0、2行 B 、C列数值替换A、B 两列的数值 (即数据左移一列)?
一、方法介绍
所使用的方法:将需要错位的数据块筛出构造新表,采用2表 更新的方式
(一)、错位块的处理方式(将错位的地方换回来)
1、整列赋值的方式【强烈建议】
df1 = df.copy()
df1
temp = df1.loc[[0,2],] # df.loc[],是根据行列的名字来选择
temp
处理过程:
# 将C列内容赋值给B列,C列用np.nan填充
for i,j in enumerate(temp.columns):
if i>0: # 从第2列起,开始错位
temp.iloc[:,i] = temp.iloc[:,i+1] # 将后一列内容赋值给前一列
temp.iloc[:,i+1] = np.nan # # 将最后一列用np.nan填充
if i==len(temp.columns)-2: # 当遍历到最后一列时,结束循环
break
temp
2、取全部数据,删除多余空列,添加一列nan,重命名,更新原表【建议】
df1_2 = df.copy()
df1_2
temp1_2 = df1_2[df1_2['B'].isna()]
temp1_2
处理过程:
temp1_2 = temp1_2.drop(columns=['B']) # 删除错位开始的“B”列
temp1_2
temp1_2['add'] = np.nan # 最后添加一列,用np.nan来填充
temp1_2
temp1_2 = pd.DataFrame(temp1_2.values, index=temp1_2.index, columns=df1_2.columns) # 重新构造DataFrame
temp1_2
3、取b、c列,添加一列nan,重命名,更新原表
df3 = df.copy()
df3
temp3 = df1.iloc[[0,2],] # df.iloc[],是根据行列的位置顺序来选择【有时行索引为2,但位置顺序为1,注意与df.loc[]的区别】
temp3
处理过程:
temp3 = temp3.loc[:,'B':] # 错位开始的“B”列及之后的列
temp3
temp3['add'] = np.nan # 最后添加一列,用np.nan来填充
temp3
temp3 = pd.DataFrame(temp3.values, index=temp3.index, columns=df3.columns) # 重新构造DataFrame
temp3
temp3 = temp3.drop(columns = ['A']) # 删除temp3中未错位的列
temp3
(二)、更新原数据的方式
1、运用等号赋值:“=”【建议】
df1 = df.copy()
df1
temp
df1[df1['B'].isna()]=temp # 等号左边只能用df1[df1['B'].isna()]的形式
df1
# ps: 等号左边以df.loc()、df.iloc()、df.iloc[0:1] 都形式会报错,如:df1.loc[[0,2],] = temp 会报错
注意:等号赋值时,需要进行整行的赋值操作。若等号右边只是行的一部分切片列,那么没出现的列,左边的会显示为缺失值:np.nan
例如:
df1 = df.copy()
df1
df1[df1['B'].isna()]
temp.loc[:,'B':'C'] # 等号右边只是行的一部分切片列:B、C列
df1[df1['B'].isna()] = temp.loc[:,'B':'C']
df1 # 可以看到原来A列的 1、7,全部改成了缺失值:nan,因为等号右边对应行索引的的位置,没有A列内容
总结:使用等号:“=” 赋值时,必须整行整行的赋值。
2、运用:df.update() 来更新数据
df2 = df.copy()
df2
temp2 = temp.copy()
temp2
type(temp2.loc[0,'C'])
# 1、正确的操作
# 1)先把temp2的字段 全转换成字符型
temp2 = temp2.astype('str')
# 2)运用update
df2.update(temp2) # update会直接在原数据的基础上更新数据
# 3)最后按需求将字符的nan 替换成np.nan
df2 = df2.replace('nan',np.nan)
print(df2,'\n------')
print(df2.loc[0,'C'], type(temp.loc[0,'C']))
# 2、错误的操作:不先改变缺失值nan的类型,直接运用update。此时缺失值nan不能覆盖原来的数据
print(temp2.loc[0,'C'], type(temp2.loc[0,'C']), '\n----')
df2.update(temp2)
df2
总结:
- 1、与等号:“=”对比df.update()不要求整行,只对对应位置进行数据的更新(行索引,列索引相同的位置)
- 2、注意,使用df.update()时,缺失值nan不能覆盖原来的数据。可以先转换为字符型,更新后再转回需要的格式
3、运用:df.combine_first() 来更新数据
df3 = df.copy()
df3
temp3 = temp.copy()
temp3
# 1、正确的操作
# 1)先把temp3的字段 全转换成字符型
print(temp3.loc[0,'C'], type(temp3.loc[0,'C']),'\n------')
temp3 = temp3.astype('str')
print(temp3.loc[0,'C'], type(temp3.loc[0,'C']),'\n------')
# 2)运用combine_first
temp3.combine_first(df3) # 【temp3和地方相同位置存在元素时,会优先保留temp3的数据】combine_first不会直接在原数据的基础上更新数据
# 3)最后按需求将字符的nan 替换成np.nan
df3 = df3.replace('nan',np.nan)
print(df2,'\n------')
print(df2.loc[0,'C'], type(temp.loc[0,'C']))
# 2、错误的操作:不先改变缺失值nan的类型,直接运用combine_first。此时会覆盖原来的缺失值nan
print(temp3.loc[0,'C'], type(temp3.loc[0,'C']), '\n----')
temp3.combine_first(df3)
(二)、错位处理案例
path = r'C:\Users\...\Desktop\read_test\订单信息.csv'
order = pd.read_csv(path ,delimiter=',',encoding = 'UTF-8',skip_blank_lines=True,header=0) # 跳过空行,第一行为标题行,编码为utf-8
order.tail() # 后面几行(699995:699997行)<订单类型>列有错位
# 单独查看错位的行
order[order['订单类型'].isna()]
# 将需要错位的行单独筛选出来处理
temp = order[order['订单类型'].isna()]
for i,j in enumerate(temp.columns):
if i>0:
temp.iloc[:,i] = temp.iloc[:,i+1]
temp.iloc[:,i+1] = np.nan
if i==len(temp.columns)-2:
break
temp
# 对原数据利用等号的方式重新赋值
order[order['订单类型'].isna()] = temp
order.tail()
——————
此时,利用pandas以将错位的行调整完毕