Pandas(1):数据选取/条件筛选小结

小结一下Pandas 筛选表格数据子集的方法作为速查手册……实际中数据处理分析及可视化往往只是数据表的一部分,因此经常需要进行:选取特定位置、特定日期、特定数值(如文本、空值)、或者满足若干组合条件的行、列等处理,这里简单汇总一下主要有以下几类,理论上基于代码我们可以实现任何想得到的处理

  1. 位置筛选(与表中数值无关,仅取决于行列号或行列名),最常用df.iloc[ , ]
  2. 条件筛选df.loc[条件](与数值相关,根据若干符合条件(特定值或范围)选取数据子集)
  3. 复杂条件筛选(自定义函数df.apply的运用)

数据预览

日常涉及数据类型主要有:数字、字符串、时间日期格式。

测试数据导入及查看基本信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pandas as pd
filepath = "F:/weibo2017/Dataset/s3_day/1/2017-01-01.csv"
# 取前1000行测试即可
df = pd.read_csv(filepath, header=0, parse_dates=['PubTime', 'date'], nrows=1000)
# 查看数据字段类型及信息
df.info()
df.columns.to_list()# 导出列
# 预览后剔除冗余列
usecols = ['_id','Tools']
df = df.drop(columns=usecols)
# 查看表格形状,行列数
df.shape # nrows = df.shape[0]
# 查看前几行或后几行
df.head(7)
df.tail(7)

位置筛选

Python默认从0开始索引.

行列号切片

  • 切片时选取\([a,b]\)默认为 数学中的左闭右开\([a,b)\),因此总的个数为\(b-a\)

  • 一般情况单列返回类型Series,多列或多行则返回DataFrame

  • 大多数情况,可以访问也可以修改值

主要函数:df.iloc[], df.iat[], df.at[]

原则:传入一个值或一个list时返回若干行;传入两个参数时,返回对应行及列的筛选

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
# 一个参数
df.iloc[2] # 以Series类型返回第二行数据
df.iloc[1:4] #返回2 3 4行
df.iloc[[2,4,6]] #返回 3 5 7行
# 两个参数
df.iloc[6,4] #第六行第四列
df.iloc[1:4,:] #返回2 3 4行的表格
df.iloc[1:4, 2:4] #返回2~5行,3到5列的表格
df.iloc[[1,3,5], 5] #返回2 4 6行,第五列的表格
df.iloc[[1,3,5], 5].values # 取值

#df.at获取或就地更改第四行'B'列的数值,4为行索引名称
df.at[4, 'B']
df.at[4, 'B'] = 10

## 选取或更改单个值
df.iat[4,4] #访问第五行第五列的数值
df.iat[3,3]=2 #就地更改第四行第四列的数值

# 行索引选取
df = df.set_index('gridid') #比如可以先设置id为索引再访问
df.loc[[1,2,3]] # 多行,这里的1 2 3是索引的名字
df.loc[[1,2,3]]['colname'] # 多行某列,取值则df.loc[[1,2,3]]['colname'].values

# 列选取
usecol = ['_id','Content']# usecol = ['_id']
new_df = df[usecol] #一列或多列都是返回dataframe

选择某一列值对应同行的单个其他值

1
2
# 这张表有很多列,我想根据城市挨个获取其对应的省份id
province = list(cities.loc[cities.city == "宜春"]['province_id'])[0]

创建新行列

df创建列:直接df[]新建,右侧为值或者series或series的元组

1
2
df['列1'] = ...# 新建一列
df[['列1','列2']] = ...# 新建多列

df新建行:或者追加一个同样的dataframe及多行,简单示意,更多的关于表格拼接和合并单写,需注意==列名及个数一致==。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 新建一个表格并追加一行数据
df = pd.DataFrame(columns=['c1', 'c2', 'c3'])
df.loc[0] = {'c1':1,'c2':2, 'c3':3}
## 追加两行
df = df.append([{'c1':1,'c2':2, 'c3':3},{'c1':2,'c2':3, 'c3':4}], ignore_index=True)

## 循环或遍历追加行
df.loc[i]={'c':1,'c2':2, 'c3':3}
values = [1,2,3]
df.loc[df.shape[0]] = dict(zip(df.columns, values))
# 表格合并/追加
df1 = df1.append(df2, ignore_index=True)# 追加一个格式一样的表格,等价于
df1 = pd.concat([df1,df2], axis=0)

条件筛选行df.loc

多个条件使用: 与(&), 或(|), 非(!), 及取反(~)/即补集,

主要函数df.loc,条件过多或繁琐则参考第三节apply

条件筛选的实质是先根据条件生成一个这样的数组:[True, False, False,...],再根据这个数组匹配

特定值

1
2
3
4
5
6
7
8
9
10
Con = df['Comment'].isna() # na值筛选
Con= df['Comment'].isnull() # null值筛选
Con = df['Comment'].isin([a,b,c,...]) # 包含值列表筛选
# 选取并构造新的df
df2 = df.loc[Con]
# 当然为了简介通常写在一起
df2 = df.loc[df['Comment'].isna()]
df2 = df.loc[df['Comment'].isin([a,b,c,...])]
df2 = df.loc[df['Comment'].str.contains("a")]
...

范围值

1
2
3
4
5
6
Con = df['hour']==3
Con = df['hour']>=23
df2 = df.loc[Con]
df2 = df.loc[(df['date']=='2017-01-01') & (df['Transfer']>6)]
# 筛选hour<=3的行
df2 = df.loc[~(df['hour']>3)]

复杂条件筛选

个人建议通过类似 df.apply(lambda x: myfun(x)) 的方式实现

即自定义一个新的函数生成新列,再筛选,如:

1
2
3
4
5
6
7
def myfun(x):
if x>3:
return 0
elif x>0:
retuen 1
else:
retuen 2

有几种形式,一种是单列输入单输出,这里的lambda x就是每一行的该列(df[col])的值

  • df[newcol] = df[col].apply(lambda x: myfun(x))

有时候需要多列参与运算,结果是返回单个值

如函数为myfun(x, y),即有多个输入,这种情况x是代表一行,建议写成row,因此需要指定值

  • df[col] = df.apply(lambda row: myfun(row[col1],row[col2]), axis=1)
1
df['datetime'] =  df.apply(lambda row: datetime(row.year, row.month, row.day, row.hour), axis=1)

如果输入输出都得是多列的,则需要通过zip函数拆包并新建多个列来接收,

举例df[],df[]... = zip(*df.apply()):其他情况类推

1
2
3
def myfun(x,y):
return x,y
df['x'], df['y'] = zip(*df.apply(lambda row: myfun(row['Co_oridinate1'],row['Co_oridinate2']), axis=1))

关于更多函数的运用后续小结