Как в каждом столбце фрейма данных узнать продолжительность существования каждого уникального значения в столбце?

Пример, рассмотрим

дф:

   Time     colA    colB
0     1.1      2     2
1     2.2      2     2
2     3.4      3     5
3     4.5      3     5
4     5.6      4     5
5     6.2      4     6
6     7.4      4     6
7     8.5      2     6
8     9.8      2     5 
9     10.1     2     5
10    11.2     2     5

Ожидаемый результат — это CSV-файл отчета со следующими столбцами:

Col_name    unique_value   Duration

colA             2             3.8s 
colA             3             1.1s
colA             4             1.8s
colB             2             1.1s
colB             5             3.6s
colB             6             2.3s

(например): Чтобы вычислить colA :

unique value = 2
Duration = [1st consecutive appearance of 2 time difference (2.2-1.1)] + [2nd consecutive appearance time difference (11.2-8.5)] = 1.1 + 2.7 = 3.8s 

Одна из логик, которые я пробовал:

  1. Создайте новый столбец, который будет вычислять разницу последовательных значений в столбце и выдавать выходные данные True — если есть последовательные значения и False — если есть разные значения одно за другим.

df["answer"] = df['colA'].diff().eq(0)

  1. В качестве следующего шага я планировал собрать все False в одном списке и True в одном списке и получить разницу в списке.

  2. Меня смущает то, как связать их с уникальными ценностями.

Помогите мне выяснить, работает ли существующая логика или ее следует изменить.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
61
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

*Хорошим началом будет создание нового столбца с указанием последовательных значений True и False. Однако, чтобы вычислить продолжительность для каждого уникального значения в каждом столбце, вы можете использовать следующие шаги: Переберите каждое уникальное значение в каждом столбце. Для каждого уникального значения найдите последовательные вхождения и рассчитайте продолжительность. Сохраните результаты в новом фрейме данных.

import pandas as pd

# Sample DataFrame
data = {
    'Time': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    'colA': [1.1, 2.2, 3.4, 4.5, 5.6, 6.2, 7.4, 8.5, 9.8, 10.1, 11.2],
    'colB': [2, 2, 3, 3, 4, 4, 4, 2, 2, 2, 2]
}

df = pd.DataFrame(data)

# Function to calculate duration for each unique value in a column
def calculate_duration(column_name):
    durations = []
    unique_values = df[column_name].unique()
    for value in unique_values:
        # Find consecutive occurrences of the value
        consecutive_indices = df[df[column_name] == value].index.to_list()
        consecutive_occurrences = []
        current_occurrence = [consecutive_indices[0]]
        for i in range(1, len(consecutive_indices)):
            if consecutive_indices[i] - consecutive_indices[i-1] == 1:
                current_occurrence.append(consecutive_indices[i])
            else:
                consecutive_occurrences.append(current_occurrence)
                current_occurrence = [consecutive_indices[i]]
        consecutive_occurrences.append(current_occurrence)
        
        # Calculate duration for each consecutive occurrence
        for occurrence in consecutive_occurrences:
            start_time = df.iloc[occurrence[0]]['Time']
            end_time = df.iloc[occurrence[-1]]['Time']
            duration = end_time - start_time
            durations.append((value, duration))
    return durations

# Create a DataFrame to store results
report_df = pd.DataFrame(columns=['Col_name', 'unique_value', 'Duration'])

# Calculate durations for each column
for column in df.columns[1:]:
    durations = calculate_duration(column)
    for value, duration in durations:
        report_df = report_df.append({'Col_name': column, 'unique_value': value, 'Duration': duration}, ignore_index=True)

# Export to CSV
report_df.to_csv('report.csv', index=False)

Экспортируйте фрейм данных в файл CSV.*

Это потрясающе ! Большое спасибо за молниеносный ответ. Однако у меня есть один вопрос. Я думаю, то, как я вводил столбцы и то, как они выглядели, на самом деле запутало ввод столбцов. Я поменял местами и запустил ваш код, в котором мой результат: уникальные значения для столбца colA: [2 5 6] длительность вывода для этого столбца: [(2, 2.3), (5, 1.7000000000000002), (5, 1.3999999999999986) , (6, 1,0999999999999996)]. Здесь, если вы видите, я намеренно повторил значение 5 с другим числом между ними. Где бы я изменил код, чтобы рассматривать эти 5 вместе?

zeke wonder 16.04.2024 07:35

Для справки, это df, который я использовал: # Пример данных DataFrame = { 'Time': [1.1, 2.2, 3.4, 4.5, 5.6, 6.2, 7.4, 8.5, 9.8, 10.1, 11.2], 'colA': [2 , 2, 2, 5, 5, 5, 6, 6, 5, 5, 5], 'colB': [2, 2, 3, 3, 4, 4, 4, 2, 2, 2, 2] }

zeke wonder 16.04.2024 07:37

Я думаю, что цикл здесь не нужен, используйте методы pandas:

df1 = df.melt('Time')
s = df1['value'].ne(df1['value'].shift()).cumsum().rename('g')
out = (df1.groupby(['variable', 'value', s])['Time']
          .agg(['first','last'])
          .assign(dif=lambda x: x['last'].sub(x['first']))
          .groupby(['variable', 'value'])['dif'].sum()
          .rename_axis(['Col_name','unique_value'])
          .reset_index(name='Duration')
          )
print (out)
  Col_name  unique_value  Duration
0     colA             2       3.8
1     colA             3       1.1
2     colA             4       1.8
3     colB             2       1.1
4     colB             5       3.6
5     colB             6       2.3

Вывод с новыми данными из комментария:

df = pd.DataFrame({ 'Time': [1.1, 2.2, 3.4, 4.5, 5.6, 6.2, 7.4, 8.5, 9.8, 10.1, 11.2], 
                   'colA': [2, 2, 2, 5, 5, 5, 6, 6, 5, 5, 5],
                   'colB': [2, 2, 3, 3, 4, 4, 4, 2, 2, 2, 2] })

df1 = df.melt('Time')
s = df1['value'].ne(df1['value'].shift()).cumsum().rename('g')
out = (df1.groupby(['variable', 'value', s])['Time']
          .agg(['first','last'])
          .assign(dif=lambda x: x['last'].sub(x['first']))
          .groupby(['variable', 'value'])['dif'].sum()
          .rename_axis(['Col_name','unique_value'])
          .reset_index(name='Duration')
          )
print (out)
  Col_name  unique_value  Duration
0     colA             2       2.3
1     colA             5       3.1
2     colA             6       1.1
3     colB             2       3.8
4     colB             3       1.1
5     colB             4       1.8

Как это работает:

Первые значения, которые можно отменить с помощью DataFrame.melt:

df1 = df.melt('Time')
print (df1)
    Time variable  value
0    1.1     colA      2
1    2.2     colA      2
2    3.4     colA      2
3    4.5     colA      5
4    5.6     colA      5
5    6.2     colA      5
6    7.4     colA      6
7    8.5     colA      6
8    9.8     colA      5
9   10.1     colA      5
10  11.2     colA      5
11   1.1     colB      2
12   2.2     colB      2
13   3.4     colB      3
14   4.5     colB      3
15   5.6     colB      4
16   6.2     colB      4
17   7.4     colB      4
18   8.5     colB      2
19   9.8     colB      2
20  10.1     colB      2
21  11.2     colB      2

Создайте Series следующих значений:

print (df1.assign(g=s))
    Time variable  value  g
0    1.1     colA      2  1
1    2.2     colA      2  1
2    3.4     colA      2  1
3    4.5     colA      5  2
4    5.6     colA      5  2
5    6.2     colA      5  2
6    7.4     colA      6  3
7    8.5     colA      6  3
8    9.8     colA      5  4
9   10.1     colA      5  4
10  11.2     colA      5  4
11   1.1     colB      2  5
12   2.2     colB      2  5
13   3.4     colB      3  6
14   4.5     colB      3  6
15   5.6     colB      4  7
16   6.2     colB      4  7
17   7.4     colB      4  7
18   8.5     colB      2  8
19   9.8     colB      2  8
20  10.1     colB      2  8
21  11.2     colB      2  8

Агрегировать по последовательным unique_value по вспомогательным s сериям с помощью GroupBy.first и GroupBy.last значения по группам:

print (df1.groupby(['variable', 'value', s])['Time']
          .agg(['first','last']))

                  first  last
variable value g             
colA     2     1    1.1   3.4
         5     2    4.5   6.2
               4    9.8  11.2
         6     3    7.4   8.5
colB     2     5    1.1   2.2
               8    8.5  11.2
         3     6    3.4   4.5
         4     7    5.6   7.4

Вычтите столбцы для разницы:

print (df1.groupby(['variable', 'value', s])['Time']
          .agg(['first','last'])
          .assign(dif=lambda x: x['last'].sub(x['first'])))
                  first  last  dif
variable value g                  
colA     2     1    1.1   3.4  2.3
         5     2    4.5   6.2  1.7
               4    9.8  11.2  1.4
         6     3    7.4   8.5  1.1
colB     2     5    1.1   2.2  1.1
               8    8.5  11.2  2.7
         3     6    3.4   4.5  1.1
         4     7    5.6   7.4  1.8

И сумма по группам за последний раз:

print (df1.groupby(['variable', 'value', s])['Time']
          .agg(['first','last'])
          .assign(dif=lambda x: x['last'].sub(x['first']))
          .groupby(['variable', 'value'])['dif'].sum())

variable  value
colA      2        2.3
          5        3.1
          6        1.1
colB      2        3.8
          3        1.1
          4        1.8
Name: dif, dtype: float64

Последнее переименование индексных имен и преобразование в DataFrame:

s = df1['value'].ne(df1['value'].shift()).cumsum().rename('g')
out = (df1.groupby(['variable', 'value', s])['Time']
          .agg(['first','last'])
          .assign(dif=lambda x: x['last'].sub(x['first']))
          .groupby(['variable', 'value'])['dif'].sum()
          .rename_axis(['Col_name','unique_value'])
          .reset_index(name='Duration')
          )

print (out)
  Col_name  unique_value  Duration
0     colA             2       2.3
1     colA             5       3.1
2     colA             6       1.1
3     colB             2       3.8
4     colB             3       1.1
5     colB             4       1.8

Это удивительное использование панд. Спасибо за ваш ответ

zeke wonder 16.04.2024 08:50

Другие вопросы по теме