Pandas数据处理-筛选数据

使用demo.csv举几个栗子~

编号,日期,单价,数量
T001,2018-03-02 12:34:05,100,3
T002,2018-03-02 13:04:05,200,3
T003,2018-03-03 18:12:31,30,10
T004,2018-03-04 20:34:05,400,2
T005,2018-03-02 20:34:05,500,1
import pandas as pd

df = pd.read_csv('demo.csv', index_col='编号') # 指定行标签 label
"""
                    日期   单价
编号                            
T001  2018-03-02 12:34:05  100
T002  2018-03-02 13:04:05  200
T003  2018-03-03 18:12:31   30
T004  2018-03-04 20:34:05  400
T005  2018-03-02 20:34:05  500
"""

如果不指定 index_col,则会默认生成 0 - 5的行标签,这种情况下,行标签与行号相等。

行标签可以理解为这一行的区别于其他行的标志(类似SQL中的主键)

df_without_index_col = pd.read_csv('demo.csv')
"""
     编号                   日期   单价  数量
0  T001  2018-03-02 12:34:05  100   3
1  T002  2018-03-02 13:04:05  200   3
2  T003  2018-03-03 18:12:31   30  10
3  T004  2018-03-04 20:34:05  400   2
4  T005  2018-03-02 20:34:05  500   1
"""

一、选取列

1. 使用方括号

df[['日期', '单价']]
"""
                     日期   单价
编号                            
T001  2018-03-02 12:34:05  100
T002  2018-03-02 13:04:05  200
T003  2018-03-03 18:12:31   30
T004  2018-03-04 20:34:05  400
T005  2018-03-02 20:34:05  500
"""
df[['单价']] # -> DataFrame
"""
       单价
编号       
T001  100
T002  200
T003   30
T004  400
T005  500
"""
type(df[['单价']]) # <class 'pandas.core.frame.DataFrame'>
df['单价'] # -> Series
"""
编号
T001    100
T002    200
T003     30
T004    400
T005    500
Name: 单价, dtype: int64
"""
type(df['单价']) # <class 'pandas.core.series.Series'>

二、选取行

1. 行标签使用loc

可接受2个参数,第一个参数是行标签,第二个参数是列标签

  • 行标签为T002的行
df.loc['T002'] #  -> Series
"""
日期    2018-03-02 12:34:05
单价                    100
数量                      3
Name: T001, dtype: object
"""
  • 行标签从T002到 T004的行(与切片不同,这种情况下包含开头也包含结束)
df.loc['T002':'T004']  # -> DataFrame
"""
                       日期   单价  数量
编号                                
T002  2018-03-02 13:04:05  200   3
T003  2018-03-03 18:12:31   30  10
T004  2018-03-04 20:34:05  400   2
"""
  • 行标签从T002到最后的行,且只选取单价和数量2列
df.loc['T002':, ['单价', '数量']] # -> DataFrame
# 等价于 df.loc['T002':][['单价', '数量']]
"""
       单价  数量
编号           
T002  200   3
T003   30  10
T004  400   2
T005  500   1
"""

2. 行号使用iloc

  • 第1行到倒数第2行

iloc参数是一个slice对象,和python中可迭代对象用法是一致的。[start, end, step)。

下标从0开始,包含开头,不包含结束。

df.iloc[1:-2] # -> DataFrame,不包含 -2 行
"""
                       日期   单价  数量
编号                                
T002  2018-03-02 13:04:05  200   3
T003  2018-03-03 18:12:31   30  10
"""
  • 第1行到最后,隔行取,即行号为单数的行,1,3,5,7,9....
df.iloc[1::2] # -> DataFrame,到最后,切片的第二个参数可省略不写

"""
                       日期   单价  数量
编号                                
T002  2018-03-02 13:04:05  200   3
T004  2018-03-04 20:34:05  400   2
"""
  • 第0行到第3行,第1列到第3列
df.iloc[:3, 1:3] # -> DataFrame, 等价于 df.iloc[0:3, 1:3],0可以省略不写
"""
       单价  数量
编号           
T001  100   3
T002  200   3
T003   30  10
"""
  • 若没有指定标签列(index_col),则loc与iloc表现相近
df_without_index_col.loc[1:3] # 行标签从1到3的行,行标签是包含结束的。
"""
     编号                   日期   单价  数量
1  T002  2018-03-02 13:04:05  200   3
2  T003  2018-03-03 18:12:31   30  10
3  T004  2018-03-04 20:34:05  400   2
"""
df_without_index_col.iloc[1:3] # 切片是不包含结束的。
"""
     编号                   日期   单价  数量
1  T002  2018-03-02 13:04:05  200   3
2  T003  2018-03-03 18:12:31   30  10
"""

3. ix兼容处理loc与iloc(deprecated)

loc是根据行标签定位的,iloc是根据行号定位的。

ix的处理逻辑是,通常将传入的参数优先视为行标签,若找不到该标签的情况下,再当做行号取索引。

df.ix['T002':'T004'] # 匹配到了行标签,所以和loc表现一致
"""
                       日期   单价  数量
编号                                
T002  2018-03-02 13:04:05  200   3
T003  2018-03-03 18:12:31   30  10
T004  2018-03-04 20:34:05  400   2
"""
df.ix[1:3] # 没有匹配到行标签,所以和iloc一致
"""
                       日期   单价  数量
编号                                
T002  2018-03-02 13:04:05  200   3
T003  2018-03-03 18:12:31   30  10
"""
df_without_index_col.ix[1:3] # 匹配到了行标签 1,2,3,表现与iloc一致
"""
     编号                   日期   单价  数量
1  T002  2018-03-02 13:04:05  200   3
2  T003  2018-03-03 18:12:31   30  10
3  T004  2018-03-04 20:34:05  400   2
"""

ix方法虽然兼容处理了2种情况,但是建议不要使用,尽量使用loc和iloc明确索引方式。

更多的关于ix的讨论可以参考 pandas iloc vs ix vs loc explanation, how are they different?

当前ix方法已经处于 deprecated 状态。

三、简单条件

1. 简单的逻辑判断(<, >, ==, &, |, ~ 等)

  • 单价不小于200的记录
df[df['单价'] >= 200]
# 等价于 df[~(df['单价'] < 200)]
"""
                       日期   单价  数量
编号                                
T002  2018-03-02 13:04:05  200   3
T004  2018-03-04 20:34:05  400   2
T005  2018-03-02 20:34:05  500   1
"""
  • 单价大于等于200且数量大于1的记录(&表示与,|表示或,~表示非)
df[(df['单价'] >= 200) & (df['数量'] >= 2)]
"""
                       日期   单价  数量
编号                                
T002  2018-03-02 13:04:05  200   3
T004  2018-03-04 20:34:05  400   2
"""

四、自定义函数

1. loc

loc函数支持传入自定义的函数进行筛选

  • 筛选总价大于500的记录
df.loc[lambda x: x['单价'] * x['数量'] > 500] # 函数入参 x 是整个 DataFrame
"""
                       日期   单价  数量
编号                                
T002  2018-03-02 13:04:05  200   3
T004  2018-03-04 20:34:05  400   2
"""
# 等价于 
def filter_func(x):
    print(type(x)) # <class 'pandas.core.frame.DataFrame'>
    return x['单价'] * x['数量'] > 500
df.loc[filter_func]
  • 筛选3月2号的记录
# x是整个DataFrame,x['日期']是包含所有记录的Series
df.loc[lambda x: x['日期'].str.startswith('2018-03-02')]
"""
                       日期   单价  数量
编号                                
T001  2018-03-02 12:34:05  100   3
T002  2018-03-02 13:04:05  200   3
T005  2018-03-02 20:34:05  500   1
"""

Series.str(),可以使用Python自带的string相关的方法,构造筛选条件。

查看官方文档pandas.Series.str

2. apply

  • 筛选总价大于500的记录
df[df.apply(lambda x: x['单价'] * x['数量'] > 500, axis=1)] # 函数入参 x 是一行数据 Series
"""
                       日期   单价  数量
编号                                
T002  2018-03-02 13:04:05  200   3
T004  2018-03-04 20:34:05  400   2
"""
# 等价于 
def filter_func(x):
    print(type(x)) # <class 'pandas.core.series.Series'>
    return x['单价'] * x['数量'] > 500
df[df.apply(filter_func, axis=1)]

axis默认为0,表示遍历列,axis=1,表示遍历行。

更多参数,查看官方文档pandas.DataFrame.apply

  • 筛选3月2号的记录
df['日期'] = pd.to_datetime(df['日期'])
# x表示一行记录(Series),x['日期']已经是一个具体的日期对象
df[df.apply(lambda x: x['日期'].date() == pd.to_datetime('2018/03/02').date(), axis=1)]
"""
                      日期   单价  数量
编号                               
T001 2018-03-02 12:34:05  100   3
T002 2018-03-02 13:04:05  200   3
T005 2018-03-02 20:34:05  500   1
"""
  • 假如数据中单价包含非数字,需要删除
编号,日期,单价,数量
T001,2018-03-02 12:34:05,100,3
T002,2018-03-02 13:04:05,200,3
T003,2018-03-03 18:12:31,30,10
T004,2018-03-04 20:34:05,400,2
T005,2018-03-02 20:34:05,500,1
T006,2018-03-02 20:34:05,$#500,1
def filter_func(x):
    try:
        float(x['单价']) # x是为某一行的数据,x['单价']可以取到该行对应的值
        return True
    except:
        return False


df = pd.read_csv('demo.csv', index_col='编号')
print(df[df.apply(filter_func, axis=1)])
"""
                       日期     单价  数量
编号                                  
T001  2018-03-02 12:34:05    100   3
T002  2018-03-02 13:04:05    200   3
T003  2018-03-03 18:12:31     30  10
T004  2018-03-04 20:34:05    400   2
T005  2018-03-02 20:34:05  500.0   1
"""

标签:

本站使用 署名 4.0 国际 创作共享协议,转载请注明出处

相关文章