9

Tôi có khung dữ liệu gấu trúc với nhiều cột. Tôi muốn tạo một cột mới weighted_sum từ các giá trị trong hàng và một dataframe vector cột weightLàm thế nào để tính toán tổng trọng số của tất cả các phần tử trong một hàng trong gấu trúc?

weighted_sum nên có giá trị sau:

row[weighted_sum] = row[col0]*weight[0] + row[col1]*weight[1] + row[col2]*weight[2] + ...

tôi thấy chức năng sum(axis=1), nhưng nó doesn' để tôi nhân với weight.

Chỉnh sửa: Tôi đã thay đổi mọi thứ một chút.

weight trông như thế này:

 0 
col1 0.5 
col2 0.3 
col3 0.2 

df trông như thế này:

col1 col2 col3 
1.0 2.2 3.5 
6.1 0.4 1.2 

df*weight trả về một dataframe đầy Nan giá trị.

+0

Bạn có thể hiển thị một số 'DataFrame' và' trọng số' của mình không? Không rõ tại sao bạn đang gặp sự cố khi thực hiện việc này. Nếu bạn chỉ muốn sản phẩm dấu chấm của các giá trị hàng với 'weights' thì hãy sử dụng phương thức' ndarray.dot': 'row.values.dot (weights.values)'. –

Trả lời

9

Vấn đề là bạn nhân một khung có kích thước khác với chỉ mục hàng khác. Dưới đây là giải pháp:

In [121]: df = DataFrame([[1,2.2,3.5],[6.1,0.4,1.2]], columns=list('abc')) 

In [122]: weight = DataFrame(Series([0.5, 0.3, 0.2], index=list('abc'), name=0)) 

In [123]: df 
Out[123]: 
      a   b   c 
0  1.00  2.20  3.50 
1  6.10  0.40  1.20 

In [124]: weight 
Out[124]: 
      0 
a  0.50 
b  0.30 
c  0.20 

In [125]: df * weight 
Out[125]: 
      0   a   b   c 
0  nan  nan  nan  nan 
1  nan  nan  nan  nan 
a  nan  nan  nan  nan 
b  nan  nan  nan  nan 
c  nan  nan  nan  nan 

Bạn có thể truy cập vào các cột:

In [126]: df * weight[0] 
Out[126]: 
      a   b   c 
0  0.50  0.66  0.70 
1  3.05  0.12  0.24 

In [128]: (df * weight[0]).sum(1) 
Out[128]: 
0   1.86 
1   3.41 
dtype: float64 

Hoặc sử dụng dot để lấy lại khác DataFrame

In [127]: df.dot(weight) 
Out[127]: 
      0 
0  1.86 
1  3.41 

Để mang lại cho nó tất cả cùng nhau:

In [130]: df['weighted_sum'] = df.dot(weight) 

In [131]: df 
Out[131]: 
      a   b   c weighted_sum 
0  1.00  2.20  3.50   1.86 
1  6.10  0.40  1.20   3.41 

Dưới đây là các phương pháp timeit s của từng phương pháp, sử dụng DataFrame lớn hơn.

In [145]: df = DataFrame(randn(10000000, 3), columns=list('abc')) 
weight 
In [146]: weight = DataFrame(Series([0.5, 0.3, 0.2], index=list('abc'), name=0)) 

In [147]: timeit df.dot(weight) 
10 loops, best of 3: 57.5 ms per loop 

In [148]: timeit (df * weight[0]).sum(1) 
10 loops, best of 3: 125 ms per loop 

Đối với một rộng DataFrame:

In [162]: df = DataFrame(randn(10000, 1000)) 

In [163]: weight = DataFrame(randn(1000, 1)) 

In [164]: timeit df.dot(weight) 
100 loops, best of 3: 5.14 ms per loop 

In [165]: timeit (df * weight[0]).sum(1) 
10 loops, best of 3: 41.8 ms per loop 

Vì vậy, dot là nhanh hơn và dễ đọc hơn.

LƯU Ý: Nếu bất kỳ dữ liệu của bạn chứa NaN s thì bạn không nên sử dụng dot bạn nên sử dụng phương pháp nhân-và-sum. dot không thể xử lý NaN s vì nó chỉ là một bao bọc mỏng xung quanh numpy.dot() (không xử lý NaN s).

+0

Tôi đã khá ngạc nhiên bởi sự tăng tốc này, nhưng thực sự tôi không chắc rằng dấu chấm tạo ra cùng một kết quả. Và 'df.mul (trọng lượng) .sum (1)' có vẻ giống nhau (nếu chậm hơn một chút). –

+0

'df.dot (weight)' sẽ tạo ra một 'DataFrame' nếu' df' và 'weight' là cả hai' DataFrames', một 'Series' nếu là một' Series' và một vô hướng nếu cả hai là 'Series'. Bằng số, chúng tương đương nhau. –

+0

Tốc độ có thể là do tạm thời được tạo bởi thao tác '*'. 'dot' không cần tạm thời như vậy :) –

6

Giả sử trọng lượng là một loạt các khối lượng cho mỗi cột, bạn có thể chỉ nhân và làm tổng:

In [11]: df = pd.DataFrame([[1, 2, 3], [4, 5, 6]], columns=['a', 'b', 'c']) 

In [12]: weights = pd.Series([7, 8, 9], index=['a', 'b', 'c']) 

In [13]: (df * weights) 
Out[13]: 
    a b c 
0 7 16 27 
1 28 40 54 

In [14]: (df * weights).sum(1) 
Out[14]: 
0  50 
1 122 
dtype: int64 

Lợi ích của phương pháp này là nó sẽ chăm sóc của các cột mà bạn không muốn phải cân nhắc :

In [21]: weights = pd.Series([7, 8], index=['a', 'b']) 

In [22]: (df * weights) 
Out[22]: 
    a b c 
0 7 16 NaN 
1 28 40 NaN 

In [23]: (df * weights).sum(1) 
Out[23]: 
0 23 
1 68 
dtype: float64 
Các vấn đề liên quan