假设我们有以下简化数据:
df = pd.DataFrame({'A':list('abcd'),
'B':list('efgh'),
'Data_mean':[1,2,3,4],
'Data_std':[5,6,7,8],
'Data_corr':[9,10,11,12],
'Text_one':['foo', 'bar', 'foobar', 'barfoo'],
'Text_two':['bar', 'foo', 'barfoo', 'foobar'],
'Text_three':['bar', 'bar', 'barbar', 'foofoo']})
A B Data_mean Data_std Data_corr Text_one Text_two Text_three
0 a e 1 5 9 foo bar bar
1 b f 2 6 10 bar foo bar
2 c g 3 7 11 foobar barfoo barbar
3 d h 4 8 12 barfoo foobar foofoo
我想枚举具有相同前缀的列。在这种情况下,前缀为Data, Text
。因此,预期的输出将是:
A B Data_mean1 Data_std2 Data_corr3 Text_one1 Text_two2 Text_three3
0 a e 1 5 9 foo bar bar
1 b f 2 6 10 bar foo bar
2 c g 3 7 11 foobar barfoo barbar
3 d h 4 8 12 barfoo foobar foofoo
请注意列举的列。
尝试解决方案1 :
def enumerate_cols(dataframe, prefix):
cols = []
num = 1
for col in dataframe.columns:
if col.startswith(prefix):
cols.append(col + str(num))
num += 1
else:
cols.append(col)
return cols
enumerate_cols(df, 'Data')
['A',
'B',
'Data_mean1',
'Data_std2',
'Data_corr3',
'Text_one',
'Text_two',
'Text_three']
尝试的解决方案2:
[c+str(x+1) for x, c in enumerate([col for col in df.columns if col.startswith('Data')])]
['Data_mean1', 'Data_std2', 'Data_corr3']
问题:是否有更简单的解决方案,我也查看了df.filter(like='Data')
等。但这看起来也很牵强。
XY问题
只要确定我没有陷入XY problem。我想使用pd.wide_to_long
,但是stubnames
列需要加一个数字后缀才能融化数据框。
从文档中引用:
具有存根名称['A','B']的情况下,此函数希望查找一组或多组格式为A-后缀1,A-后缀2,…,B-后缀1,B-后缀2,
的列
pd.wide_to_long(df, stubnames=['Data', 'Text'], i=['A', 'B'], j='grp', sep='_')
这将返回一个空的数据框。
答案 0 :(得分:2)
想法是将具有相同前缀的列分组,并为它们建立一个累加器。
由于我们需要分别处理不带前缀的列,因此需要使用private void OnGenerate(object sender, EventArgs e)
{
MessagingCenter.Subscribe<App, string>(App.Current, "OpenPage", (snd, arg) =>
{
Device.BeginInvokeOnMainThread(() => {
tagLabel.Text = arg;
});
});
}
和GroupBy.cumcount
分两步进行:
np.where
cols = df.columns.str.split('_').str[0].to_series()
df.columns = np.where(
cols.groupby(level=0).transform('count') > 1,
cols.groupby(level=0).cumcount().add(1).astype(str).radd(df.columns),
cols
)
一个更简单的解决方案是将您不想添加后缀的列设置为索引。那你就可以做
df
A B Data_mean1 Data_std2 Data_corr3 Text_one1 Text_two2 Text_three3
0 a e 1 5 9 foo bar bar
1 b f 2 6 10 bar foo bar
2 c g 3 7 11 foobar barfoo barbar
3 d h 4 8 12 barfoo foobar foofoo
答案 1 :(得分:1)
您还可以使用defaultdict为每个前缀创建一个计数器。
from collections import defaultdict
prefix_starting_location = 2
columns = df.columns[prefix_starting_location:]
prefixes = set(col.split('_')[0] for col in columns)
new_cols = []
dd = defaultdict(int)
for col in columns:
prefix = col.split('_')[0]
dd[prefix] += 1
new_cols.append(col + str(dd[prefix]))
df.columns = df.columns[:prefix_starting_location].tolist() + new_cols
>>> df
A B Data_mean1 Data_std2 Data_corr3 Text_one1 Text_two2 Text_three3
0 a e 1 5 9 foo bar bar
1 b f 2 6 10 bar foo bar
2 c g 3 7 11 foobar barfoo barbar
3 d h 4 8 12 barfoo foobar foofoo
如果前缀已知:
prefixes = ['Data', 'Text']
new_cols = []
dd = defaultdict(int)
for col in df.columns:
prefix = col.split('_')[0]
if prefix in prefixes:
dd[prefix] += 1
new_cols.append(col + str(dd[prefix]))
else:
new_cols.append(col)
如果您的拆分字符_
不在您的任何数据字段中:
new_cols = []
dd = defaultdict(int)
for col in df.columns:
if '_' in col:
prefix = col.split('_')[0]
dd[prefix] += 1
new_cols.append(col + str(dd[prefix]))
else:
new_cols.append(col)
df.columns = new_cols
答案 2 :(得分:1)
您可以使用rename
,例如:
l_word = ['Data','Text']
df = df.rename(columns={ col:col+str(i+1)
for word in l_word
for i, col in enumerate(df.filter(like=word))})
答案 3 :(得分:1)
根据我们的对话,方法melt
s=df.melt(['A','B']).assign(x=lambda x : x.groupby(x.variable.str.split('_').str[0]).cumcount(),y=lambda x : x.variable.str.split('_').str[0])
# after this the problem became a pivot problem
pd.crosstab([s.A,s.B,s.x],columns=s.y,values=s.value,aggfunc='sum')
y Data Text
A B x
a e 0 1 foo
4 5 bar
8 9 bar
b f 1 2 bar
5 6 foo
9 10 bar
c g 2 3 foobar
6 7 barfoo
10 11 barbar
d h 3 4 barfoo
7 8 foobar
11 12 foofoo