我有一个dataframe列,其中包含.csv中的数字列表。这些数字的范围是1-1400,可以重复也可以不重复,并且NaN值几乎可以随机出现在任何地方。
两个例子是
a=[1,4,NaN,5,6,7,...1398,1400,1,2,3,NaN,8,9,...,1398,NaN]
b=[1,NaN,2,3,4,NaN,7,10,...,1398,1399,1400]
我想创建另一个列,该列找到第一个1-1400,并在相同的索引中记录一个“ 1”,如果第二个1-1400存在,则在新索引中将其标记为“ 2”列
我可以想到一些使用临时占位符和其他检查方式的回旋方式,但是我想知道是否可以使用1-3班轮进行此操作
Edit1:我希望只返回一列
a1=[1,1,NaN,1,1,1,...1,1,2,2,2,NaN,2,2,...,2,NaN]
b1=[1,NaN,1,1,1,NaN,1,1,...,1,1,1]
答案 0 :(得分:2)
您可以使用groupby()
和cumcount()
对每一列中的数字进行计数:
# create new columns for counting
df['a1'] = np.nan
df['b1'] = np.nan
# take groupby for each value in column `a` and `b` and count each value
df.a1 = df.groupby('a').cumcount() + 1
df.b1 = df.groupby('b').cumcount() + 1
# set np.nan as it is
df.loc[df.a.isnull(), 'a1'] = np.nan
df.loc[df.b.isnull(), 'b1'] = np.nan
编辑(收到“不起作用”的评论后):
df['a2'] = df.ffill().a.diff()
df['a1'] = df.loc[df.a2 < 0].groupby('a').cumcount() + 1
df['a1'] = df['a1'].bfill().shift(-1)
df.loc[df.a1.isnull(), 'a1'] = df.a1.max() + 1
df.drop('a2', axis=1, inplace=True)
df.loc[df.a.isnull(), 'a1'] = np.nan
答案 1 :(得分:0)
您可以使用diff
来检查以下两个值之间的差是否为负,表示新范围的开始。让我们创建一个数据框:
import pandas as pd
import numpy as np
# to create a dataframe with two columns my range go up to 12 but 1400 is the same
df = pd.DataFrame({'a':[1,4,np.nan,5,10,12,2,3,4,np.nan,8,12],'b':range(1,13)})
df.loc[[4,8],'b'] = np.nan
因为您有'NaN',所以您需要使用ffill
来用先前的值填充NaN
,并且想要与{{1 }}大于或等于0(我知道它听起来小于0,但此处不完全正确,因为它错过了数据帧的第一行)。例如,对于“ a”列
~
您将获得两行,其中“新”范围开始。要使用此属性创建“ a1”,您可以执行以下操作:
diff
最后,对于几列,您可以执行以下操作:
print (df.loc[~(df.a.ffill().diff()>=0),'a'])
0 1.0
6 2.0
Name: a, dtype: float64
根据我的输入,您将得到:
# put 1 in the rows with a new range start
df.loc[~(df.a.ffill().diff()>=0),'a1'] = 1
# create a mask to select notnull row in a:
mask_a = df.a.notnull()
# use cumsum and ffill on column a1 with the mask_a
df.loc[mask_a,'a1'] = df.loc[mask_a,'a1'].cumsum().ffill()
编辑:您甚至可以为每一列在一行中完成,结果相同:
list_col = ['a','b']
for col in list_col:
df.loc[~(df[col].ffill().diff()>=0),col+'1'] = 1
mask = df[col].notnull()
df.loc[mask,col+'1'] = df.loc[mask,col+'1'].cumsum().ffill()