Python怎么从pandas DataFrame中选择特定的行和列_pandas数据索引与切片技巧

答案:Pandas中选择数据的核心方法是loc、iloc和布尔索引。loc基于标签进行索引,支持切片包含结束点,适合使用行索引和列名操作;iloc基于整数位置,切片行为与Python列表一致,适用于按位置访问数据;布尔索引通过条件筛选行,可结合逻辑运算符实现复杂查询。优先使用loc保证代码可读性,按位置操作时用iloc,避免链式索引以防止SettingWithCopyWarning,复杂条件可用query()提升可读性,单值访问推荐at和iat提高效率。

Python怎么从pandas DataFrame中选择特定的行和列_pandas数据索引与切片技巧

在Pandas中,要从DataFrame中选择特定的行和列,核心方法主要有三种:基于标签的

loc

、基于整数位置的

iloc

,以及非常灵活的布尔索引。理解并熟练运用它们,能让你在数据处理时事半功倍,避免许多不必要的麻烦。

解决方案

Pandas DataFrame的数据索引与切片,就像你在地图上找具体位置一样,需要明确的坐标。我们通常会用到

loc

iloc

和布尔索引这三把“瑞士军刀”。

1. 使用

loc

进行基于标签的索引和切片

loc

是我个人最常用也最推荐的方法之一,因为它直接使用行索引(index)和列名(column names)来定位数据,非常直观。它的基本语法是

df.loc[row_label, column_label]

立即学习Python免费学习笔记(深入)”;

  • 选择单行或单列:

    import pandas as pd import numpy as np  # 创建一个示例DataFrame data = {'A': [1, 2, 3, 4],         'B': [5, 6, 7, 8],         'C': [9, 10, 11, 12]} df = pd.DataFrame(data, index=['x', 'y', 'z', 'w']) print("原始DataFrame:n", df)  # 选择索引为'y'的行 print("n选择索引为'y'的行:n", df.loc['y'])  # 选择列'B' print("n选择列'B':n", df.loc[:, 'B'])
  • 选择多行或多列: 可以传入一个列表。

    # 选择索引为'x'和'z'的行 print("n选择索引为'x'和'z'的行:n", df.loc[['x', 'z']])  # 选择列'A'和'C' print("n选择列'A'和'C':n", df.loc[:, ['A', 'C']])
  • 选择行和列的组合:

    # 选择索引为'y'和'w'的行的列'A'和'C' print("n选择索引为'y','w'的行的列'A','C':n", df.loc[['y', 'w'], ['A', 'C']])  # 选择从索引'y'到'w'(包含)的所有行,以及从列'A'到'C'(包含)的所有列 # 注意:loc的切片是包含结束点的 print("n切片选择行'y'到'w',列'A'到'C':n", df.loc['y':'w', 'A':'C'])

2. 使用

iloc

进行基于整数位置的索引和切片

iloc

则完全依赖于数据的整数位置,就像Python列表的索引一样。它的基本语法是

df.iloc[row_index, column_index]

  • 选择单行或单列:

    # 选择第1行(索引为0开始) print("n选择第1行:n", df.iloc[0])  # 选择第2列(索引为0开始) print("n选择第2列:n", df.iloc[:, 1])
  • 选择多行或多列: 同样可以传入一个列表。

    # 选择第0和第2行 print("n选择第0和第2行:n", df.iloc[[0, 2]])  # 选择第0和第2列 print("n选择第0和第2列:n", df.iloc[:, [0, 2]])
  • 选择行和列的组合:

    # 选择第1和第3行的第0和第2列 print("n选择第1和第3行的第0和第2列:n", df.iloc[[1, 3], [0, 2]])  # 切片选择从第1行到第3行(不包含第3行),以及从第0列到第2列(不包含第2列) # 注意:iloc的切片是排他性的,与Python列表切片行为一致 print("n切片选择行1到3(不含3),列0到2(不含2):n", df.iloc[1:3, 0:2])

3. 使用布尔索引进行条件筛选

布尔索引是我在进行数据清洗和分析时最常用的功能之一,它允许你根据一个或多个条件来选择行。

  • 单条件筛选:

    # 选择列'A'中值大于2的所有行 print("n选择列'A'中值大于2的所有行:n", df[df['A'] > 2])
  • 多条件筛选: 使用

    &

    (AND),

    |

    (OR),

    ~

    (NOT) 运算符,并且每个条件表达式必须用括号括起来。

    # 选择列'A'大于2且列'B'小于8的所有行 print("n选择列'A'>2且'B'<8的所有行:n", df[(df['A'] > 2) &amp;amp; (df['B'] < 8)])  # 选择列'A'等于1或列'C'大于11的所有行 print("n选择列'A'==1或'C'>11的所有行:n", df[(df['A'] == 1) | (df['C'] > 11)])  # 选择列'A'不等于1的所有行 print("n选择列'A'不等于1的所有行:n", df[~(df['A'] == 1)])
  • 结合

    loc

    进行布尔索引和列选择:

    # 选择列'A'大于2的所有行的列'B'和'C' print(&amp;quot;n选择列'A'>2的所有行的列'B'和'C':n&amp;quot;, df.loc[df['A'] > 2, ['B', 'C']])

在Pandas中,

loc

iloc

究竟有何区别,我该如何选择?

这确实是初学者,甚至是一些有经验的用户也时常会混淆的地方。说实话,刚开始用的时候我也常常搞不清楚什么时候该用哪个。但核心的区别其实非常简单:

loc

是基于标签(label)的,而

iloc

是基于整数位置(integer location)的。

想象一下你有一本书,

loc

就像你在目录里找“第三章”或者“附录A”一样,它关心的是章节的名字。而

iloc

则像你在书架上数“从上往下第三本书”或者“从左往右第五页”,它关心的是物理上的顺序。

loc

的特点:

  • 使用行索引和列名。 如果你的DataFrame有自定义的行索引(比如日期、ID、类别名称),或者你希望用明确的列名来操作,
    loc

    是你的首选。

  • 切片是包含结束点的。 这一点非常关键,也是和Python原生切片行为不同的地方。比如
    df.loc['start_label':'end_label']

    会包含

    end_label

    对应的行或列。这在处理时间序列数据或者有明确范围的数据时非常方便。

  • 可以进行布尔索引。 结合条件筛选时,
    loc

    能让你在筛选行的同时,也指定要查看哪些列,这比单独的布尔索引更强大和灵活。

iloc

的特点:

  • 使用从0开始的整数位置。 它不关心你的行索引或列名是什么,只关心它们在DataFrame中的排列顺序。
  • 切片是排他性的。 比如
    df.iloc[0:5]

    会选择索引为0到4的行,不包含第5行。这和Python列表的切片行为完全一致,对于熟悉Python的人来说更容易理解。

  • 适合循环或需要按位置动态选择数据时。 当你需要遍历DataFrame的特定部分,或者你的选择逻辑是基于数据在DataFrame中的物理位置时,
    iloc

    就显得非常方便。

我该如何选择?

我的建议是:

Python怎么从pandas DataFrame中选择特定的行和列_pandas数据索引与切片技巧

千帆AppBuilder

百度推出的一站式的ai原生应用开发资源和工具平台,致力于实现人人都能开发自己的AI原生应用。

Python怎么从pandas DataFrame中选择特定的行和列_pandas数据索引与切片技巧90

查看详情 Python怎么从pandas DataFrame中选择特定的行和列_pandas数据索引与切片技巧

  1. 优先使用
    loc

    如果你的DataFrame有有意义的行索引和列名,并且你的操作是基于这些标签的,那么

    loc

    能让你的代码更具可读性和健壮性。即使数据的顺序发生变化,只要标签不变,你的代码依然能正确工作。

  2. 当需要按位置操作时使用
    iloc

    比如,你总是想获取DataFrame的第一行,或者最后一列,而不管它们的标签是什么。或者在某些算法中,你需要基于数据的相对位置进行切片。

  3. 避免混合使用。 尽量保持代码风格的一致性,减少混淆。

一个常见的错误就是把

loc

的切片行为(包含结束)和

iloc

的切片行为(不包含结束)搞混。我个人在写代码的时候,如果涉及到切片,会特别留意当前用的是

loc

还是

iloc

,避免因为这个小细节导致数据选择错误。

如何利用布尔索引进行复杂的数据筛选,有哪些常见陷阱?

布尔索引是Pandas数据筛选的利器,它允许你根据数据的实际值来动态选择行,这在数据分析和清洗中几乎是无处不在的。

利用布尔索引进行复杂筛选:

  • 多条件组合: 如前面所示,使用

    &amp;amp;

    (AND),

    |

    (OR),

    ~

    (NOT) 运算符可以组合多个条件。例如,如果你想找出年龄在18到30岁之间,并且是女性的用户数据:

    # 假设df有一个'Age'和'Gender'列 # df[(df['Age'] >= 18) &amp;amp; (df['Age'] <= 30) &amp;amp; (df['Gender'] == 'Female')]

    这里的关键是每个独立的条件表达式都必须用括号

    ()

    括起来,因为Python的位运算符(

    &amp;amp;

    ,

    |

    )优先级高于比较运算符(

    >

    ,

    <

    ,

    ==

    等)。如果没有括号,可能会导致意想不到的错误。

  • 使用

    isin()

    方法: 当你想选择某一列的值在某个特定列表中的所有行时,

    isin()

    方法非常方便。

    # 选择列'City'是'New York'或'London'的行 # df[df['City'].isin(['New York', 'London'])]

    这比写

    (df['City'] == 'New York') | (df['City'] == 'London')

    要简洁得多,尤其当列表很长时。

  • 使用

    str.contains()

    进行字符串匹配: 如果你的列是字符串类型,并且你需要根据子字符串匹配来筛选,

    str.contains()

    是一个很好的选择。

    # 选择列'Description'中包含'error'关键词的行 # df[df['Description'].str.contains('error', na=False)]
    na=False

    参数很重要,它指定了如何处理NaN值。如果为

    True

    ,则NaN值也会被视为包含(或不包含,取决于具体实现),通常我们希望它们不匹配。

常见陷阱:

  1. 忘记括号: 这是最常见的错误,没有之一。

    # 错误示例: # df[df['A'] > 2 &amp;amp; df['B'] < 8] # 这会先计算 2 &amp;amp; df['B'],然后用 df['A'] > (结果) # 正确写法: # df[(df['A'] > 2) &amp;amp; (df['B'] < 8)]

    Pandas会告诉你一个

    ValueError: The truth value of a Series is ambiguous

    ,或者直接得到错误的结果。

  2. 处理

    NaN

    值: 当你的条件列中包含

    NaN

    (Not a Number)时,布尔运算可能会产生意外结果。

    NaN

    与任何值(包括它自己)的比较结果都是

    False

    # 假设df有一个包含NaN的'Value'列 # df[df['Value'] > 10] # 结果会排除所有NaN的行,即使你可能希望它们被包含在内或单独处理。

    处理

    NaN

    的常见方法是:

    • dropna()

      在筛选前先删除包含

      NaN

      的行。

    • fillna()

      在筛选前先用某个值填充

      NaN

    • isna()

      /

      notna()

      专门用来检查

      NaN

      值。

      # 选择'Value'列不是NaN的行 # df[df['Value'].notna()]
  3. 对Series进行布尔运算时,Series的索引必须对齐。 如果你创建了一个布尔Series,它的索引与DataFrame的索引不匹配,Pandas会尝试对齐,如果对齐失败(例如,索引标签不完全一致),可能会填充

    NaN

    ,然后导致错误或意外结果。通常,我们直接在DataFrame内部生成布尔Series,所以这个问题不常遇到,但了解其原理有助于调试。

布尔索引的强大之处在于它的灵活性,但这种灵活性也要求我们对数据类型和运算符优先级有清晰的认识。我通常会把复杂的条件分解成小的、可测试的部分,确保每个布尔Series都按预期生成,然后再组合起来。

除了基础索引,还有哪些高级技巧能提升我的数据选择效率?

在掌握了

loc

iloc

和布尔索引这些基础之后,还有一些高级技巧和最佳实践可以进一步提升你在Pandas中选择数据的效率和代码的可读性,同时避免一些常见的性能陷阱。

  1. 避免链式索引 (Chained Indexing) 写入操作,警惕

    SettingWithCopyWarning

    这是Pandas用户经常遇到的一个“坑”。当你像这样操作时:

    # df[df['col_A'] > 5]['col_B'] = 10 # 错误或产生警告

    你可能会遇到

    SettingWithCopyWarning

    。这是因为

    df[df['col_A'] > 5]

    返回的可能是一个“视图”(view)而不是一个“副本”(copy)。当你试图修改一个视图时,修改可能不会反映到原始DataFrame上,或者即使反映了,Pandas也会发出警告,因为它不确定你的意图。

    正确且推荐的做法是使用

    loc

    iloc

    # 修改满足条件的行的特定列 df.loc[df['col_A'] > 5, 'col_B'] = 10

    这种方式明确地告诉Pandas,你打算在原始DataFrame上进行修改,它会返回一个指向原始数据的引用,确保修改生效。

  2. 使用

    query()

    进行字符串表达式筛选: 对于复杂的布尔条件筛选,特别是当条件涉及多个列时,

    query()

    方法能让你的代码更像SQL语句,可读性大大提高。它接受一个字符串表达式。

    # 假设df有'Age', 'Gender', 'Score'列 # df.query('Age > 25 and Gender == "Male" and Score > 80')
    query()

    内部会进行优化,在某些情况下,它的性能可能比直接的布尔索引更好,因为它避免了创建多个中间的布尔Series。它也支持使用

    @

    符号引用外部变量:

    min_age = 25 # df.query('Age > @min_age')
  3. 使用

    filter()

    进行列的筛选: 如果你需要根据列名的一部分、正则表达式或者一个列表来选择列,

    filter()

    方法非常有用。

    # 选择列名中包含'A'的列 # df.filter(like='A')  # 选择列名以'C'开头的列 # df.filter(regex='^C')  # 选择特定列(与df[['col1', 'col2']]类似,但更灵活) # df.filter(items=['col1', 'col2'])

    这在处理大量列或者需要动态选择列时非常方便。

  4. at

    iat

    用于快速单值访问: 当你知道确切的行标签/位置和列名/位置,并且只需要访问或修改单个单元格时,

    at

    iat

    loc

    iloc

    效率更高。它们是针对单点访问进行了优化的。

    # 获取索引为'y',列为'A'的值 # value = df.at['y', 'A']  # 修改索引为'z',列为'C'的值 # df.at['z', 'C'] = 100  # 获取第1行,第0列的值 # value = df.iat[1, 0]

    虽然这看起来是微小的优化,但在大型数据集上进行大量单点操作时,累积起来的性能提升会很显著。

这些高级技巧并非每次数据选择都必须使用,但它们提供了更高效、更具可读性或更安全的选择。在实际工作中,我通常会根据具体场景和数据规模来决定使用哪种方法。例如,对于简单的筛选,直接布尔索引就足够了;但如果条件复杂或者需要避免

SettingWithCopyWarning

loc

query()

就是更好的选择。理解这些工具的适用场景,能让你在数据处理的道路上走得更远。

python 正则表达式 工具 ai 区别 sql语句 代码可读性 排列 Python sql 正则表达式 pandas 数据类型 Integer 运算符 比较运算符 逻辑运算符 Filter 位运算符 字符串 循环 字符串类型 切片 copy number location column 算法 数据分析

上一篇
下一篇