Tho*_*dis 8 python dataframe pandas
我有一个包含 5 列的数据框,我正在使用 pandas 和 numpy 来编辑和处理数据。
id calv1 calv2 calv3 calv4
1 2006-08-29 2007-08-29 2008-08-29 2009-08-29
2 NaT NaT NaT NaT
3 2006-08-29 NaT NaT NaT
4 2006-08-29 2007-08-29 2010-08-29 NaT
5 2006-08-29 2013-08-29 NaT NaT
6 2006-08-29 NaT 2013-08-29 2013-08-292
Run Code Online (Sandbox Code Playgroud)
我想创建另一个列来计算每个 id 出现的“calv”的数量。但是,如果其他值之间存在缺失值,这对我来说很重要,请参阅第 6 行。然后我希望有一个 NaN 或其他一些值,表明这不是正确的行。
id calv1 calv2 calv3 calv4 no_calv
1 2006-08-29 2007-08-29 2008-08-29 2009-08-29 4
2 NaT NaT NaT NaT 0
3 2006-08-29 NaT NaT NaT 1
4 2006-08-29 2007-08-29 2010-08-29 NaT 3
5 2006-08-29 2013-08-29 NaT NaT 2
6 2006-08-29 NaT 2013-08-29 2013-08-292 NaN #or some other value
Run Code Online (Sandbox Code Playgroud)
这是我的最后一次尝试:
nat = np.datetime64('NaT')
df.loc[
(df["calv1"] == nat) & (df["calv2"] == nat) &
(df["calv3"] == nat) & (df["calv4"] == nat),
"no_calv"] = 0
#1 calvings
df.loc[
(df["calv1"] != nat) & (df["calv2"] == nat) &
(df["calv3"] == nat) & (df["calv4"] == nat),
"no_calv"] = 1
#2 calvings
df.loc[
(df["calv1"] != nat) & (df["calv2"] != nat) &
(df["calv3"] == nat) & (df["calv4"] == nat),
"no_calv"] = 2
#3 calvings
df.loc[
(df["calv1"] != nat) & (df["calv2"] != nat) &
(df["calv3"] != nat) & (df["calv4"] == nat),
"no_calv"] = 3
#4 or more calvings
df.loc[
(df["calv1"] != nat) & (df["calv2"] != nat) &
(df["calv3"] != nat) & (df["calv4"] != nat),
"no_calv"] = 4
Run Code Online (Sandbox Code Playgroud)
但结果是整个“no_calv”列是4.0
我以前尝试过类似的事情
..
(df["calv1"] != "NaT")
..
Run Code Online (Sandbox Code Playgroud)
和
..
(df["calv1"] != pd.nat)
..
Run Code Online (Sandbox Code Playgroud)
整个列的结果总是4.0或只是NaN。 我似乎找不到告诉 python NaT 值是什么的方法?
对新 Python 用户有什么提示和技巧吗?我已经在 SAS 和 Fortran 中使用 if 和 elseif 语句完成了此操作,但我正在尝试找到在 Python 中执行此操作的最佳方法。
编辑: 我真的很想知道这是否可以通过 if 或 ifelse 语句来完成。
现在我也在想我希望能够在数据框中包含其他列,这些列包含额外的信息,但对于这个确切的目的不需要。一个例子(一个添加的 yx 列):
id yx calv1 calv2 calv3 calv4 no_calv
1 27 2006-08-29 2007-08-29 2008-08-29 2009-08-29 4
2 34 NaT NaT NaT NaT 0
3 89 2006-08-29 NaT NaT NaT 1
4 23 2006-08-29 2007-08-29 2010-08-29 NaT 3
5 11 2006-08-29 2013-08-29 NaT NaT 2
6 43 2006-08-29 NaT 2013-08-29 2013-08-292 NaN #or some other value
Run Code Online (Sandbox Code Playgroud)
另一种方法是使用pd.Series.last_valid_indexand pd.DataFrame.count:
>>> df2 = df.copy()
>>> df2.columns = np.arange(df2.shape[1]) + 1
>>> mask = (df2.apply(pd.Series.last_valid_index, axis=1).fillna(0) == df2.count(axis=1))
>>> df.loc[mask, 'no_calv'] = df.notna().sum(1)
>>> df
calv1 calv2 calv3 calv4 no_calv
id
1 2006-08-29 2007-08-29 2008-08-29 2009-08-29 4.0
2 NaN NaN NaN NaN 0.0
3 2006-08-29 NaN NaN NaN 1.0
4 2006-08-29 2007-08-29 2010-08-29 NaN 3.0
5 2006-08-29 2013-08-29 NaN NaN 2.0
6 2006-08-29 NaN 2013-08-29 2013-08-292 NaN
Run Code Online (Sandbox Code Playgroud)
pd.Series.last_valid_index返回系列中最后一个有效数据的位置。将其应用到行上将告诉列位置最后一个有效数据的位置(之后是所有NaNs/NaTs)。
下面我暂时用整数索引替换列名称,然后应用于pd.Series.last_valid_index每一行:
>>> df2.columns = np.arange(df2.shape[1]) + 1
>>> df2
1 2 3 4
id
1 2006-08-29 2007-08-29 2008-08-29 2009-08-29
2 NaN NaN NaN NaN
3 2006-08-29 NaN NaN NaN
4 2006-08-29 2007-08-29 2010-08-29 NaN
5 2006-08-29 2013-08-29 NaN NaN
6 2006-08-29 NaN 2013-08-29 2013-08-292
>>> df2.apply(pd.Series.last_valid_index, axis=1).fillna(0)
id
1 4.0
2 0.0
3 1.0
4 3.0
5 2.0
6 4.0
dtype: float64
Run Code Online (Sandbox Code Playgroud)
因此,在第 1 行上,最后一个有效数据位于第 4 列中,在第 2 行上没有有效数据,依此类推。
现在我们来数一下没有。每行中的有效数据数:
>>> df2.count(axis=1)
id
1 4
2 0
3 1
4 3
5 2
6 3
dtype: int64
Run Code Online (Sandbox Code Playgroud)
因此,第 1 行有 4 个有效值,第 2 行没有有效值,依此类推。现在,如果所有NaN/NaT值都接近行尾,则计数应与我们上面计算的最后一个有效数据位置匹配:
>>> df2.apply(pd.Series.last_valid_index, axis=1).fillna(0) == df2.count(axis=1)
id
1 True
2 True
3 True
4 True
5 True
6 False
dtype: bool
Run Code Online (Sandbox Code Playgroud)
正如所见,它匹配除最后一行之外的所有行,因为 NaT 出现在最后一行有效值的中间。我们可以用它作为掩码,然后填充总和:
>>> mask = (df2.apply(pd.Series.last_valid_index, axis=1).fillna(0) == df2.count(axis=1))
>>> df.loc[mask, 'no_calv'] = df.notna().sum(1)
>>> df
calv1 calv2 calv3 calv4 no_calv
id
1 2006-08-29 2007-08-29 2008-08-29 2009-08-29 4.0
2 NaN NaN NaN NaN 0.0
3 2006-08-29 NaN NaN NaN 1.0
4 2006-08-29 2007-08-29 2010-08-29 NaN 3.0
5 2006-08-29 2013-08-29 NaN NaN 2.0
6 2006-08-29 NaN 2013-08-29 2013-08-292 NaN
Run Code Online (Sandbox Code Playgroud)