Страницы

Поиск по вопросам

Показаны сообщения с ярлыком pandas. Показать все сообщения
Показаны сообщения с ярлыком pandas. Показать все сообщения

вторник, 31 марта 2020 г.

Преобразование Фурье в Pandas

#python #pandas #dataframe #scipy #фурье


Есть DataFrame примерно такого содержания:

Time     Data
95114    1012.0
96078    1108.0
97033    1132.0
98015    1076.0
...


Состоит из 100 строк, где:


Time - время измерения в микросекундах
Data - измеряемое значение. 


Мне необходимо найти ДПФ этой зависимости. Все бы ничего, только частота измерения
непостоянна. Она немного плывет со временем случайным образом. Т.е. мои потуги в духе:

xf = fftfreq(len(df['Time']),1000) # 1000 взята как примерный период измерений
i = xf > 0
yf = fft(df['Data'])


Дают немного неожиданный результат. Я так понимаю, что дело в частоте. Как правильно
ее искать? Интерполировать свой дискретный ряд и потом уже находить его ДПФ? 

В итоге мне нужно будет найти площадь между определенными частотами спектра. 
    


Ответы

Ответ 1



Можно воспользоваться методом DataFrame.resample(), чтобы преобразовать DataFrame во временной ряд с единым интервалом (в качестве единого интервала возьмем средний интервал между замерами в микросекундах) и после этого интерполировать недостающие значения. Для этого надо конвертировать df.Time в datetime dtype и установить этот столбец в качестве индекса: In [62]: freq = int(df['Time'].diff().mean()) # средняя частота измерения в микросекундах In [63]: freq Out[63]: 967 In [64]: df = (df.set_index(pd.to_datetime(df.pop('Time'), unit='us')) .resample('{}U'.format(freq)) .mean() .interpolate()) In [65]: df Out[65]: Data Time 1970-01-01 00:00:00.094766 1012.0 1970-01-01 00:00:00.095733 1108.0 1970-01-01 00:00:00.096700 1132.0 1970-01-01 00:00:00.097667 1076.0 После этого можно попробовать воспользоваться преобразованиями Фурье.

понедельник, 30 марта 2020 г.

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

#python #python_3x #pandas #dataframe


Есть датафрейм df. Есть фича feat имеющая три категории cat1, cat2, и немногочисленная
Unknown. 

Я хочу избавиться от Unknown, раскидав ее по cat1 и cat2 так, чтобы она разлетелась
по ним пропорционально их доле в датасете. То есть, если изначально было 45% cat1,
40% cat2 и 5% Unknown, то нужно, чтобы Unknown разлетелась в между cat1 и сat2 в соотношении 9/8.

В документации и блогах ничего подобного не нашел.  
    


Ответы

Ответ 1



Исходный DF: In [67]: %paste df = pd.DataFrame({'feat':np.random.choice(['cat1','cat2','Unknown'], size=100, p=[0.45,0.40,0.15])}) ## -- End pasted text -- In [68]: df.feat.value_counts() Out[68]: cat1 49 cat2 36 Unknown 15 Name: feat, dtype: int64 Сначала найдем соотношение между cat1 и cat2: In [69]: pct = df.feat.value_counts() / len(df) In [70]: ratio = pct.loc[['cat1','cat2']].min() / pct.loc[['cat1','cat2']].max() In [71]: pct Out[71]: cat1 0.49 cat2 0.36 Unknown 0.15 Name: feat, dtype: float64 In [72]: ratio Out[72]: 0.7346938775510204 теперь заменим строки с Unknown с таким же соотношением: In [74]: df.loc[df['feat']=='Unknown', 'feat'] = \ ...: np.random.choice([pct[['cat1','cat2']].idxmax(), pct[['cat1','cat2']].idxmin()], ...: size=df['feat'].eq('Unknown').sum(), ...: p=[ratio, 1-ratio]) ...: ...: In [75]: df.feat.value_counts() Out[75]: cat1 62 cat2 38 Name: feat, dtype: int64 проверка соотношения после замены значений: In [76]: pct.loc[['cat1','cat2']].min() / pct.loc[['cat1','cat2']].max() Out[76]: 0.7346938775510204

Получение строки значений из groupby

#python #pandas #dataframe #group_by


Есть DataFrameGroupby со следующими данными:

                       last  vol
datetime                        
2013-07-23 10:00:00  112450   49
2013-07-23 10:00:00  112440   67
2013-07-23 10:00:00  112430   93
2013-07-23 10:00:00  112420   52
2013-07-23 10:00:00  112410   63

                       last  vol
datetime                        
2013-07-23 10:01:00  112690   17
2013-07-23 10:01:00  112680   59
2013-07-23 10:01:00  112670  226
2013-07-23 10:01:00  112660  184
2013-07-23 10:01:00  112650  289


Сгруппированные по уровню индекса:

blocks_group = datetime_group.groupby(level=0)


Как получить целую строку из каждой группы с максимальным значением, а не только
значения столбца vol?
    


Ответы

Ответ 1



Исходный DataFrame: In [47]: df Out[47]: last vol datetime 2018-08-31 10:00:00 112450 49 2018-08-31 10:00:00 112440 67 2018-08-31 10:00:00 112430 93 2018-08-31 10:00:00 112420 52 2018-08-31 10:00:00 112410 63 2018-08-31 10:01:00 112690 17 2018-08-31 10:01:00 112680 59 2018-08-31 10:01:00 112670 226 2018-08-31 10:01:00 112660 184 2018-08-31 10:01:00 112650 289 Решение: In [48]: df.groupby(level=0, as_index=False).apply(lambda x: x.nlargest(1, 'vol')) Out[48]: last vol datetime 0 2018-08-31 10:00:00 112430 93 1 2018-08-31 10:01:00 112650 289 Ещё один, менее идиоматичный, вариант: In [51]: df.sort_values('vol').groupby(level=0).tail(1) Out[51]: last vol datetime 2018-08-31 10:00:00 112430 93 2018-08-31 10:01:00 112650 289

Столбец по сгруппированным данным Pandas

#python #pandas #dataframe #group_by


Имеется Pandas DataFrame, например:

  city  col1  
0  nsk    15
1  nsk    17
2  nsk    22
3  vdk    11
4  vdk     9


Требуется добавить столбец, в котором будут суммы значений col1, сгруппированные
по столбцу city. Например:

  city  col1  col2
0  nsk    15    54
1  nsk    17    54
2  nsk    22    54
3  vdk    11    20
4  vdk     9    20

    


Ответы

Ответ 1



In [434]: df['col2'] = df.groupby('city')['col1'].transform('sum') In [435]: df Out[435]: city col1 col2 0 nsk 15 54 1 nsk 17 54 2 nsk 22 54 3 vdk 11 20 4 vdk 9 20

воскресенье, 29 марта 2020 г.

Как эффективно объединить несколько pandas DataFrame?

#python #pandas #numpy #dataframe


Готовлю данные для модели, в частности заполняю пропуски для вещественных признаков
и преобразую категориальные. Исходные данные имеют размерность (40000, 230), из них
первые 190 признаков вещественные, остальные — категориальные.


Подготовим вещественные данные для анализа. Заполним пропуски средним

X_data = pd.DataFrame()
for column in data.columns[:num_of_numerical_vars]:
    m1 = data[column].mean()
    if np.isnan(m1):
        m1 = data[column].notnull().mean()
    X_data[column] = data[column].fillna(m1) 

Подготовим категориальные признаки. Воспользуемся LabelEncoder в 
связке с OneHotEncoder

label_encoder = LabelEncoder()
data_categorical_num = data_categorical.apply(lambda col: label_encoder.fit_transform(col))
hot_encoder = OneHotEncoder(handle_unknown='ignore', sparse=False)
encoded_categorical = hot_encoder.fit_transform(data_categorical_num)



Выводим размерность encoded_categorical

print encoded_categorical.shape


Вывод:


  (40000, 143513)


То есть данных довольно много. Подскажите, как в этом случае объединить получившиеся
вещественные и категориальные признаки эффективно? Если написать что–то вроде:

pd_cats = pd.DataFrame(data=encoded_categorical)
X_data = pd.concat([X_data, pd_cats])


То на моем ПК не хватает памяти для данной операции. Как мне кажется, данные можно
объединить как–то без копирования данных.

Данные могут быть загружены отсюда ("small" dataset)
    


Ответы

Ответ 1



В данном случае стоит использовать разреженные матрицы / фреймы. from sklearn.preprocessing import MultiLabelBinarizer mlb = MultiLabelBinarizer(sparse_output=True) WORK_DIR = Path(r'D:\data\927487') train = pd.read_csv(WORK_DIR / 'orange_small_train.data', sep='\t') labels = pd.read_csv(WORK_DIR / 'orange_small_train_appetency.labels', header=None, squeeze=True, dtype='int8') categorical_cols = train.columns[train.dtypes.eq('object')] train_cat = train[categorical_cols].copy() train = pd.SparseDataFrame(train.drop(categorical_cols, axis=1)) train = train.join( pd.SparseDataFrame( mlb.fit_transform( train_cat.T.apply(lambda c: c.dropna() .str.cat(sep=' ') .split())), default_fill_value=0)) Результат: In [242]: type(train) Out[242]: pandas.core.sparse.frame.SparseDataFrame In [243]: train.memory_usage().sum() Out[243]: 27806864 # NOTE: sparse DF takes only 27 MiB in RAM In [244]: train.shape Out[244]: (50000, 71696)

Ответ 2



Несколько слов об обработке столбцов с преимущественно отсутствующими данными... Если внимательно посмотреть на исходные данные, то можно заметить, что львиная доля (154) столбцов состоит из NaN на 90+%: train = pd.read_csv(WORK_DIR / 'orange_small_train.data', sep='\t') labels = pd.read_csv(WORK_DIR / 'orange_small_train_appetency.labels', header=None, squeeze=True, dtype='int8') оценка количества столбцов состоящих преимущественно из NaN: In [52]: (train.isna().sum() / len(train) > 0.9).sum() Out[52]: 154 мне кажется стоит попробовать построить регрессионную модель в которой данные столбцы не будут учавствовать вовсе и сравнить с той моделью, где такие данные заполнены средним значением (с высокой долей вероятности эти столбцы/признаки не сильно повлияют на результаты предсказываний): In [54]: train = train.loc[:, train.isna().sum() / len(train) <= 0.9] In [55]: train.shape Out[55]: (50000, 76) categorical_cols = train.columns[train.dtypes.eq('object')] train_cat = train[categorical_cols].copy() # drop categorical cols from the train DF train = train.drop(categorical_cols, axis=1) Чтобы заполнить NaN в оставшихся вещественных столбцах можно воспользоваться sklearn.imputer.SimpleImputer. Кроме того стоит нормализовать данные, чтобы все признаки имели одинаковую шкалу величин - для этого существует sklearn.preprocessing.StandardScaler: from sklearn.impute import SimpleImputer from sklearn.preprocessing import StandardScaler impute = SimpleImputer(strategy='mean') scale = StandardScaler() train = pd.SparseDataFrame( scale.fit_transform(impute.fit_transform(train)), columns=train.columns, index=train.index, default_fill_value=0) train = train.join( pd.SparseDataFrame( mlb.fit_transform( train_cat.T.apply(lambda c: c.dropna() .str.cat(sep=' ') .split())), default_fill_value=0)) In [82]: train.memory_usage().sum() Out[82]: 21455996 In [83]: train.shape Out[83]: (50000, 71542) In [84]: train.info() RangeIndex: 50000 entries, 0 to 49999 Columns: 71542 entries, Var6 to 71499 dtypes: float64(42), int32(71500) memory usage: 20.5 MB PS также стоит попробовать воспользоваться методом главных компонент (sklearn.decomposition.PCA) для уменьшения размерности (уменьшить число признаков) выборки и сравнить результаты регрессии. PCA позволяет значительно уменьшить число признаков, выбрав самые значимые. Как работает MultilabelBinarizer: In [104]: mlb = MultiLabelBinarizer() In [105]: df = pd.DataFrame({ ...: 'Col1': [10, 20, 30], ...: 'Col2': [['Apple','Orange','Banana'], ['Apple','Grape'], ['Banana']] ...: }) In [106]: df Out[106]: Col1 Col2 0 10 [Apple, Orange, Banana] 1 20 [Apple, Grape] 2 30 [Banana] In [107]: df.join(pd.DataFrame(mlb.fit_transform(df['Col2']), index=df.index, columns=mlb.classes_)) Out[107]: Col1 Col2 Apple Banana Grape Orange 0 10 [Apple, Orange, Banana] 1 1 0 1 1 20 [Apple, Grape] 1 0 1 0 2 30 [Banana] 0 1 0 0

Как в pandas применить метод rolling к нескольким столбцам DataFrame?

#python #python_3x #pandas #dataframe


Подскажите, как правильнее скользящим окном пройтись по датафрейму для нескольких
столбцов? Окно например 3х3.

Я хочу вычислять максимум из значений попадающих в это окно и записать их в новый
столбец. Вот мой код в несколько действий:

x = pd.Series([1, 4, 3, 2, 1, 6, 2, 8, 3, 0, 1, 2, 1, 5])

df = pd.DataFrame({"A": x**2+8, "B": x*8, "C": x+34})
df[['maxA','maxB','maxC']]  = df.loc[:,'A':'C'].rolling(3).max()
df['Max_ABC']  = df.loc[:,['maxA','maxB','maxC']].max(axis=1)

df


Сейчас я использую промежуточное вычисление как на рисунке, используя столбцы ['maxA','maxB','maxC']
только для получения промежуточного результата. Мне видится что это лишний шаг вычисления,
и наверное есть более простой способ решения.


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


    


Ответы

Ответ 1



In [46]: df['Max_ABC'] = df[['A','B','C']].rolling(3).max().max(axis='columns') In [47]: df Out[47]: A B C Max_ABC 0 9 8 35 NaN 1 12 16 36 NaN 2 17 24 37 37.0 3 24 32 38 38.0 4 33 40 39 40.0 5 44 48 40 48.0 6 57 56 41 57.0 7 72 64 42 72.0 Пояснение: df[['A','B','C']].rolling(3).max() - возвращает максимумы в скользящем окне для всех указанных столбцов: In [51]: df[['A','B','C']].rolling(3).max() Out[51]: A B C 0 NaN NaN NaN 1 NaN NaN NaN 2 17.0 24.0 37.0 3 24.0 32.0 38.0 4 33.0 40.0 39.0 5 44.0 48.0 40.0 6 57.0 56.0 41.0 7 72.0 64.0 42.0 далее мы выбираем максимум для каждой строки, указав axis='columns': In [52]: df[['A','B','C']].rolling(3).max().max(axis='columns') Out[52]: 0 NaN 1 NaN 2 37.0 3 38.0 4 40.0 5 48.0 6 57.0 7 72.0 dtype: float64

Объединение двух таблиц по конкретному столбцу

#python #pandas #dataframe #join


Как грамотно объединить таблицы по столбцу Б? 

На примере будет наглядней. У меня есть таблица А и Б, количество строк не совпадает.

Табл. А: 

   А  Б  
0  1  2  
1  1  3  
2  2  2  
3  2  3  
4  2  1


Табл. Б: 

   Б  В  
0  1  4  
1  2  5  
2  3  6


Требуемый результат:

Табл. В: 

   А  Б  Б  В    
0  1  2  2  5   
1  1  3  3  6   
2  2  2  2  5   
3  2  3  3  6   
4  2  1  1  4  


Как вы сами понимаете, мне требуется "подтянуть" значения из столбца В.
В SQL это решается просто, но как это можно сделать в питоне?
    


Ответы

Ответ 1



Это оч. просто: In [439]: A.merge(B) Out[439]: А Б В 0 1 2 5 1 2 2 5 2 1 3 6 3 2 3 6 4 2 1 4 PS по умолчанию метод DataFrame.merge() объединяет таблицы (DataFrame'ы) по столбцам с совпадающими названиями. Также столбец(ы) для объединения можно указать явно, воспользовавшись параметрами: on left_on right_on Официальная документация о различных способах объединения данных в Pandas

Получить предпоследний заказ для клиента

#python #pandas #dataframe #group_by


У меня есть dataframe с некоторым количеством заказов, id клиента и датой заказа.
Мне нужно посчитать последний выполненный заказ по клиенту для каждой строки

Я попробовал вытащить максимальное значение id заказа для клиента, но не могу сообразить
как ограничить по дате.

import pandas as pd
data=pd.DataFrame({'ID': [ 133853.0,155755.0,149331.0,337270.0,
  775727.0,200868.0,138453.0,738497.0,666802.0,697070.0,128148.0,1042225.0,
  303441.0,940515.0,143548.0],
 'CLIENT':[ 235632.0,231562.0,235632.0,231562.0,734243.0,
   235632.0,235632.0,734243.0,231562.0,734243.0,235632.0,734243.0,231562.0,
   734243.0,235632.0],
 'DATE_START': [ ('2017-09-01 00:00:00'),
   ('2017-10-05 00:00:00'),('2017-09-26 00:00:00'),
   ('2018-03-23 00:00:00'),('2018-12-21 00:00:00'),
   ('2017-11-23 00:00:00'),('2017-09-08 00:00:00'),
   ('2018-12-12 00:00:00'),('2018-11-21 00:00:00'),
   ('2018-12-01 00:00:00'),('2017-08-22 00:00:00'),
   ('2019-02-06 00:00:00'),('2018-02-20 00:00:00'),
   ('2019-01-20 00:00:00'),('2017-09-17 00:00:00')]})
data.groupby('CLIENT').apply(lambda x:max(x['ID']))


В идеале нужно, чтобы было тоже количество строк в dataframe, и был еще столбец в
котором указано значение id заказа, который был последним перед текущим заказом.
    


Ответы

Ответ 1



Попробуйте так: data['prev_id']= data.sort_values('DATE_START').groupby('CLIENT')['ID'].transform(lambda x: x.shift()) Или так: data['prev_id']= data.sort_values('DATE_START').groupby('CLIENT').shift()['ID']

Особенности использования условий в DataFrame

#python #pandas #dataframe #условия


Есть DataFrame, в котором надо заполнить col3 данными из col2 по условию:

mask = ((df['col3'].isnull()) & (df['col1'] == 2))


 col1   col2    col3
0   2   2   NaN
1   3   1   NaN
2   2   1   NaN
3   3   1   NaN
4   2   2   NaN


Вывожу данные, которые должны быть изменены в col3:

mask = ((df['col3'].isnull()) & (df['col1'] == 2))
df.loc[mask]

 col1   col2 col3
0   2   2   NaN
2   2   1   NaN
4   2   2   NaN


Выполняю заполнение:

df.loc[mask, 'col3'] = df['col2']
df


Проверяю результат:

df
 col1   col2 col3
0   2   2   2.0
1   3   1   NaN
2   2   1   1.0
3   3   1   NaN
4   2   2   2.0


Все ОК, но на большом объеме данных так не проверишь.

Повторно использую для этого маску:

df.loc[mask]

 col1 col2  col3
0   2   2   2.0
2   2   1   1.0
4   2   2   2.0


Ожидал, что будет пустой список, т.к. col3 заполнена данными, а в маске существует
условие df['col3'].isnull() - выводить только незаполненные.

Почему так произошло и в чем я ошибся?
    


Ответы

Ответ 1



Логическая ошибка в том, что переменная mask была создана до заполнения col3. In [12]: df Out[12]: col1 col2 col3 0 2 2 2.0 1 3 1 NaN 2 2 1 1.0 3 3 1 NaN 4 2 2 2.0 Создаем логическую маску после обновления: In [13]: mask = ((df['col3'].isna()) & (df['col1'] == 2)) и получаем пустой DataFrame: In [14]: df.loc[mask] Out[14]: Empty DataFrame Columns: [col1, col2, col3] Index: [] PS методы .isnull() / .notnull() являются устаревшими, лучше использовать .isna() / .notna().

суббота, 21 марта 2020 г.

Конвертация pd.Series в pd.Dataframe определенного формата

#python #python_3x #pandas #dataframe #pivot


Существует одномерный массив b

b = pd.Series(
[110.0, 120.0, Horsepower]
[150.0, 175.0, Horsepower]
[1351.0, 1601.0, Capacity]
[12.0, 14.0, Metric Tons]
[1601.0, 1751.0, Capacity])
Name: fiProductClassDesc, dtype: object



Первая цифра списка - минимальное значение
Вторая цифра списка - максимальное значение
Третье значение - название категории (всего 4 шт.)


Необходимо создать из него a = pd.Dataframe, всего 8 колонок, где для каждой строки,
значения будут присвоены только тем колонкам, для которых совпадает название категории
и лэйбла колонки. Остальные 0. 

Digging Depth_min   Digging Depth_max   Metric Tons_min Metric Tons_max Horsepower_min
 Horsepower_max  Capacity_min    Capacity_max
0   0   0   0   110 120 0   0
0   0   0   0   150 175 0   0
0   0   0   0   0   0   1351    1601
0   0   12  14  0   0   0   0
0   0   0   0   0   0   1601    1751

    


Ответы

Ответ 1



Я бы делал это так: x = pd.DataFrame(b.to_list()).rename(columns={0: "min", 1: "max"}) res = x.pivot_table(index=x.index, columns=2, fill_value=0).swaplevel(axis=1) res.columns = res.columns.map("_".join) res = res.sort_index(axis=1, ascending=False) результат: In [115]: res Out[115]: Metric Tons_min Metric Tons_max Horsepower_min Horsepower_max Capacity_min Capacity_max 0 0 0 110 120 0 0 1 0 0 150 175 0 0 2 0 0 0 0 1351 1601 3 12 14 0 0 0 0 4 0 0 0 0 1601 1751 PS думаю добавить нулевые столбцы Digging Depth_min и Digging Depth_max проблем не составит пошаговое решение: In [116]: pd.DataFrame(b.to_list()).rename(columns={0: "min", 1: "max"}) Out[116]: min max 2 0 110.0 120.0 Horsepower 1 150.0 175.0 Horsepower 2 1351.0 1601.0 Capacity 3 12.0 14.0 Metric Tons 4 1601.0 1751.0 Capacity In [117]: x.pivot_table(index=x.index, columns=2, fill_value=0).swaplevel(axis=1) Out[117]: 2 Capacity Horsepower Metric Tons Capacity Horsepower Metric Tons max max max min min min 0 0 120 0 0 110 0 1 0 175 0 0 150 0 2 1601 0 0 1351 0 0 3 0 0 14 0 0 12 4 1751 0 0 1601 0 0 In [120]: res Out[120]: Capacity_max Horsepower_max Metric Tons_max Capacity_min Horsepower_min Metric Tons_min 0 0 120 0 0 110 0 1 0 175 0 0 150 0 2 1601 0 0 1351 0 0 3 0 0 14 0 0 12 4 1751 0 0 1601 0 0 In [121]: res.sort_index(axis=1, ascending=False) Out[121]: Metric Tons_min Metric Tons_max Horsepower_min Horsepower_max Capacity_min Capacity_max 0 0 0 110 120 0 0 1 0 0 150 175 0 0 2 0 0 0 0 1351 1601 3 12 14 0 0 0 0 4 0 0 0 0 1601 1751

Ошибка Python Pandas - The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all()

#python #pandas


Жестко затупил на контрольном задании на курсе ЯндексПрактикум "Аналитик данных"

Дана таблица:

df = pd.read_csv('/datasets/music_project.csv')


Задание:

Утро понедельника и вечер пятницы — разная музыка или одна и та же?

Ищем ответ на вопрос, какие жанры преобладают в разных городах в понедельник утром
и в пятницу вечером. Есть предположение, что в понедельник утром пользователи слушают
больше бодрящей музыки (например, жанра поп), а вечером пятницы — больше танцевальных
(например, электронику).

Получим таблицы данных по Москве moscow_general и по Санкт-Петербургу spb_general.

# получение таблицы moscow_general из тех строк таблицы df, 
# для которых значение в столбце 'city' равно 'Moscow'
moscow_general = df[df['city'] == 'Moscow']


# получение таблицы spb_general
# для которых значение в столбце 'city' равно 'Saint-Petersbur'
spb_general = df[df['city'] == 'Saint-Petersburg']


Создаём функцию genre_weekday(), которая возвращает список жанров по запрошенному
дню недели и времени суток с такого-то часа по такой-то.

def genre_weekday(df, day, time1, time2):
    genre_list =  df[ (df['weekday'] == day) & (df['time']>time1) & (time2>df['time'])]
    genre_list_sorted = genre_list.groupby('genre_name')['genre_name'].count().sort_values(ascending
= False).head(10) 
    return genre_list_sorted

# объявление функции genre_weekday() с параметрами df, day, time1, time2

# в переменной genre_list сохраняются те строки df, для которых одновременно:
# 1) значение в столбце 'weekday' равно параметру day,
# 2) значение в столбце 'time' больше time1 и
# 3) меньше time2.

# в переменной genre_list_sorted сохраняются в порядке убывания  
# первые 10 значений Series, полученной подсчётом числа значений 'genre_name'
# сгруппированной по столбцу 'genre_name' таблицы genre_list

# функция возвращает значение genre_list_sorted


Cравниваем полученные результаты по таблице для Москвы и Санкт-Петербурга в понедельник
утром (с 7 до 11) и в пятницу вечером (с 17 до 23).

Утро понедельника в Москве

# <вызов функции для утра понедельника в Москве (вместо df таблица moscow_general)>
genre_weekday(moscow_general, 'Monday', '07:00:00', '11:00:00')


Результат:

genre_name
pop            781
dance          549
electronic     480
rock           474
hiphop         286
ruspop         186
world          181
rusrap         175
alternative    164
classical      157
Name: genre_name, dtype: int64


Утро понедельника в СПб

# <вызов функции для утра понедельника в Петербурге (вместо df таблица spb_general)>
genre_weekday(spb_general, 'Monday', '07:00:00', '11:00:00')


Результат:

genre_name
pop            218
dance          182
rock           162
electronic     147
hiphop          80
ruspop          64
alternative     58
rusrap          55
jazz            44
classical       40
Name: genre_name, dtype: int64


Вечер пятницы в Москве

# <вызов функции для вечера пятницы в Москве>
genre_weekday(moscow_general, 'Friday', '17:00:00', '23:00:00')


Результат:

genre_name
pop            713
rock           517
dance          495
electronic     482
hiphop         273
world          208
ruspop         170
alternative    163
classical      163
rusrap         142
Name: genre_name, dtype: int64


Вечер пятницы в СПб

# <вызов функции для вечера пятницы в Питере>
genre_weekday(spb_general, 'Friday', '17:00:00', '23:00:00')


Результат:

genre_name
pop            256
rock           216
electronic     216
dance          210
hiphop          97
alternative     63
jazz            61
classical       60
rusrap          59
world           54
Name: genre_name, dtype: int64


Популярные жанры в понедельник утром в Питере и Москве оказались похожи: везде, как
и предполагалось, популярен поп. Несмотря на это, концовка топ-10 для двух городов
различается: в Питере в топ-10 входит джаз и русский рэп, а в Москве жанр world.

В конце недели ситуация не меняется. Поп-музыка всё так же на первом месте. Опять
разница заметна только в концовке топ-10, где в Питере пятничным вечером тоже присутствует
жанр world

Конец задания

Вроде все сходится с написанными Яндексом подсказками и выводами, но при сдаче задания
на проверку дает ошибку The truth value of a Series is ambiguous. Use a.empty, a.bool(),
a.item(), a.any() or a.all().

Суть ошибки вроде бы понял, но не понимаю в какой момент она возникает.

Если это может помочь, ссылка на диск со всеми заданиями. cell In [48]:
https://yadi.sk/d/xO0cm83NXVyPJA
    


Ответы

Ответ 1



Возможно, проблема в этой строке: genre_list = df[ (df['weekday'] == day) & (df['time']>time1) & (time2>df['time'])] Попробуйте заменить на какой-нибудь из этих вариантов: genre_list = df.query('weekday == @day and @time2 > time > @time1') genre_list = df.loc[(df['weekday'] == day) & (df['time'].between(time1, time2, inclusive=False))]

Ответ 2



У меня валидатор принял такой вариант: genre_list = df[ (df['weekday'] == day) & (df['time'] > time1) & (df['time'] < time2)] возможно ему важно в каком порядке идут сравниваемые величины..

Группировка кол-ва выполненных задач по сотрудникам

#python #python_3x #pandas #dataframe #group_by


Как сгруппировать корректно данные? 

Имеется датафрейм со статусом завершенных заданий по каждому аналитику и типу задач:

df1

    ID     Board   Analyst   Status   Crea_d       Fin_d
    46258  RUCRA   Ivanov    open     2019-07-10    NaT
    2345   RUCRA   Ivanov    close    2019-07-11   2019-07-11
    46218  RUCRA   Ivanov    close    2019-07-11   2019-07-11
    3087   RUCRA   Sidorov   open     2019-07-22    NaT
    2367   BV      Petrov    open     2019-07-25    NaT
    2985   GRADE   Petrov    close    2019-07-05   2019-07-05 
    20987  GRADE   Ivanov    close    2019-07-11   2019-07-12
    2396   BV      Sidorov   open     2019-07-29     NaT


Необходимо сгруппировать данные таким образом, чтобы было видно сколько аналитик
выполнил и сколько еще невыполненных заданий по типам (Board) за определенный период
(за день, неделю, месяц).

grouped_df:

      Board   Analyst   Status   Count       
      RUCRA   Ivanov    open     1    
      RUCRA   Ivanov    close    2   
      RUCRA   Sidorov   open     1    
      BV      Petrov    open     1    
      GRADE   Petrov    close    1    
      GRADE   Ivanov    close    1
      BV      Sidorov   open     1     


Я что-то похожее сделал, но где-то нарушена логика, где не могу разобраться:

grouped_df: = (df1.groupby(['Board','Analyst','Status', pd.Grouper(key='Fin_d', freq='M')],
as_index=False)['ID'].count())


Просто дальше я хочу строить графики по каждому аналитику, сколько он по дням выполняет
заданий (bars) с трендовой линией, но то ли из-за ошибки в коде или нарушения логики,
ничего не выходит.
    


Ответы

Ответ 1



Если я правильно понял: In [5]: df1.groupby(["Board", "Analyst", "Status"]).size().reset_index(name="Count") Out[5]: Board Analyst Status Count 0 BV Petrov open 1 1 BV Sidorov open 1 2 GRADE Ivanov close 1 3 GRADE Petrov close 1 4 RUCRA Ivanov close 2 5 RUCRA Ivanov open 1 6 RUCRA Sidorov open 1 или так: In [11]: df1.groupby(["Board", "Analyst", "Status", pd.Grouper(key='Crea_d', freq='MS')]).size().reset_index(name="Count") Out[11]: Board Analyst Status Crea_d Count 0 BV Petrov open 2019-07-01 1 1 BV Sidorov open 2019-07-01 1 2 GRADE Ivanov close 2019-07-01 1 3 GRADE Petrov close 2019-07-01 1 4 RUCRA Ivanov close 2019-07-01 2 5 RUCRA Ivanov open 2019-07-01 1 6 RUCRA Sidorov open 2019-07-01 1

Трансформация DataFrame

#python #pandas #dataframe #group_by #статистика


Есть 2 pd.DataFrame:

a = pd.DataFrame([[1, 20], [2, 25], [3, 24], [1, 22], [2, 29]], columns=['type', 'size'])
b = pd.DataFrame([[1, 19], [1, 21], [2, 24], [4, 21]], columns=['type', 'size'])


В каждый DataFrame хочу добавить столбцы следующего типа

a['amount_mean_type'] = a['size'] / a.groupby('type')['size'].transform('mean')
a['amount_std_type'] = a['size'] / a.groupby('type')['size'].transform('std')


Вопрос в том, как мне сделать так, чтобы в b['amount_mean_type'] и b['amount_std_type']
я использовал mean и std по группам из a, а по тем категориям, которых нет в a, использовать
mean и std по всему сету (если это корректно). 

Что-то вроде этого: 

b['amount_mean_type'] = b['size'] / a.groupby('type')['size'].transform('mean')
b['amount_std_type'] = b['size'] / a.groupby('type')['size'].transform('std')


Но только с теми условиями, которые описал выше

UPD: пример фреймов на выходе

Для a все просто:

a['amount_mean_type'] = a['size'] / a.groupby('type')['size'].transform('mean')
a['amount_std_type'] = a['size'] / a.groupby('type')['size'].transform('std')

  type size amount_mean_type amount_std_type
0   1   20  0.952381    14.142136
1   2   25  0.925926    8.838835
2   3   24  1.000000    NaN 
3   1   22  1.047619    15.556349
4   2   29  1.074074    10.253048


для b приходится прописать вручную каждую операцию

b.loc[0, 'amount_mean_type'] = b.loc[0, 'size'] / a[a['type'] == 1]['size'].mean()
b.loc[1, 'amount_mean_type'] = b.loc[1, 'size'] / a[a['type'] == 1]['size'].mean()
b.loc[2, 'amount_mean_type'] = b.loc[2, 'size'] / a[a['type'] == 2]['size'].mean()
b.loc[3, 'amount_mean_type'] = b.loc[3, 'size'] / a['size'].mean()

b.loc[0, 'amount_std_type'] = b.loc[0, 'size'] / a[a['type'] == 1]['size'].std()
b.loc[1, 'amount_std_type'] = b.loc[1, 'size'] / a[a['type'] == 1]['size'].std()
b.loc[2, 'amount_std_type'] = b.loc[2, 'size'] / a[a['type'] == 2]['size'].std()
b.loc[3, 'amount_std_type'] = b.loc[3, 'size'] / a['size'].std()

  type size amount_mean_type amount_std_type
0   1   19  0.904762    13.435029
1   1   21  1.000000    14.849242
2   2   24  0.888889    8.485281
3   4   21  0.875000    6.192562 # Считается по всей переменной 'type', так как категории
(4) нет в `a`


Фреймы a и b можно рассматривать как train и test соответственно
    


Ответы

Ответ 1



tmp = a.groupby('type')['size'].agg(["mean", "std"]) res = (b.assign(x=b["type"].map(tmp["mean"]).fillna(a["size"].mean())) .eval("amount_mean_type = size / x") .drop(columns="x")) res = (res.assign(x=b["type"].map(tmp["std"]).fillna(a["size"].std())) .eval("amount_std_type = size / x") .drop(columns="x")) результат: In [28]: res Out[28]: type size amount_mean_type amount_std_type 0 1 19 0.904762 13.435029 1 1 21 1.000000 14.849242 2 2 24 0.888889 8.485281 3 4 21 0.875000 6.192562

Как удалить столбцы, у которых кол-во пропущенных значений больше 2 согласно прилагаемого алгоритма

#python #pandas #dataframe


Алгоритм удаления по заданию следующий:


найдите все такие столбцы (метод .isna() + подвыборка с условием)
определите их названия (поймите как выцепить названия и сохраните их в массив, т.е.
по цепочке примените методы .index, .tolist() или .values)
"дропните их" (используйте метод .drop (имена столбцов))
результат сохраните в новой табличке (например, data_1), исходную менять не нужно


Сделала по-другому:

cols_to_delete = df2.columns[df2.isna().sum() > 2]
df2.drop(cols_to_delete, axis = 1, inplace = True)


Что мне непонятно: как сделать задание по вышеуказанному алгоритму #1 - #4.

df = pd.DataFrame({
    'col1': [23, 54, pd.np.nan, 87],
    'col2': [45, 39, 45, 32],
    'col3': [pd.np.nan, pd.np.nan, 76, pd.np.nan,]
})

    


Ответы

Ответ 1



Исходный DF: In [92]: df Out[92]: col1 col2 col3 0 23.0 45 NaN 1 54.0 39 NaN 2 NaN 45 76.0 3 87.0 32 NaN Решение 1: In [93]: thresh = 2 In [94]: new = df.loc[:, df.isna().sum().le(thresh)] Решение 2: In [96]: new = df.drop(columns=df.columns[df.isna().sum() > thresh]) Результат: In [95]: new Out[95]: col1 col2 0 23.0 45 1 54.0 39 2 NaN 45 3 87.0 32

пятница, 20 марта 2020 г.

Работа с именованными объектами

#python #pandas #numpy


Для решения задачи комивояжера использую массивы из библиотеки NumPy:

    mat = np.array([[-1., 10., 25., 25., 10.],
                    [1., -1, 10., 15., 2.],
                    [8., 9., -1., 20., 10.],
                    [14., 10., 24., -1., 15.],
                    [10., 8., 25., 27., -1.]])


Столбцы и строки представляют собой именованные точки (города). Алгоритм работы предполагает
периодическое удаление некоторых строк и столбцов. При этом теряется информация об
оставшихся именованных столбцах и строках.
Приходится параллельно вести два вектора (по столбцам и строкам), к которым применяются
аналогичные операции удаления.

Есть ли возможность использовать преимущества библиотеки NumPy (работа с массивами)
и возможности DataFrame из Pandas по ведению именованных столбцов и строк?
    


Ответы

Ответ 1



Собственно Pandas DataFrame и есть набор именованных Numpy векторов (столбцы таблицы). Кроме этого у DataFrame есть индекс - метка или имя каждой строки. Таким образом Pandas DataFrame обеспечивает удобное индексирование как по строкам так и по столбцам. Большинство алгоритмов и функций умеющих работать с Numpy матрицами могут напрямую работать с Pandas DataFrame. Приходится параллельно вести два вектора (по столбцам и строкам), к которым применяются аналогичные операции удаления. Pandas делает это за вас автоматически. Если вам нужен доступ к меткам / именам строк или столбцов то воспользуйтесь атрибутами: df.index или df.columns соответственно.

воскресенье, 1 марта 2020 г.

почему появляется столбец 'Unnamed'

#python #pandas #dataframe #csv


я создал датафрейм , в нём 3 колнки. Перегоняю его в файл. Читаю данные с файла и
вижу новый столбец 'Unnamed' . Всё бы ничего , но я не могу его удалить , вылетает ошибка:

ValueError: labels ['Unnamed'] not contained in axis


откуда вообще он взялся и что с ним делать ?
    


Ответы

Ответ 1



Скорее всего вы сохранили CSV файл с индексом (по умполчанию). Как это проверить: In [31]: df.columns.tolist() Out[31]: ['Unnamed: 0', 'a', 'b', 'c'] Пример: In [16]: df = pd.DataFrame(np.arange(1,10).reshape(3,3), columns=list('abc')) In [17]: df Out[17]: a b c 0 1 2 3 1 4 5 6 2 7 8 9 In [18]: df.to_csv(r'c:/temp/test.csv') теперь если просто прочитать его, то получим столбец Unnamed: 0 (т.к. индекс был безымянным): In [20]: x = pd.read_csv(r'c:/temp/test.csv') In [21]: x Out[21]: Unnamed: 0 a b c 0 0 1 2 3 1 1 4 5 6 2 2 7 8 9 вот как это выглядит в CSV файле: In [22]: print(Path(r'c:/temp/test.csv').read_text()) ,a,b,c 0,1,2,3 1,4,5,6 2,7,8,9 Как это обойти: In [23]: x = pd.read_csv(r'c:/temp/test.csv', index_col=0) In [24]: x Out[24]: a b c 0 1 2 3 1 4 5 6 2 7 8 9 или сохранять DataFrame без индекса: In [25]: df.to_csv(r'c:/temp/test.csv', index=False) In [26]: print(Path(r'c:/temp/test.csv').read_text()) a,b,c 1,2,3 4,5,6 7,8,9 In [27]: pd.read_csv(r'c:/temp/test.csv') Out[27]: a b c 0 1 2 3 1 4 5 6 2 7 8 9

Случайный лес и бэггинг деревьев решений

#python #pandas #машинное_обучение #dataframe #numpy


Запрограммировала случайный лес и бэггинг деревьев решений. 

Что-то видимо не правильно потому, что процент несовпадений выдает одинаковое число
для трех методов, и при изменении выборки ничего не происходит.

Как правильно должна выглядеть программа? Надо ли отдельно реализовать бэггинг и
деревья решений?

Код:

 import numpy as np
 import pandas as pd
 from sklearn.model_selection import cross_val_score
 from sklearn.cross_validation import train_test_split
 from sklearn.ensemble.forest import RandomForestClassifier
 from sklearn.ensemble import BaggingClassifier
 from sklearn.tree import DecisionTreeClassifier
data = pd.read_csv('C:\\Users\\Vika\\Downloads\\1500.csv', ";",decimal =',', skipinitialspace=True)
 data.head()
 kfold = 10
 itog_val1 = {} 
 itog_val2 = {} 
 itog_val3 = {} 
 itog_val4 = {} 
 itog_val5 = {} 
 itog_val6 = {}
 X = data.drop('Y1', axis=1).values[:, :8] 
 y = data['Y1'].values
 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
 print ('обучающая выборка X:\n', X_train[:6])
 print ('\n')
 print ('y_train У:\n', y_train[:10])
 print (' \n')
 print ('тестовая выборка Х:\n', X_test[:6])
 print ('\n')
 print ('y_test У\n', y_test[:10])
 first_tree = RandomForestClassifier(n_estimators=100)  
 scores = cross_val_score(first_tree, X_train, y_train, cv=kfold) 
 itog_val1 = scores 
 print(itog_val1)  
 first_tree1 = DecisionTreeClassifier(max_depth=1)    
 scores = cross_val_score(first_tree, X_train, y_train, cv=kfold)
 itog_val4 = scores 
 print(itog_val4)
 first_tree.fit(X_train, y_train) 
 first_tree.score(X_test, y_test)
 y_test_predicted = first_tree.predict(X_test) 
 print ('RandomForestClassifier X\n', X_test[:9])
 print ('\n')
 print ('RandomForestClassifier y\n', y_test[:11]) 
 first_tree1.fit(X_train, y_train)
 first_tree1.score(X_test, y_test)
 y_test_predicted = first_tree1.predict(X_test)
 print ('DecisionTreeClassifier X\n', X_test[:9])
 print ('\n')
 print (' DecisionTreeClassifier y\n', y_test[:11])
 first_bagging.fit(X_train, y_train)
 first_bagging.score(X_test, y_test)
 y_test_predicted = first_bagging.predict(X_test)
 print ('BaggingClassifier X\n', X_test[:9])
 print ('\n')
 print (' BaggingClassifier y\n', y_test[:11])
 res = pd.DataFrame(np.column_stack((y_test, y_test_predicted, X_test)), 
               columns=['Y1','YR'] + data.columns[1:9].tolist())
 (res['Y1']!= res['YR']).mean()
 res1 = pd.DataFrame(np.column_stack((y_test, y_test_predicted, X_test)), 
               columns=['Y1','YD'] + data.columns[1:9].tolist())
 (res1['Y1']!= res1['YD']).mean() 
 res2 = pd.DataFrame(np.column_stack((y_test, y_test_predicted, X_test)), 
               columns=['Y1','YB'] + data.columns[1:9].tolist())
 (res2['Y1']!= res2['YB']).mean() 

    


Ответы

Ответ 1



Вы создали три DataFrame из одних и тех же данных: res = pd.DataFrame(np.column_stack((y_test, y_test_predicted, X_test)), columns=['Y1','YR'] + data.columns[1:9].tolist()) ... res1 = pd.DataFrame(np.column_stack((y_test, y_test_predicted, X_test)), columns=['Y1','YD'] + data.columns[1:9].tolist()) ... res2 = pd.DataFrame(np.column_stack((y_test, y_test_predicted, X_test)), columns=['Y1','YB'] + data.columns[1:9].tolist()) как следствие процент несовпадений - одинаковый

Как преобразовать логические False, True в 1, 0?

#python #python_3x #pandas #dataframe #numpy


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

Только мне нужно, чтобы False -> 1, а True -> 0.
В принципе можно и replace использовать, но хочется найти более красивый способ.
    


Ответы

Ответ 1



Пример: Исходный DataFrame: In [19]: df = pd.DataFrame({'col':np.random.choice([True, False], 10)}) In [20]: df Out[20]: col 0 False 1 True 2 True 3 False 4 False 5 True 6 False 7 False 8 True 9 False решение: In [22]: df['col'] = (-df['col']).astype(np.int8) In [23]: df Out[23]: col 0 1 1 0 2 0 3 1 4 1 5 0 6 1 7 1 8 0 9 1 In [24]: df.dtypes Out[24]: col int8 dtype: object альтернативный вариант: In [27]: df['col'] = (~df['col']).astype(np.uint8) In [28]: df Out[28]: col 0 1 1 0 2 0 3 1 4 1 5 0 6 1 7 1 8 0 9 1

среда, 26 февраля 2020 г.

Как получить данные колонки индексов Pandas DataFrame?

#python #pandas #dataframe #matplotlib


Считываю данные:

data = pd.read_csv('data.csv',';', index_col=['month'], parse_dates=['month'], dayfirst=True)


Смотрю на них:

print data.shape
print data.columns
data.head()


Вывод:

(168, 1)
Index([u'milk'], dtype='object')


   month    milk
1962-01-01  589
1962-02-01  561
1962-03-01  640
1962-04-01  656
1962-05-01  727


В какой-то момент мне необходимо построить график количества во времени. Каким образом
получить данные колонки индексов (month)? Напомню, что мы ее указали индексом и в данных
у нас только одна колонка с количеством. Конечно, можно отобразить как data.plot(),
но мне хотелось бы сделать это вызвав plot у matplotlib.

Дополнительно вопрос о лучших практиках: в каких случаях обоснованно / следует использовать
данные в качестве индекса?
    


Ответы

Ответ 1



Судя по выводу data.head(), вы либо не указали параметр index_col=['month'] либо он отработал не так как ожидалось и столбец month оказался обычным столбцом, вместо того чтобы стать индексом. Чтобы получить значения индекса DataFrame'а, достаточно воспользоваться атрибутом DataFrame.index. Пример: In [129]: df = pd.DataFrame({'val':np.random.rand(100)}, index=np.arange(100, 200)) In [130]: df Out[130]: val 100 0.924396 101 0.960312 102 0.728403 103 0.435330 104 0.599777 .. ... 195 0.055345 196 0.560087 197 0.049506 198 0.819265 199 0.231141 [100 rows x 1 columns] In [131]: plt.plot(df.index, df['val']) Out[131]: [] UPDATE: если на оси X - дата/время, то проще воспользоваться Pandas для визуализации: In [154]: df = pd.read_csv(r'C:\download\data.csv', sep=';', parse_dates=True, index_col=0) In [155]: df Out[155]: milk month 1962-01-01 589 1962-02-01 561 1962-03-01 640 1962-04-01 656 1962-05-01 727 In [156]: df.plot(y='milk') Out[156]: Значения индекса DataFrame: In [157]: df.index Out[157]: DatetimeIndex(['1962-01-01', '1962-02-01', '1962-03-01', '1962-04-01', '1962-05-01'], dtype='datetime64[ns]', name='month', freq=None)

Ошибка: TypeError: fit() missing 1 required positional argument: 'y'

#python #pandas #машинное_обучение #numpy #scikit_learn


Я пытаюсь сделать алгоритм на python, определяющий написанные от руки английские
буквы, но при попытке обучения появляется ошибка.
Мой код:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier as knc

abc_train = pd.read_csv("alphabet.csv")

columns = ["let"]
for i in range(784):
    columns.append(f"px_{i+1}")
abc_train.columns = columns
label_name = abc_train["let"].values
let_train = abc_train.values[:, 1:]
pict_train = let_train.reshape(372450 , 28, 28)
knc = knc.fit( pict_train, label_name)


Ошибка:

TypeError                                 Traceback (most recent call last)
 in 
----> 1 knc = knc.fit( pict_train[1:14325], label_name)

TypeError: fit() missing 1 required positional argument: 'y'


Что я делаю не так? Как я могу решить эту проблему / ошибку ?
Может ли это быть из-за того, что в датасете не указан верный вывод?
    


Ответы

Ответ 1



Ошибка в том, что вы не создали объект класса KNeighborsClassifier, а использовали метод класса KNeighborsClassifier.fit(). Попробуйте так: from sklearn.neighbors import KNeighborsClassifier knc = KNeighborsClassifier(n_neighbors=5) ... knc.fit(pict_train, label_name) PS @gil9red отлично дополнил ответ в комментарии: в питоне у методов объекта есть первый, неочевидный параметр self, в который кладется ссылка на объект, что метод вызвал и в случае вызова метода классом (а не объектом), в тот параметр self попал объект pict_train, а label_name, соответственно, попал в X, поэтому и ругается на y?