#python #pandas
Вопрос:
У меня более 100 столбцов недели, и для каждого столбца недели я хочу разделить его на дни и присвоить каждой строке значения, зависящие от строки, более 7 новых столбцов. Подобный этому
Я новичок в python, я знаю, что мне нужны циклы while и для циклов, но теперь я не знаю, как это сделать. Кто-нибудь может помочь?
Основываясь на предыдущих советах, которые я получил на этом форуме, приведенная ниже работа для недели 1, может ли кто-нибудь посоветовать мне, как повторять каждую неделю со 2-й, 3-й, 4-й по n-ю неделю?
import pandas as pd df = pd.DataFrame({"Week1": [9, 30, 35, 65],"Week2": [20, 10, 25, 55],"Week3": [19, 35, 40, 15],"Week4": [7, 10, 70, 105]}) # define which columns need to be created # this will be the range between 1 and the maximum of the Total Number column columns_to_fill = ["col" str(i) for i in range(1, 8)] # columns_to_fill = [ col1, col2, col3, col4, col5, col6, col7, col8, col9, col10, .... , col28 ] # now, go through each row of your dataframe for indx, row in df.iterrows(): # and for each column in the new columns to be filled # check if the number is smaller or equal than the row's Total Number # if it is smaller, fill the column with 1 # else fill the column with 0 for number, column in enumerate(columns_to_fill): if number 1 lt;= row["Week1"]: df.loc[indx, column] = 1 else: df.loc[indx, column] = 0 # now check if there is a remainder remainder = row["Week1"] - 7 # while remainder is greater than 0 # we need to continue adding 1 to the columns while remainder gt; 0: for number, column in enumerate(columns_to_fill): if number 1 lt;= remainder: df.loc[indx, column] = 1 else: continue # update remainder remainder = remainder - 7
Комментарии:
1. что происходит со значениями, когда вы создаете свои новые недели и дни?
2. Привет, Умар, столбцы недель уже есть, я создаю столбцы дней с недели и использую столбец новых дней в будущем.
Ответ №1:
Вот вариант векторизации, сначала repeat
по каждой строке 7 раз (количество дней в неделю), и добавьте дополнительный уровень индекса с set_index
номером дня.
_df = ( df.loc[df.index.repeat(7)] .set_index(np.array(list(range(1,8))*len(df)), append=True) ) print(_df.head(10)) # Week1 Week2 Week3 Week4 # 0 1 9 20 19 7 # 2 9 20 19 7 # 3 9 20 19 7 # 4 9 20 19 7 # 5 9 20 19 7 # 6 9 20 19 7 # 7 9 20 19 7 # 1 1 30 10 35 10 # 2 30 10 35 10 # 3 30 10 35 10
теперь рассчитайте результат всего деления с //7
помощью , а затем добавьте остальное, где это необходимо, используя модуль %
, который вы можете сравнить с дополнительным уровнем индекса, созданным, поскольку это номер дня.
# entire division res = _df//7 # add the rest where needed res = (_df%7 gt;= _df.index.get_level_values(1).to_numpy()[:, None]).astype(int) print(res) # Week1 Week2 Week3 Week4 # 0 1 2 3 3 1 # 2 2 3 3 1 # 3 1 3 3 1 # 4 1 3 3 1 # 5 1 3 3 1 # 6 1 3 2 1 # 7 1 2 2 1 # 1 1 5 2 5 2 # 2 5 2 5 2 # 3 4 2 5 2
Наконец, измените форму и переименуйте столбцы, если хотите.
# reshape the result res = res.unstack() # rename the columns if you don't want multiindex res.columns = [f'{w}_col{i}' for w, i in res.columns] print(res) # Week1_col1 Week1_col2 Week1_col3 Week1_col4 Week1_col5 Week1_col6 # 0 2 2 1 1 1 1 # 1 5 5 4 4 4 4 # 2 5 5 5 5 5 5 # 3 10 10 9 9 9 9 # Week1_col7 Week2_col1 Week2_col2 Week2_col3 Week2_col4 Week2_col5 # 0 1 3 3 3 3 3 # 1 4 2 2 2 1 1 # ...
и вы все еще join
можете вернуться к своему исходному кадру данных
res = df.join(res)
Комментарии:
1. Спасибо, Бен, я попытался запустить код и получил ошибку. Что такое np. в вашем втором сценарии? Я предполагаю, что мне нужно поместить import numpy в np? 🙂
Ответ №2:
Это повторяет исходный фрейм данных. Строки фрейма данных могут быть любой длины и содержать любое количество элементов заголовка. Подзаголовок может содержать любое количество элементов (1D).
#Import import numpy as np import pandas as pd #Example data frame and sub-header. df = pd.DataFrame({"Week1": [9, 30, 35, 65],"Week2": [20, 10, 25, 55],"Week3": [19, 35, 40, 15],"Week4": [7, 10, 70, 105]}) subHeader = ['day1','day2','day3','day4','day5','day6','day7'] #Sort data frame and sub header. df = df.reindex(sorted(df.columns), axis=1) subHeader.sort() #Extract relevant variables. cols = df.shape[1] rows = df.shape[0] subHeadLen = len(subHeader) mainHeader = list(df.columns) meanHeadLen = len(mainHeader) #MultiIndex main header with sub-header. header = pd.MultiIndex.from_product([mainHeader,subHeader], names=['Week','Day']) #Hold vals in temporary matrix. mat = np.zeros((rows,meanHeadLen*subHeadLen)) #Iterate over data frame weeks. For every value in each row distribute over matrix indices by incrementing elements daily. for col in range(cols): for val in range(rows): while df.iat[val,col] gt; 0: for subVal in range(subHeadLen): if df.iat[val,col] gt; 0: mat[val][col*subHeadLen subVal] = mat[val][col*subHeadLen subVal] 1 df.iat[val,col] = df.iat[val,col] - 1 #Final data frame. df2 = pd.DataFrame(mat,columns=header) print(df2)