Я пытаюсь прочитать данные из CSV, а затем обработать их по-другому. (Для начала просто средний)

Данные
(OneDrive) https://1drv.ms/u/s!ArLDiUd0teU5 ? e = 6wlpko

Данные выглядят так:
ID; Property1; Property2; Свойство 3 ...
1; ....
1; ...
1; ...
2; ...
2; ...
3; ...
...

Каждая линия - это точка GPS. Все точки с одинаковым идентификатором вместе (например, 1) создают один Маршрут. Маршруты не одинаковой длины, и некоторые идентификаторы пропускаются. Так что это не плавный рост числа.

Мне может потребоваться добавить, что точки ВСЕГДА находятся на одном и том же наборе метров друг от друга. И в настоящее время мне не нужна информация о XY.

Требуемый результат
В итоге я хочу что-то вроде этого: [ID, AVG_Property1, AVG_Property2 ...] [1, 1.00595, 2.9595, ...] [2,1.50606, 1.5959, ...]

Что я получил на данный момент

import os
import numpy
import pandas as pd
data = pd.read_csv(os.path.join('C:\\data' ,'data.csv'), sep=';')
# [id, len, prop1, prop2, ...]
routes = numpy.zeros((data.size, 10)) # 10 properties

sums = numpy.zeros(8)
nr_of_entries = 0;
current_id = 1;

for index, row in data.iterrows():
    if(int(row['id']) != current_id): #after the last point of the route
        routes[current_id-1][0] = current_id;
        routes[current_id-1][1] = nr_of_entries; #how many points are in this route?
        routes[current_id-1][2] = sums[0] / nr_of_entries;
        routes[current_id-1][3] = sums[1] / nr_of_entries;
        routes[current_id-1][4] = sums[2] / nr_of_entries;
        routes[current_id-1][5] = sums[3] / nr_of_entries;
        routes[current_id-1][6] = sums[4] / nr_of_entries;
        routes[current_id-1][7] = sums[5] / nr_of_entries;
        routes[current_id-1][8] = sums[6] / nr_of_entries;
        routes[current_id-1][9] = sums[7] / nr_of_entries;

        current_id = int(row['id']);
        sums = numpy.zeros(8)
        nr_of_entries = 0;

    sums[0] += row[3];
    sums[1] += row[4];
    sums[2] += row[5];
    sums[3] += row[6];
    sums[4] += row[7];
    sums[5] += row[8];
    sums[6] += row[9];
    sums[7] += row[10];
    nr_of_entries = nr_of_entries + 1;

routes

Моя проблема
1.) Как я это сделал, мне нужно скопировать и вставить один и тот же код для любого другого подхода к обработке, поскольку, как было сказано, мне нужно сделать несколько разных способов. Среднее - это всего лишь пример.

2.) Чтение данных неуклюже и не удается при отсутствии идентификаторов.

3.) Я разработчик C #, поэтому мой подход состоит в том, чтобы создать класс «Маршрут», который имеет все точки, а затем предоставить методы для «вычисления среднего значения для опоры 1». Или что-то. Таким образом, я мог также настроить данные, если это необходимо. (например, экстремальные значения). Но я понятия не имею, как это будет сделано в Phyton, и является ли это разумным подходом для этого языка.

4.) Есть ли более элегантный способ перебрать исходный csv и получить как Route ID 1, затем Route ID 2 и так далее? Может быть, что-то вроде запросов LINQ на C #?

Спасибо за любую помощь.

0
Hans Vader 26 Ноя 2019 в 10:34
1
Не могли бы вы, например, добавить файл данных?
 – 
Finn
26 Ноя 2019 в 10:44
Конечно. Я не могу доставить оригинал из-за проблем с конфиденциальностью. Но я создам фиктивный файл в том же стиле. Секундочку
 – 
Hans Vader
26 Ноя 2019 в 10:51

1 ответ

Он является решением и некоторыми идеями, которые вы можете использовать. В примере представлено несколько вариантов для одной и той же проблемы, поэтому вам нужно выбрать, какая из них лучше всего подходит для этой цели. Также это Python 3.7, вы не указали версию, поэтому я надеюсь, что это сработает.

class Route(object):
    """description of class"""
    def __init__(self, id, rawdata): # on startup
        self.id = id
        self.rawdata = rawdata
        self.avg_Prop1 = self.calculate_average('Prop1')
        self.sum_Prop4 = None 

    def calculate_average(self, Prop_Name): #selfreference for first argument in class method
        return self.rawdata[Prop_Name].mean()

    def give_Prop_data(self, Prop_Name): #return the Propdata as list
        return self.rawdata[Prop_Name].tolist()

    def any_function(self, my_function, Prop_Name): #not sure what dataframes support so turning it into a list first
        return my_function(self.rawdata[Prop_Name].tolist())

#end of class definiton


data = pd.read_csv('testdata.csv', sep=';')
# [id, len, prop1, prop2, ...]


route_list = [] #List of all the objects created from the route class
for i in data.id.unique():
    print('Current id:', i,' with ',len(data[data['id']==i]),'entries')
    route_list.append(Route(i,data[data['id']==i]))


#created the Prop1 average in initialization of route so just accessing attribute
print(route_list[1].avg_Prop1)

for current_route in route_list:
    print('Route ',current_route.id , ' Properties :')
    for i in current_route.rawdata.columns[1:]: #for all except the first (id)
        print(i, ' has average ', current_route.calculate_average(i)) #i is the string of the column not just an id

#or pass any function that you want
route_list[1].sum_Prop4 = (route_list[1].any_function(sum,'Prop4'))
print(route_list[1].sum_Prop4)
#which is equivalent to
print(sum(route_list[1].rawdata['Prop4']))

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

Для 2. и 4.) Цикл только по существующим идентификаторам (data.id.unique()) решает проблему. Я понятия не имею, что такое LINQ Queries, но я предполагаю, что они похожи. В общем, в Python есть отличный способ зацикливания объектов (например, for current_route in route_list), на который стоит обратить внимание, если вы хотите использовать его немного больше.

Для 1. и 3.) Снова зацикливание решает проблему. Я создал класс в примере, в основном, чтобы показать синтаксис для классов. Преимущества и недостатки использования классов должны быть такими же в Python, как и в C #.

Как сейчас, класс, вероятно, не велик, но это зависит от того, как вы хотите его использовать. Если класс должен быть просто практичным способом хранения и доступа к данным, у него не должно быть методов, потому что вам не нужен отдельный метод average для каждого маршрута. Затем вы можете просто получить доступ к его данным и использовать их в функции, как в sum(route_list[1].rawdata['Prop4']). Однако, если, в зависимости от данных (например, количества строк), необходимы различные вычисления, может оказаться полезным использовать метод calculate_average и провести дифференциацию там.

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

Я надеюсь, что это поможет!

1
Finn 28 Ноя 2019 в 18:43