簡體   English   中英

替換部分匹配字符串的pandas數據框中的列名

[英]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是第一個發布的,也是執行時間最快的之一。 如果有人感興趣,我會在稍后提供代碼。

編輯2

當我嘗試時,來自suvy的建議呈現了這些結果: 在此輸入圖像描述

該片段工作正常,直到最后一行。 在運行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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM