簡體   English   中英

Python - 迭代一系列屬性

[英]Python - Iterate over a list of attributes

我的數據集中有一個功能,它是一個pandas時間戳對象。 它(以及許多其他)具有以下屬性:年,小時,每周,每月。

我可以使用一些強力方法基於這些屬性創建新功能:

df["year"] = df["timeStamp"].apply(lambda x : x.year)

df["hour"] = df["timeStamp"].apply(lambda x : x.hour)

但是,我想迭代一個列表:

nomtimes = ["year", "hour", "month", "dayofweek"]


for i in nomtimes:

  df[i] = df["timeStamp"].apply(lambda x : x.i)

我得到以下AttributeError:'Timestamp'對象沒有屬性'i',我得到它並理解為什么我有這個錯誤。

如何將引用的字符串取消引用以便我可以將其作為屬性傳遞?

你只需要getattr()

df[i] = df["timeStamp"].apply(lambda x : getattr(x, i))

不要在這里使用.apply ,pandas有各種內置實用程序來處理datetime對象,在系列對象上使用dt屬性:

In [11]: start = datetime(2011, 1, 1)
    ...: end = datetime(2012, 1, 1)
    ...:

In [12]: df = pd.DataFrame({'data':pd.date_range(start, end)})

In [13]: df.dtypes
Out[13]:
data    datetime64[ns]
dtype: object

In [14]: df['year'] = df.data.dt.year

In [15]: df['hour'] = df.data.dt.hour

In [16]: df['month'] = df.data.dt.month

In [17]: df['dayofweek'] = df.data.dt.dayofweek

In [18]: df.head()
Out[18]:
        data  year  hour  month  dayofweek
0 2011-01-01  2011     0      1          5
1 2011-01-02  2011     0      1          6
2 2011-01-03  2011     0      1          0
3 2011-01-04  2011     0      1          1
4 2011-01-05  2011     0      1          2

或者,動態地使用getattr

In [24]: df = pd.DataFrame({'data':pd.date_range(start, end)})

In [25]: nomtimes = ["year", "hour", "month", "dayofweek"]
    ...:

In [26]: df.head()
Out[26]:
        data
0 2011-01-01
1 2011-01-02
2 2011-01-03
3 2011-01-04
4 2011-01-05

In [27]: for t in nomtimes:
    ...:     df[t] = getattr(df.data.dt, t)
    ...:

In [28]: df.head()
Out[28]:
        data  year  hour  month  dayofweek
0 2011-01-01  2011     0      1          5
1 2011-01-02  2011     0      1          6
2 2011-01-03  2011     0      1          0
3 2011-01-04  2011     0      1          1
4 2011-01-05  2011     0      1          2

如果你必須使用單行,請使用:

In [30]: df = pd.DataFrame({'data':pd.date_range(start, end)})

In [31]: df.head()
Out[31]:
        data
0 2011-01-01
1 2011-01-02
2 2011-01-03
3 2011-01-04
4 2011-01-05

In [32]: df = df.assign(**{t:getattr(df.data.dt,t) for t in nomtimes})

In [33]: df.head()
Out[33]:
        data  dayofweek  hour  month  year
0 2011-01-01          5     0      1  2011
1 2011-01-02          6     0      1  2011
2 2011-01-03          0     0      1  2011
3 2011-01-04          1     0      1  2011
4 2011-01-05          2     0      1  2011

operator.attrgetter

您可以在循環中提取屬性:

from operator import attrgetter

for i in nomtimes:
    df[i] = df['timeStamp'].apply(attrgetter(i))

這是一個完整的例子:

df = pd.DataFrame({'timeStamp': ['2018-05-05 15:00', '2015-01-30 11:00']})
df['timeStamp'] = pd.to_datetime(df['timeStamp'])

nomtimes = ['year', 'hour', 'month', 'dayofweek']

for i in nomtimes:
    df[i] = df['timeStamp'].apply(attrgetter(i))

print(df)

            timeStamp  year  hour  month  dayofweek
0 2018-05-05 15:00:00  2018    15      5          5
1 2015-01-30 11:00:00  2015    11      1          4

您的代碼將無法工作,因為您嘗試傳遞字符串而不是按名稱提取屬性。 然而,這不是正在發生的事情:語法不會提供字符串,而是嘗試直接訪問i ,如第一個示例所示。

擺脫for循環

您可能會問是否有辦法一次性從datetime對象中提取所有屬性而不是按順序提取。 attrgetter的好處是你可以直接指定多個屬性以完全避免for循環:

attributes = df['timeStamp'].apply(attrgetter(*nomtimes))
df[nomtimes] = pd.DataFrame(attributes.values.tolist())

使用dt訪問器而不是應用

但是pd.Series.apply只是一個薄薄的循環。 通常,沒有必要。 借用@ juanpa.arrivillaga的想法,您可以通過pd.Series.dt訪問器直接訪問屬性:

attributes = pd.concat(attrgetter(*nomtimes)(df['timeStamp'].dt), axis=1, keys=nomtimes)
df = df.join(attributes)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM