[英]Replace column names in a pandas data frame that partially match a string
我想在数据框中识别部分匹配字符串的列名称,并将其替换为原始名称以及添加到其中的一些新元素。 新元素是由列表定义的整数。 这是一个类似的问题 ,但我担心在我的特定情况下,建议的解决方案不够灵活。 这是另一篇文章,其中有几个很好的答案接近我面临的问题。
我知道我可以组合两个字符串列表,将它们成对映射到字典中 ,并使用字典重命名列作为函数df.rename
输入。 但考虑到现有列的数量会有所不同,这似乎有点过于复杂,而且不够灵活。 与要重命名的列数一样。
以下代码段将生成一个输入示例:
# Libraries
import numpy as np
import pandas as pd
import itertools
# A dataframe
Observations = 5
Columns = 5
np.random.seed(123)
df = pd.DataFrame(np.random.randint(90,110,size=(Observations, Columns)),
columns = ['Price','obs_1','obs_2','obs_3','obs_4'])
datelist = pd.date_range(pd.datetime.today().strftime('%Y-%m-%d'),
periods=Observations).tolist()
df['Dates'] = datelist
df = df.set_index(['Dates'])
print(df)
我想识别以obs_
开头的列名,并在=
符号后面的列表newElements = [5, 10, 15, 20]
添加元素(整数)。 名为Price
的列保持不变。 在obs_
列之后出现的其他列也应保持不变。
以下代码段将演示所需的输出:
# Desired output
Observations = 5
Columns = 5
np.random.seed(123)
df2 = pd.DataFrame(np.random.randint(90,110,size=(Observations, Columns)),
columns = ['Price','Obs_1 = 5','Obs_2 = 10','Obs_3 = 15','Obs_4 = 20'])
df2['Dates'] = datelist
df2 = df2.set_index(['Dates'])
print(df2)
# Define the partial string I'm lookin for
stringMatch = 'Obs_'
# Put existing column names in a list
oldnames = list(df)
# Put elements that should be added to the column names
# where the three first letters match 'obs_'
newElements = [5, 10, 15, 20]
oldElements = [1, 2, 3, 4]
# Change types of the elements in the list
str_newElements = [str(x) for x in newElements]
str_oldElements = [str(y) for y in oldElements]
str_newNames = str_newElements.copy()
# Since I know the first column should not be renamed,
# I start with 'Price' in a list
newnames = ['Price']
# Then I add the renamed parts to the same list
i = 0
for oldElement in str_oldElements:
#print(repr(oldElement) + repr(str_newElements[i]))
newnames.append(stringMatch + oldElement + ' = ' + str_newElements[i])
i = i + 1
# Rename columns using the dict as input in df.rename
df.rename(columns = dict(zip(oldnames, newnames)), inplace = True)
print('My attempt: ', df)
已经完成了新列名的完整列表,我也可以使用df.columns = newnames
,但希望你们中的一个人以更加df.rename
方式使用df.rename
得到了一个建议。
谢谢你的任何建议!
这是一个简单的复制粘贴的完整代码:
# Libraries
import numpy as np
import pandas as pd
import itertools
# A dataframe
Observations = 5
Columns = 5
np.random.seed(123)
df = pd.DataFrame(np.random.randint(90,110,size=(Observations, Columns)),
columns = ['Price','obs_1','obs_2','obs_3','obs_4'])
datelist = pd.date_range(pd.datetime.today().strftime('%Y-%m-%d'),
periods=Observations).tolist()
df['Dates'] = datelist
df = df.set_index(['Dates'])
print('Input: ', df)
# Desired output
Observations = 5
Columns = 5
np.random.seed(123)
df2 = pd.DataFrame(np.random.randint(90,110,size=(Observations, Columns)),
columns = ['Price','Obs_1 = 5','Obs_2 = 10','Obs_3 = 15','Obs_4 = 20'])
df2['Dates'] = datelist
df2 = df2.set_index(['Dates'])
print('Desired output: ', df2)
# My attempts
# Define the partial string I'm lookin for
stringMatch = 'Obs_'
# Put existing column names in a list
oldnames = list(df)
# Put elements that should be added to the column names
# where the three first letters match 'obs_'
newElements = [5, 10, 15, 20]
oldElements = [1, 2, 3, 4]
# Change types of the elements in the list
str_newElements = [str(x) for x in newElements]
str_oldElements = [str(y) for y in oldElements]
str_newNames = str_newElements.copy()
# Since I know the first column should not be renamed,
# I start with 'Price' in a list
newnames = ['Price']
# Then I add the renamed parts to the same list
i = 0
for oldElement in str_oldElements:
#print(repr(oldElement) + repr(str_newElements[i]))
newnames.append(stringMatch + oldElement + ' = ' + str_newElements[i])
i = i + 1
# Rename columns using the dict as input in df.rename
df.rename(columns = dict(zip(oldnames, newnames)), inplace = True)
print('My attempt: ', df)
仅仅一天之后,这么多好的答案真是太神奇了! 这使得很难确定接受哪个答案。 我不知道以下是否会给整个帖子增加很多价值,但我继续把所有建议都包含在函数中并用%timeit测试它们。
建议fram HH1是第一个发布的,也是执行时间最快的之一。 如果有人感兴趣,我会在稍后提供代码。
该片段工作正常,直到最后一行。 在运行df = df.rename(columns=dict(zip(names,renames)))
,数据框看起来像这样:
您可以使用列表理解:
df.columns = [ i if "_" not in i else i + "=" + str(newElements[int(i[-1])-1]) for i in df.columns]
产量
Price obs_1=5 obs_2=10 obs_3=15 obs_4=20
0 103 92 92 96 107
1 109 100 91 90 107
2 105 99 90 104 90
3 105 109 104 94 90
4 106 94 107 93 92
从输入数据框开始,在这里调用df
Price obs_1 obs_2 obs_3 obs_4
Dates
2017-06-15 103 92 92 96 107
2017-06-16 109 100 91 90 107
2017-06-17 105 99 90 104 90
2017-06-18 105 109 104 94 90
2017-06-19 106 94 107 93 92
newElements = [5, 10, 15, 20]
names = list(filter(lambda x: x.startswith('obs'), df.columns.values))
renames = list(map(lambda x,y: ' = '.join([x,str(y)]), names, newElements))
df = df.rename(columns=dict(zip(names,renames)))
回报
Price obs_1 = 5 obs_2 = 10 obs_3 = 15 obs_4 = 20
Dates
2017-06-19 103 92 92 96 107
2017-06-20 109 100 91 90 107
2017-06-21 105 99 90 104 90
2017-06-22 105 109 104 94 90
2017-06-23 106 94 107 93 92
这有用吗?
df.columns = [col + ' = ' + str(newElements.pop(0)) if col.startswith(stringMatch) else col for col in df.columns]
选择所需的列,进行所需的更改并使用原始df加入
obs_cols = df.columns[df.columns.str.startswith('obs')]
obs_cols = [col + ' = ' + str(val) for col, val in zip(obs_cols, newElements)]
df.columns = list(df.columns[~df.columns.str.startswith('obs')]) + obs_cols
Price obs_1 = 5 obs_2 = 10 obs_3 = 15 obs_4 = 20
0 103 92 92 96 107
1 109 100 91 90 107
2 105 99 90 104 90
3 105 109 104 94 90
4 106 94 107 93 92
为了完整df.rename
,因为你提到了df.rename
,你可以用字典理解为它创建输入,其方式与其他答案中的列表df.rename
类似。
# Where Observations = len(df.index) as in the example
>>>newcols = {col: col+' = '+str(int(col[col.rfind('_')+1:])*Observations)
for col in df.columns if col.find('obs_') != -1}
>>>df.rename(columns=newcols)
Price obs_1 = 5 obs_2 = 10 obs_3 = 15 obs_4 = 20
Dates
2017-06-15 103 92 92 96 107
2017-06-16 109 100 91 90 107
2017-06-17 105 99 90 104 90
2017-06-18 105 109 104 94 90
2017-06-19 106 94 107 93 92
在这里,我还对你为什么要添加特定的新元素做了一些假设。 如果这些假设是错误的, df.rename
和字典理解仍然可以与其他答案之一的方法一起使用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.