Как я могу применить пользовательскую функцию строки ко всем строкам загруженного в массив? - PullRequest
0 голосов
/ 16 апреля 2019

Я написал пользовательскую функцию, которая перебирает ряд значений, чтобы определить количество нулей между значениями (расстояние между значениями). Эти расстояния добавляются в список и затем усредняются для получения окончательного значения среднего расстояния между значениями. Функция прекрасно работает, когда я загружаю в файл CSV только одну строку значений. Однако я хотел бы иметь возможность применить функцию к файлу с несколькими строками, а затем сообщить о выходе каждой строки в фрейм данных.

Это все работает с python 3.7. Я попытался создать вложенный цикл, чтобы применить функцию вручную. Я попробовал функцию numpy.apply_along_axis. Я также попытался прочитать файл в качестве pandas dataframe, а затем с помощью функции .apply (). Тем не менее, я немного незнаком с пандами, и когда я заменил цифровую индексацию в функции на индексирование панд, я начал генерировать несколько ошибок.

Когда я загружаю файл CSV большего размера и пытаюсь применить его к файлу [0], например, функция не работает. Кажется, это работает, только когда я загружаю в файл с одной строкой значений.

def avg_dist():
     import statistics as st


    dist = []
    ctr=0

#distances between events

    for i in range(len(n)):
        if n[i] > 0 and i < (len(n)-1):
            if n[i+1]==0:
                i+=1
                while n[i]==0 and i < (len(n)-1):
                    ctr+=1
                    i+=1
                dist.append(ctr)
                ctr=0
            else:
                i+=1
        else:
            i+=1


#Average distance between events
    aved = st.mean(dist)
    return(aved)

1 Ответ

0 голосов
/ 16 апреля 2019

Последний ответ находится в конце ответа.Было несколько исправлений.

В самом конце (4-е редактирование) ответа есть совершенно новый подход.

Я не уверен, что вы пытаетесь сделать, но, надеюсь, это можетhelp.

import numpy as np

# Generate some events
events = np.random.rand(3,12)*10.
events *= np.random.randint(5, size=(3,12))<1
events
Out[36]:
array([[ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  5.35598205,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ],
       [ 0.        ,  6.65094145,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  6.04581361],
       [ 6.88119682,  4.31178109,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  1.16999289,  0.        ,  0.        ,
         0.        ,  0.        ]])

# generate a boolean array of events.  (as int for a compact print.)
an_event = (events != 0).astype(np.int)
n_event

Out[37]:
array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
       [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
       [1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]])

def event_range(arr):
    from_start = arr.cumsum(axis=1)
    from_end = np.flip(arr, axis=1).cumsum(axis=1)
    from_end = np.flip(from_end, axis=1)
    return np.logical_and(from_start, from_end).astype(np.int)

Функция event_range шаг за шагом.
from_start - это сумма an_event.ноль до любого события,> 0 после этого.

from_start = an_event.cumsum(axis=1) # cumsum the event count.  zeros before the first event.
from_start
Out[40]:
array([[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1],  # zeroes before the first event.
       [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
       [1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3]], dtype=int32)

from_end является суммой an_event, но с макс. До мин.Следовательно, ноль после последнего события.

from_end = np.flip(an_event, axis=1).cumsum(axis=1) # cumsum of reversed arrays
from_end = np.flip(from_end, axis=1) # reverse the result.
from_end
Out[41]:
array([[1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], # zero after the last event.
       [2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [3, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]], dtype=int32)

логически и объединение их вместе, чтобы получить, нули до первого события, единицы после этого и нули после последнего события.

ev_range = np.logical_and(from_start, from_end).astype(np.int)
ev_range
Out[42]:
# zero before first and after last event, one between the events.
array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 
       [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],  
       [1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]])

n_range = ev_range.sum(axis=1)
n_range
Out[43]: array([ 1, 11,  8])

n_events = an_event.sum(axis=1)
n_events
Out[44]: array([1, 2, 3])

avg = n_range / n_events
avg
Out[45]: array([ 1.        ,  5.5       ,  2.66666667])

Должен avgбыть n_range / (n_events-1)?то есть посчитайте промежутки, а не события.

Что вы ожидаете только для одного события подряд?Что за нулевые события в строке?

Редактировать следующие комментарии

Для подсчета промежутков длиннее нуля требуется немного времени.Самым простым является, вероятно, взять различия для последовательных столбцов.Если это -1, то за 1 следует ноль.Вам нужно добавить окончательный нулевой столбец к вашим данным, если в последнем столбце есть событие.

np.random.seed(10)

test = 1*(np.random.randint(4, size=(4,12))<1)

test
Out[24]: 
array([[0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0],
       [0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1],
       [0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]])

temp = np.diff(test, axis=-1)

temp
Out[26]: 
array([[ 0,  1, -1,  1, -1,  0,  1, -1,  0,  1, -1],
       [ 0,  1, -1,  1, -1,  1, -1,  1, -1,  1,  0],
       [ 0,  0,  1, -1,  0,  0,  0,  1,  0, -1,  0],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  1, -1,  0]])

np.where(temp<0, 1,0)
Out[28]: 
array([[0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1],
       [0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0],
       [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]])

In [29]: np.where(temp<0, 1,0).sum(axis=-1)-1
Out[29]: array([3, 3, 1, 0]) # should be [3, 4, 1, 0]

Добавить столбец нулей для проверки.

test = np.hstack((test, np.zeros((4,1), dtype = np.int)))
test 
Out[31]: 
array([[0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0],
       [0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0],
       [0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]])

temp=np.diff(test, axis=-1)

temp
Out[35]: 
array([[ 0,  1, -1,  1, -1,  0,  1, -1,  0,  1, -1,  0],
       [ 0,  1, -1,  1, -1,  1, -1,  1, -1,  1,  0, -1], # An extra -1 here.
       [ 0,  0,  1, -1,  0,  0,  0,  1,  0, -1,  0,  0],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  1, -1,  0,  0]])

np.where(temp<0, 1,0).sum(axis=-1)-1
Out[36]: array([3, 4, 1, 0])

Как ясказал, немного вовлечен.Может быть легче пройти через цикл, но это должно быть быстрее, если труднее понять.

2nd Edit, следуя другой идее.

import numpy as np

np.random.seed(10)
test = 1*(np.random.randint(4, size=(4,12))<1)
test

Out[2]: 
array([[0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0],
       [0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1],
       [0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]])

temp = np.diff(test, axis=-1)

np.where(temp<0, 1, 0).sum(axis=-1)+test[:,-1]-1
# +test[:,-1] adds the last column to include any 1's from there.
Out[4]: array([3, 4, 1, 0])

3rd Edit

Думая об этом, я создал 2 функции, я также показываю do_divide, который справляется с делением на ноль.

import numpy as np

def zero_after_last_event(arr):
    """
    Returns an array set to zero in all cells after the last event
    """
    from_end = np.flip(arr, axis=-1).cumsum(axis=-1) # cumsum of reversed arrays
    from_end = np.flip(from_end, axis=-1) # reverse the result.
    from_end[from_end>0] = 1  # gt zero set to 1
    return from_end

def event_range(arr):
    """ event_range is zero before the first event, 
        zero after the last event and 1 elsewhere. """
    return np.logical_and(arr.cumsum(axis=-1), zero_after_last_event(arr)).astype(np.int)

def do_divide(a, b):
    """ Does a protected divide.  Returns zero for divide by zero """
    with np.errstate(invalid='ignore'): # Catch divide by zero
        result = a / b
        result[~np.isfinite(result)] = 0.
    return result

Настройка тестового массива

np.random.seed(10)
events = 1*(np.random.randint(4, size=(4,12))<1)
events
Out[15]: 
array([[0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0],
       [0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1],
       [0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]])

С вышеприведенными функциями и данными это следует.

# Count gap lengths  
gaps = 1 - events # invert the values in events (1->0, 0->1) 
gaps = np.logical_and(gaps, event_range(events)).astype(np.int)
gaps
Out[19]: 
array([[0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0],
       [0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0],
       [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

sumgaps = gaps.sum(axis = -1)
sumgaps
Out[22]: array([5, 4, 4, 0])

# Count how many gaps
temp = np.diff(events, axis=-1) # temp is -1 when an event isn't immediately followed by another event.
n_gaps = np.where(temp<0, 1, 0).sum(axis=-1)+events[:,-1]-1
# +test[:,-1] adds the last column to include any 1's from there.
n_gaps
Out[23]: array([3, 4, 1, 0])

do_divide(sum_gaps, n_gaps)
Out[21]: array([1.66666667, 1.        , 4.        , 0.        ])

4-е редактирование - с использованием np.bincount

import numpy as np

def do_divide(a, b):
""" Does a protected divide.  Returns zero for divide by zero """
    with np.errstate(invalid='ignore'): # Catch divide by zero
        result = a / b
        result[~np.isfinite(result)] = 0.
        return result

np.random.seed(10)
events = 1*(np.random.randint(4, size=(4,12))<1)

cumulative = events.cumsum(axis=1)
cumulative
Out[2]: 
array([[0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4],
       [0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6],
       [0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 3, 3],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1]])

bin_count_len = 1+cumulative.max()  # Biggest bins length required.

result = np.zeros((cumulative.shape[0], bin_count_len), dtype=np.int)
for ix, row in enumerate(cumulative):
    result[ix] = np.bincount( row, minlength = bin_count_len )

result
Out[4]: 
array([[2, 2, 3, 3, 2, 0, 0],
       [2, 2, 2, 2, 2, 1, 1],
       [3, 5, 1, 3, 0, 0, 0],
       [9, 3, 0, 0, 0, 0, 0]])

Потерять столбец 0. Его перед любымСобытия.Потерять последний столбец, всегда после последнего события.Пробелы включают в себя событие открытия, -1 удаляет его из размера пробела.

temp = result[:, 1:-1]-1   # 
temp
Out[6]: 
array([[ 1,  2,  2,  1, -1],
       [ 1,  1,  1,  1,  0],
       [ 4,  0,  2, -1, -1],
       [ 2, -1, -1, -1, -1]])

Установите любую ячейку temp [r, n] = 0, если temp [r, n + 1] == 0

temp_lag = (result[:, 2:]>0)*1
temp_lag
Out[8]: 
array([[1, 1, 1, 0, 0],
       [1, 1, 1, 1, 1],
       [1, 1, 0, 0, 0],
       [0, 0, 0, 0, 0]])

temp *= temp_lag
temp
Out[10]: 
array([[1, 2, 2, 0, 0],
       [1, 1, 1, 1, 0],
       [4, 0, 0, 0, 0],
       [0, 0, 0, 0, 0]])

tot_gaps = temp.sum(axis=1)
n_gaps = np.count_nonzero(temp, axis=1)

tot_gaps, n_gaps
Out[13]: (array([5, 4, 4, 0]), array([3, 4, 1, 0]))

do_divide(tot_gaps, n_gaps)
Out[14]: array([1.66666667, 1.        , 4.        , 0.        ])

HTH

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...