我正在尝试将值分为pandas df中的不同列。具体来说,我在同一列中有代表标签和时间戳的字符串。我希望将它们分成单独的列。我只是不确定会更有效的过程。
对于下面的df,我想将时间字符串分成一个单独的列。
df = pd.DataFrame({
'Value' : ['Foo X','10:00','10:00','10:00','10:00','Bar X','11:00','11:00','Cat X','12:00','12:00','12:00'],
'Number' : [0,1,2,3,4,0,1,2,0,1,2,3],
})
出局:
Value Number
0 Foo X 0
1 10:00 1
2 10:00 2
3 10:00 3
4 10:00 4
5 Bar X 0
6 11:00 1
7 11:00 2
8 Cat X 0
9 12:00 1
10 12:00 2
11 12:00 3
问题在于每个标签的时间戳数量不同,因此我不能仅在第n行中拆分。例如
df1 = pd.DataFrame({'Value':df['Value'].iloc[:1:4].values, 'Time':df['Value'].iloc[:1:4].values})
另一种尝试是创建一个单独的列,以传递df.Value中的所有值,然后将所有时间戳替换为np.nan并设置输出子集。但是我不确定这是否非常有效?
Value Number Time
0 Foo X 0 Foo X
1 10:00 1 10:00
2 10:00 2 10:00
3 10:00 3 10:00
4 10:00 4 10:00
5 Bar X 0 Bar X
6 11:00 1 11:00
7 11:00 2 11:00
8 Cat X 0 Cat X
9 12:00 1 12:00
10 12:00 2 12:00
11 12:00 3 12:00
预期输出:
Value Number Time
0 Foo X 1 10:00
1 Foo X 2 10:00
2 Foo X 3 10:00
3 Foo X 4 10:00
4 Bar X 1 11:00
5 Bar X 2 11:00
6 Cat X 1 12:00
7 Cat X 2 12:00
8 Cat X 3 12:00
答案 0 :(得分:1)
以下功能应该会为您提供所需的输出。
def process_dataframe(df):
s = df.loc[df.Number==0]['Value']
labels = s.to_list()
a = s.index.to_list()
a.append(df.index.size)
repnum = [x2 - x1 - 1 for x1,x2 in zip(a[:-1], a[1:])]
df2 = df.loc[df['Number']!=0].copy()
df2['Time'] = df2['Value']
df2['Value'] = s.repeat(repnum).to_list()
return df2
process_dataframe(df)
输出
Value Number Time
0 Foo X 1 10:00
1 Foo X 2 10:00
2 Foo X 3 10:00
3 Foo X 4 10:00
4 Bar X 1 11:00
5 Bar X 2 11:00
6 Cat X 1 12:00
7 Cat X 2 12:00
8 Cat X 3 12:00
答案 1 :(得分:1)
您可以将groupby与pd.Series.repat一起使用
创建Value
列
然后通过使用boolean indexing选择Time
和Number
:
value_bool=pd.Series(['X' in key for key in df['Value']])
Value=df.loc[value_bool]['Value'] #selecting values for the Value column
groups=df.groupby(value_bool.cumsum())
new_df=Value.repeat(groups.size()-1).to_frame().reset_index(drop=True) #create dataframe with new Value Column
new_df[['Number','Time']]=df.loc[~value_bool].reset_index(drop=True).reindex(columns=['Number','Value']) #creating Number and Time
输出:
Value Number Time
0 Foo X 1 10:00
1 Foo X 2 10:00
2 Foo X 3 10:00
3 Foo X 4 10:00
4 Bar X 1 11:00
5 Bar X 2 11:00
6 Cat X 1 12:00
7 Cat X 2 12:00
8 Cat X 3 12:00
答案 2 :(得分:1)
想法是用to_datetime
和errors='coerce'
来区分缺少的不匹配值的时间值:
mask = pd.to_datetime(df['Value'], errors='coerce').notna()
或用:
用Series.str.contains
表示测试模式2位数字:
mask = df['Value'].str.contains(r'\d{2}:\d{2}')
可能的测试是否等于0
:
mask = df['Number'].ne(0)
然后创建新列,并用Series.mask
将Value
的{{1}}替换为NaN
,并向前填充缺失值,最后用boolean indexing
进行过滤:>
mask
答案 3 :(得分:1)
使用遮罩和填充的另一种解决方案:
%02.2hhx