Как разделить каждый столбец на несколько столбцов в данном фрейме данных

#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)