我有一个类似于以下示例的DataFrame。
# define DataFrame for reproducability
df = pd.DataFrame({'date': ['2019-05-06', '2019-05-07', '2019-05-07', '2019-05-09', '2019-05-10', '2019-05-11'],
'Identifier': [1, 1, 1, 1, 1, 1],
'B': [2.4, 3.9, 3.9, 4.3, 2.5, 3.14],
'C': [0.214, 0.985, 0.985, 0.839, 0.555, 0.159],
'Name': [np.nan, "CD", "AD", np.nan, np.nan, np.nan]})
print(df)
date Identifier B C Name
0 2019-05-06 1 2.40 0.214 NaN
1 2019-05-07 1 3.90 0.985 CD
2 2019-05-07 1 3.90 0.985 AD
3 2019-05-09 1 4.30 0.839 NaN
4 2019-05-10 1 2.50 0.555 NaN
5 2019-05-11 1 3.14 0.159 NaN
可以看到的是,对于给定的标识符,可以有多个。但是,该名称仅在单个日期一次附加到DataFrame。我需要的是基本上在每个日期向前向后填写姓名。目前,我有一个可行的解决方案,但是对于我正在处理的整个数据帧而言,这是非常慢的。代码如下所示
final_df = pd.DataFrame()
for i in df.Identifier.unique():
# select the current identifier
identifier_df = df.loc[df.Identifier == i]
# allow a given identifier to have different names
for n in df.Name.unique():
if pd.isna(n):
continue
else:
intermediate = identifier_df.copy()
intermediate.loc[:,"Name"] = np.repeat(n, len(intermediate))
final_df = final_df.append(intermediate)
final_df = final_df.drop_duplicates()
请注意,完整的DataFrame需要通过标识符循环。但是,在这种情况下,这似乎毫无意义。但是,此代码会导致以下DataFrame(这是我希望输出的样子):
print(final_df)
date Identifier B C Name
0 2019-05-06 1 2.40 0.214 CD
1 2019-05-07 1 3.90 0.985 CD
3 2019-05-09 1 4.30 0.839 CD
4 2019-05-10 1 2.50 0.555 CD
5 2019-05-11 1 3.14 0.159 CD
0 2019-05-06 1 2.40 0.214 AD
1 2019-05-07 1 3.90 0.985 AD
3 2019-05-09 1 4.30 0.839 AD
4 2019-05-10 1 2.50 0.555 AD
5 2019-05-11 1 3.14 0.159 AD
是否可以通过groupby来执行此操作,或者是否可以通过其他方式使其更快?
谢谢!
答案 0 :(得分:2)
据我了解,如果对日期进行排序并且每个日期都具有相同的长度:
from itertools import islice,cycle
m=df.name.isna() #pull where name is NaN
l=df.loc[~m,'name'].tolist() #create a list for not null names
df.loc[m,'name']=list(islice(cycle(l),len(df[m]))) #repeat the list for all dates and assign to NaN
print(df)
date identifier B C name
0 2019-05-07 1 2.4 0.214 AB
1 2019-05-07 1 2.4 0.214 CD
2 2019-05-08 1 3.9 0.985 AB
3 2019-05-08 1 3.9 0.985 CD
4 2019-05-09 1 2.5 0.555 AB
5 2019-05-09 1 2.5 0.555 CD
答案 1 :(得分:1)
将itertools.product
用于所有3列的所有组合:
from itertools import product
df1 = pd.DataFrame(list(product(df['date'].unique(),
df['Identifier'].unique(),
df['Name'].dropna().unique())),
columns=['date','Identifier','Name'])
print (df1)
date Identifier Name
0 2019-05-06 1 CD
1 2019-05-06 1 AD
2 2019-05-07 1 CD
3 2019-05-07 1 AD
4 2019-05-09 1 CD
5 2019-05-09 1 AD
6 2019-05-10 1 CD
7 2019-05-10 1 AD
8 2019-05-11 1 CD
9 2019-05-11 1 AD
通过DataFrame.merge
左加入并通过DataFrame.set_index
创建MultiIndex
:
df2 = df1.merge(df, how='left').set_index(['date','Identifier'])
使用DataFrame.drop_duplicates
可能用DataFrame.combine_first
替换丢失的值:
df3 = df.drop_duplicates(['date','Identifier']).set_index(['date','Identifier'])
print (df3)
B C Name
date Identifier
2019-05-06 1 2.40 0.214 NaN
2019-05-07 1 3.90 0.985 CD
2019-05-09 1 4.30 0.839 NaN
2019-05-10 1 2.50 0.555 NaN
2019-05-11 1 3.14 0.159 NaN
df4 = df2.combine_first(df3).reset_index()
print (df4)
date Identifier B C Name
0 2019-05-06 1 2.40 0.214 CD
1 2019-05-06 1 2.40 0.214 AD
2 2019-05-07 1 3.90 0.985 CD
3 2019-05-07 1 3.90 0.985 AD
4 2019-05-09 1 4.30 0.839 CD
5 2019-05-09 1 4.30 0.839 AD
6 2019-05-10 1 2.50 0.555 CD
7 2019-05-10 1 2.50 0.555 AD
8 2019-05-11 1 3.14 0.159 CD
9 2019-05-11 1 3.14 0.159 AD
答案 2 :(得分:0)
尝试以下这种单线concat
,replace
,切片和ffill
:
print(pd.concat([df[::2],df[::2].replace('AB','CD')]).ffill())
输出:
date identifier B C name
0 2019-05-07 1 2.4 0.214 AB
2 2019-05-08 1 3.9 0.985 AB
4 2019-05-09 1 2.5 0.555 AB
0 2019-05-07 1 2.4 0.214 CD
2 2019-05-08 1 3.9 0.985 CD
4 2019-05-09 1 2.5 0.555 CD
答案 3 :(得分:0)
一种大幅提高此代码速度的方法是,首先将中间DataFrame追加到列表中,并在最后一步使用pd.concat()
连接DataFrame列表。
这将使代码如下所示:
final_df = []
for i in df.Identifier.unique():
# select the current identifier
identifier_df = df.loc[df.Identifier == i]
# allow a given identifier to have different names
for n in df.Name.unique():
if pd.isna(n):
continue
else:
intermediate = identifier_df.copy()
intermediate.loc[:,"Name"] = np.repeat(n, len(intermediate))
final_df.append(intermediate)
final_df = pd.concat(final_df).drop_duplicates()
这个简单的解决方案使我大大减少了执行时间。希望它也可以帮助其他人。