簡體   English   中英

來自 R/Python 中 dataframe 的矩陣

[英]Matrix from dataframe in R/Python

我有一個 dataframe 像這樣:如果具有該 ID 的人有該水果,則值為 1,否則為 0。 ID 列是主鍵。

ID 蘋果 橙子 葡萄
E1 1 0 1 1
E2 0 0 1 0
E3 0 1 1 0
E4 1 1 0 0
E5 1 0 0 1

我想要一個 output 作為這樣的矩陣。 這是同時擁有 i 和 j 水果的人數。 其中 i 和 j 都相同,例如:cell apple x apple,我們正在查看只有蘋果而沒有其他水果的人數。 沒有人只有蘋果,所以該單元格的值為 0。類似地,我們只有一個人同時擁有蘋果和橙子,因此 (橙 x 蘋果) 和 (蘋果 x 橙) 單元格中的計數均為 1 . 我們在上面的 dataframe 中有 2 個人同時擁有葡萄和蘋果,因此該單元格中的值為 2。

蘋果 橙子 葡萄
蘋果 0 1 1 2
橙子 1 0 1 0
1 1 1 1
葡萄 2 0 1 0

我是 R 和 Python 的新手,不知道如何實現這一點。 R 或 Python 的任何幫助將不勝感激。 如果有任何不清楚或缺少任何內容,請隨時提出問題。 謝謝!

這是 Python3 和itertools.permutations的示例:

import itertools

import pandas as pd

# Create original dataframe
columns = ['ID', 'Apple', 'Orange', 'Pear', 'Grapes']
rows = [
    ['E1', 1, 0, 1, 1],
    ['E2', 0, 0, 1, 0],
    ['E3', 0, 1, 1, 0],
    ['E4', 1, 1, 0, 0],
    ['E5', 1, 0, 0, 1],
]
df = pd.DataFrame(rows, columns=columns)

# Count values of resulting matrix
def get_ones_indexes(els):
    for i, el in enumerate(els):
        if el == 1:
            yield i

res_n = len(df.columns) - 1
res = [[0] * res_n for _ in range(res_n)]

for _, row in df.drop('ID', axis=1).iterrows():
    indexes = list(get_ones_indexes(row.to_list()))

    if len(indexes) == 1:
        idx = indexes[0]
        res[idx][idx] += 1
    else:
        for i, j in itertools.permutations(indexes, 2):
            res[i][j] += 1

# Convert resultinng matrix to dataframe
_, *fruit_cols = df.columns
res_df = pd.DataFrame(res, index=fruit_cols, columns=fruit_cols)

print(res_df)
#         Apple  Orange  Pear  Grapes
# Apple       0       1     1       2
# Orange      1       0     1       0
# Pear        1       1     1       1
# Grapes      2       0     1       0

這是一個tidyverse R 選項:

library(tidyverse)
data %>%
    pivot_longer(-ID) %>%
    filter(value > 0) %>%
    select(-value) %>%
    group_by(ID) %>%
    nest() %>%
    mutate(data = map(data, ~ expand.grid(.x$name, .x$name))) %>%
    unnest(data) %>%
    group_by(Var1, Var2) %>%
    summarise(n = n(), .groups = "drop") %>%
    filter(Var1 != Var2) %>%
    pivot_wider(names_from = Var1, values_from = n, values_fill = 0)
## A tibble: 4 x 5
#  Var2   Apple  Pear Grapes Orange
#  <fct>  <int> <int>  <int>  <int>
#1 Pear       1     0      1      1
#2 Grapes     2     1      0      0
#3 Orange     1     1      0      0
#4 Apple      0     1      2      1

這個想法是使用expand.grid來生成所有成對的組合。 rest 正在計算出現次數並進行整形。 根據需要重新排序行和列。

PS。 我應該提到,結果與預期的 output 略有不同。 例如,我不明白為什么 (Pear, Pear) = 1。我認為這是錯誤的。 由於您要求同時出現,因此所有對角線元素都應為零。


樣本數據

data <- read.table(text = "ID   Apple   Orange  Pear    Grapes
E1  1   0   1   1
E2  0   0   1   0
E3  0   1   1   0
E4  1   1   0   0
E5  1   0   0   1", header = T)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM