1

動作する次のコードを作成しましたが、改善したいと思います。ファイルを再読み込みしたくありませんが、sales_input.seek(0) を削除すると、sales の各行がスローされません。どうすればこれを改善できますか?

def computeCritics(mode, cleaned_sales_input = "data/cleaned_sales.csv"):
    if mode == 1:
        print "creating customer.critics.recommendations"
        critics_output = open("data/customer/customer.critics.recommendations", 
                              "wb")
        ID = getCustomerSet(cleaned_sales_input)
        sales_dict = pickle.load(open("data/customer/books.dict.recommendations", 
                                      "r"))
    else: 
        print "creating books.critics.recommendations"
        critics_output = open("data/books/books.critics.recommendations", 
                              "wb")
        ID = getBookSet(cleaned_sales_input)
        sales_dict = pickle.load(open("data/books/users.dict.recommendations", 
                                      "r"))
    critics = {}
    # make critics dict and pickle it 
    for i in ID:
        with open(cleaned_sales_input, 'rb') as sales_input:
            sales = csv.reader(sales_input)  # read new 
            for j in sales:
                if mode == 1:
                    if int(i) == int(j[2]):
                        sales_dict[int(j[6])] = 1
                else: 
                    if int(i) == int(j[6]):
                        sales_dict[int(j[2])] = 1
            critics[int(i)] = sales_dict
    pickle.dump(critics, critics_output)
    print "done"

cleaned_sales_inputは次のようになります

6042772,2723,3546414,9782072488887,1,9.99,314968
6042769,2723,3546414,9782072488887,1,9.99,314968
...

ここで、番号 6 は書籍 ID、番号 0 は顧客 ID です。

次のようなdictを取得したい

critics = {
    CustomerID1: {
        BookID1: 1,
        BookID2: 0,
        ........
        BookIDX: 0
    },
    CustomerID2: {
        BookID1: 0,
        BookID2: 1,
        ...
    }
}

また

critics = {
    BookID1: {
        CustomerID1: 1,
        CustomerID2: 0,
        ........
        CustomerIDX: 0
    },
    BookID1: {
        CustomerID1: 0,
        CustomerID2: 1,
        ...
        CustomerIDX: 0
    }
}

これが多くの情報ではないことを願っています

4

2 に答える 2

2

以下にいくつかの提案を示します。

まず、このコード パターンを見てみましょう。

for i in ID:
    for j in sales:
        if int(i) == int(j[2])

iとのみ比較されていることに注意してj[2]ください。それがループでの唯一の目的です。int(i) == int(j[2])は、各 に対して最大 1 回だけ True にできますi

したがって、ループを次のfor i in IDように書き換えることで、ループを完全に削除できます。

for j in sales:
    key = j[2]
    if key in ID:

getCustomerSet関数名およびに基づいて、がセットであるgetBookSetかのように聞こえます ID(リストまたはタプルとは対照的に)。セット内のメンバーシップのテストは O(1) (リストまたはタプルの O(n) とは対照的) であるため、ID をセットにする必要があります。


次に、次の行を検討してください。

critics[int(i)] = sales_dict

ここに潜在的な落とし穴があります。この行はfor each in に割り当てsales_dictて います。各キーはまったく同じ にマッピングされています。と をループすると、次のように変更されます。たとえば、次のようになります。critics[int(i)]iIDint(i)dictsalesIDsales_dict

sales_dict[int(j[6])] = 1

ただし、これにより、すべてのキーが同じ dict を指しているため、すべての値がcritics同時に変更されます。それがあなたの望んでいることだとは思えません。criticssales_dict

この落とし穴を避けるために、sales_dict のコピーを作成する必要があります。

critics = {i:sales_dict.copy() for i in ID}

def computeCritics(mode, cleaned_sales_input="data/cleaned_sales.csv"):
    if mode == 1:
        filename = 'customer.critics.recommendations'
        path = os.path.join("data/customer", filename)
        ID = getCustomerSet(cleaned_sales_input)
        sales_dict = pickle.load(
            open("data/customer/books.dict.recommendations", "r"))
        key_idx, other_idx = 2, 6
    else:
        filename = 'books.critics.recommendations'
        path = os.path.join("data/books", filename)        
        ID = getBookSet(cleaned_sales_input)
        sales_dict = pickle.load(
            open("data/books/users.dict.recommendations", "r"))
        key_idx, other_idx = 6, 2

    print "creating {}".format(filename)
    ID = {int(item) for item in ID}
    critics = {i:sales_dict.copy() for i in ID}
    with open(path, "wb") as critics_output:
        # make critics dict and pickle it
        with open(cleaned_sales_input, 'rb') as sales_input:
            sales = csv.reader(sales_input)  # read new
            for j in sales:
                key = int(j[key_idx])
                if key in ID:
                    other_key = int(j[other_idx])
                    critics[key][other_key] = 1                    
                critics[key] = sales_dict
        pickle.dump(dict(critics), critics_output)
        print "done"
于 2013-09-05T12:14:05.447 に答える
0

@unutbuの答えの方が優れていますが、この構造にこだわっている場合は、ファイル全体をメモリに入れることができます:

sales = []
with open(cleaned_sales_input, 'rb') as sales_input:
     sales_reader = csv.reader(sales_input)       
     [sales.append(line) for line in sales_reader]

     for i in ID:
        for j in sales:
            #do stuff
于 2013-09-05T12:18:56.743 に答える