美文网首页PythonPythonpython
Python 数据处理(十)—— 迭代与 dt 访问器

Python 数据处理(十)—— 迭代与 dt 访问器

作者: 名本无名 | 来源:发表于2021-02-11 10:25 被阅读0次

    8. 迭代

    Pandas 对象基于类型进行迭代操作。Series 迭代时被视为数组,每次迭代生成值。

    DataFrame 则遵循字典遍历方式,用对象的 key 进行迭代操作。

    总之,对于基础迭代(for i in object)会产生:

    • Series:值
    • DataFrame:列名

    例如,对 DataFrame 进行迭代会获取到列名

    In [254]: df = pd.DataFrame(
       .....:     {"col1": np.random.randn(3), "col2": np.random.randn(3)}, index=["a", "b", "c"]
       .....: )
       .....: 
    
    In [255]: for col in df:
       .....:     print(col)
       .....: 
    col1
    col2
    

    pandas 对象还具有类似于 dictitems() 方法,用于迭代键值对。

    要遍历 DataFrame 的行,可以使用以下方法:

    • iterrows(): 以 (索引,Series) 对的形式遍历 DataFrame 的行。这会将每行转换为 Series 对象,这会改变数据类型并影响性能。

    • itertuples(): 将 DataFrame 的行作为值的命名元组进行迭代。这比 iterrows() 的速度快很多,并且在大多数情况下,最好使用它来遍历 DataFrame 的值

    警告

    遍历 pandas 对象通常都很慢。在多数情况下,不需要手动在行上进行迭代,并且可以通过以下方法来避免:

    • 寻找向量化解决方案:可以使用内置方法或 NumPy 函数,索引等执行操作
    • 当您无法一次性在 DataFrame/Series 上运行的函数时,最好使用 apply() 而不是遍历值。
    • 如果必须要对值进行迭代操作,但又要追求性能,请考虑使用 cythonnumba 来编写内部循环

    警告
    永远不要在迭代内部修改数据内容,根据数据类型,迭代器返回一份拷贝(copy)而不是视图(view),并且对其进行写入将无效

    例如,在下面的情况下,设置该值将不起作用

    In [256]: df = pd.DataFrame({"a": [1, 2, 3], "b": ["a", "b", "c"]})
    In [257]: for index, row in df.iterrows():
      .....:     row["a"] = 10
      .....: 
    
    In [258]: df
    Out[258]: 
      a  b
    0  1  a
    1  2  b
    2  3  c
    
    8.1 items

    与字典类似,items() 遍历键值对

    • Series: (索引, 标量值)
    • DataFrame: (列名, Series)

    例如

    In [259]: for label, ser in df.items():
       .....:     print(label)
       .....:     print(ser)
       .....: 
    a
    0    1
    1    2
    2    3
    Name: a, dtype: int64
    b
    0    a
    1    b
    2    c
    Name: b, dtype: object
    
    8.2 iterrows

    iterrows()Series 对象的形式遍历 DataFrame 中的行。

    它返回一个迭代器,产生索引值以及对应行数据的 Series:

    In [260]: for row_index, row in df.iterrows():
       .....:     print(row_index, row, sep="\n")
       .....: 
    0
    a    1
    b    a
    Name: 0, dtype: object
    1
    a    2
    b    b
    Name: 1, dtype: object
    2
    a    3
    b    c
    Name: 2, dtype: object
    

    注意

    iterrows() 返回的行数据是 Series,该操作不会保留每行的原始数据类型,DataFrame 的数据类型是根据列来界定的。例如

    In [261]: df_orig = pd.DataFrame([[1, 1.5]], columns=["int", "float"])
    
    In [262]: df_orig.dtypes
    Out[262]: 
    int        int64
    float    float64
    dtype: object
    
    In [263]: row = next(df_orig.iterrows())[1]
    
    In [264]: row
    Out[264]: 
    int      1.0
    float    1.5
    Name: 0, dtype: float64
    

    row 中的所有值,作为一个 Series 返回,并且都被转换为了浮点数,而列 x 中的保留的还是原始整数值

    In [265]: row["int"].dtype
    Out[265]: dtype('float64')
    
    In [266]: df_orig["int"].dtype
    Out[266]: dtype('int64')
    

    为了保持原始类型,还是使用 itertuples() 来进行迭代。

    例如,对 DataFrame 进行转置

    In [267]: df2 = pd.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
    
    In [268]: print(df2)
       x  y
    0  1  4
    1  2  5
    2  3  6
    
    In [269]: print(df2.T)
       0  1  2
    x  1  2  3
    y  4  5  6
    
    In [270]: df2_t = pd.DataFrame({idx: values for idx, values in df2.iterrows()})
    
    In [271]: print(df2_t)
       0  1  2
    x  1  2  3
    y  4  5  6
    
    8.3 itertuples

    itertuples() 方法会返回一个迭代器,为 DataFrame 中的每一行生成一个 namedtuple

    元组的第一个元素将是行的索引值,剩余的值是行的数据值,例如

    In [272]: for row in df.itertuples():
       .....:     print(row)
       .....: 
    Pandas(Index=0, a=1, b='a')
    Pandas(Index=1, a=2, b='b')
    Pandas(Index=2, a=3, b='c')
    

    此方法不会将行转换为 Series 对象。它仅返回 namedtuple 中的值。

    因此,itertuples() 会保留值的数据类型,并且通常会比 iterrows() 更快

    注意

    如果列名包含无效的 Python 标识符、重复的列名及以下划线开头的列名,都会被重命名为位置名称。

    如果列数较大,比如大于 255 列,则返回正则元组。

    9 .dt 访问器

    Series 有一个可以简单、快速地返回 datetime 属性值的访问器。

    这个访问器返回的也是 Series,具有与现有的 Series 一样的索引

    In [273]: s = pd.Series(pd.date_range("20130101 09:10:12", periods=4))
    
    In [274]: s
    Out[274]: 
    0   2013-01-01 09:10:12
    1   2013-01-02 09:10:12
    2   2013-01-03 09:10:12
    3   2013-01-04 09:10:12
    dtype: datetime64[ns]
    
    In [275]: s.dt.hour
    Out[275]: 
    0    9
    1    9
    2    9
    3    9
    dtype: int64
    
    In [276]: s.dt.second
    Out[276]: 
    0    12
    1    12
    2    12
    3    12
    dtype: int64
    
    In [277]: s.dt.day
    Out[277]: 
    0    1
    1    2
    2    3
    3    4
    dtype: int64
    

    这样就可以使用更加便捷的表达式来访问数据

    In [278]: s[s.dt.day == 2]
    Out[278]: 
    1   2013-01-02 09:10:12
    dtype: datetime64[ns]
    

    也可以轻松的进行时区转换

    In [279]: stz = s.dt.tz_localize("US/Eastern")
    
    In [280]: stz
    Out[280]: 
    0   2013-01-01 09:10:12-05:00
    1   2013-01-02 09:10:12-05:00
    2   2013-01-03 09:10:12-05:00
    3   2013-01-04 09:10:12-05:00
    dtype: datetime64[ns, US/Eastern]
    
    In [281]: stz.dt.tz
    Out[281]: <DstTzInfo 'US/Eastern' LMT-1 day, 19:04:00 STD>
    

    也可以使用链式操作

    In [282]: s.dt.tz_localize("UTC").dt.tz_convert("US/Eastern")
    Out[282]: 
    0   2013-01-01 04:10:12-05:00
    1   2013-01-02 04:10:12-05:00
    2   2013-01-03 04:10:12-05:00
    3   2013-01-04 04:10:12-05:00
    dtype: datetime64[ns, US/Eastern]
    

    您也可以使用 Series.dt.strftime() 将日期时间格式化为字符串,该字符串支持与标准 strftime() 相同的格式

    # DatetimeIndex
    In [283]: s = pd.Series(pd.date_range("20130101", periods=4))
    
    In [284]: s
    Out[284]: 
    0   2013-01-01
    1   2013-01-02
    2   2013-01-03
    3   2013-01-04
    dtype: datetime64[ns]
    
    In [285]: s.dt.strftime("%Y/%m/%d")
    Out[285]: 
    0    2013/01/01
    1    2013/01/02
    2    2013/01/03
    3    2013/01/04
    dtype: object
    
    # PeriodIndex
    In [286]: s = pd.Series(pd.period_range("20130101", periods=4))
    
    In [287]: s
    Out[287]: 
    0    2013-01-01
    1    2013-01-02
    2    2013-01-03
    3    2013-01-04
    dtype: period[D]
    
    In [288]: s.dt.strftime("%Y/%m/%d")
    Out[288]: 
    0    2013/01/01
    1    2013/01/02
    2    2013/01/03
    3    2013/01/04
    dtype: object
    

    .dt 访问器适用于 periodtimedelta 类型数据

    # period
    In [289]: s = pd.Series(pd.period_range("20130101", periods=4, freq="D"))
    
    In [290]: s
    Out[290]: 
    0    2013-01-01
    1    2013-01-02
    2    2013-01-03
    3    2013-01-04
    dtype: period[D]
    
    In [291]: s.dt.year
    Out[291]: 
    0    2013
    1    2013
    2    2013
    3    2013
    dtype: int64
    
    In [292]: s.dt.day
    Out[292]: 
    0    1
    1    2
    2    3
    3    4
    dtype: int64
    
    # timedelta
    In [293]: s = pd.Series(pd.timedelta_range("1 day 00:00:05", periods=4, freq="s"))
    
    In [294]: s
    Out[294]: 
    0   1 days 00:00:05
    1   1 days 00:00:06
    2   1 days 00:00:07
    3   1 days 00:00:08
    dtype: timedelta64[ns]
    
    In [295]: s.dt.days
    Out[295]: 
    0    1
    1    1
    2    1
    3    1
    dtype: int64
    
    In [296]: s.dt.seconds
    Out[296]: 
    0    5
    1    6
    2    7
    3    8
    dtype: int64
    
    In [297]: s.dt.components
    Out[297]: 
       days  hours  minutes  seconds  milliseconds  microseconds  nanoseconds
    0     1      0        0        5             0             0            0
    1     1      0        0        6             0             0            0
    2     1      0        0        7             0             0            0
    3     1      0        0        8             0             0            0
    

    注意

    如果您的数据不是类似 datetime 类型的值,那么 Series.dt 将引发 TypeError

    10 向量化字符串方法

    Series 还配备了一套字符串处理方法,可以轻松地对数组的每个元素进行操作。

    这些方法有一个重要的特性,能够自动排除缺失值和空值。

    这些方法是通过 Series.str 属性访问的,其名称一般与内置字符串方法相匹配。例如

    In [298]: s = pd.Series(
       .....:     ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"], dtype="string"
       .....: )
       .....: 
    
    In [299]: s.str.lower()
    Out[299]: 
    0       a
    1       b
    2       c
    3    aaba
    4    baca
    5    <NA>
    6    caba
    7     dog
    8     cat
    dtype: string
    

    同时还提供了强大的模式匹配方法,这里模式匹配通常默认情况下使用的是正则表达式。

    详细的操作细节将会在后面的章节中介绍

    相关文章

      网友评论

        本文标题:Python 数据处理(十)—— 迭代与 dt 访问器

        本文链接:https://www.haomeiwen.com/subject/wtohxltx.html