CSV sütunlarını hiyerarşik ilişkilere dönüştürmenin bir yolu var mı?


27

Taksonomi düzeylerinin sütunlar olduğu 7 milyon biyoçeşitlilik kaydına sahip bir csv'm var. Örneğin:

RecordID,kingdom,phylum,class,order,family,genus,species
1,Animalia,Chordata,Mammalia,Primates,Hominidae,Homo,Homo sapiens
2,Animalia,Chordata,Mammalia,Carnivora,Canidae,Canis,Canis
3,Plantae,nan,Magnoliopsida,Brassicales,Brassicaceae,Arabidopsis,Arabidopsis thaliana
4,Plantae,nan,Magnoliopsida,Fabales,Fabaceae,Phaseoulus,Phaseolus vulgaris

D3 bir görselleştirme oluşturmak istiyorum, ancak veri biçimi sütun her farklı değeri belirli bir değer için önceki sütunun bir alt olduğu bir ağ olmalıdır. Ben csv böyle bir şeye gitmek gerekir:

{
  name: 'Animalia',
  children: [{
    name: 'Chordata',
    children: [{
      name: 'Mammalia',
      children: [{
        name: 'Primates',
        children: 'Hominidae'
      }, {
        name: 'Carnivora',
        children: 'Canidae'
      }]
    }]
  }]
}

Döngüler için bin kullanmadan bunu nasıl yapacağım hakkında bir fikir bulamadım. Python veya javascript üzerinde bu ağın nasıl oluşturulacağı konusunda bir önerisi olan var mı?


Sorunuzla ilgili değil, ama cevabımı yazdıktan hemen sonra nanMagnoliopsida içeren Phylum için bir fark ettim . Bu nedir nan? Phylum Anthophyta veya alternatif olarak Manolya'dır (eski Phylum Angiospermae'dir).
Gerardo Furtado

Yanıtlar:


16

Tam olarak istediğiniz iç içe geçmiş nesneyi oluşturmak için saf JavaScript ve adlandırılmış bir D3 yöntemi karışımı kullanacağız d3.stratify. Ancak, 7 milyon satırın (lütfen aşağıdaki yazı komut dosyasına bakın) hesaplanması gereken çok şey olduğunu unutmayın.

Önerilen bu çözüm için, Krallıkları farklı veri dizilerinde (örneğin, kullanarak Array.prototype.filter) ayırmanız gerekeceğinden bahsetmek çok önemlidir . Bu kısıtlama, bir kök düğüme ihtiyacımız olduğu için gerçekleşir ve Linna taksonomisinde Krallıklar arasında bir ilişki yoktur ( tüm ökaryotların kökü olacak bir üst sıra olarak "Etki Alanı" oluşturmazsanız , ancak aynı Archaea ve Bakteriler için problem).

Diyelim ki sadece bir Krallık ile bu CSV'ye (birkaç satır daha ekledim) sahipsin:

RecordID,kingdom,phylum,class,order,family,genus,species
1,Animalia,Chordata,Mammalia,Primates,Hominidae,Homo,Homo sapiens
2,Animalia,Chordata,Mammalia,Carnivora,Canidae,Canis,Canis latrans
3,Animalia,Chordata,Mammalia,Cetacea,Delphinidae,Tursiops,Tursiops truncatus
1,Animalia,Chordata,Mammalia,Primates,Hominidae,Pan,Pan paniscus

Bu CSV'ye dayanarak, burada tableOfRelationshipsadından da anlaşılacağı gibi, dereceler arasında ilişkileri olan bir dizi oluşturacağız :

const data = d3.csvParse(csv);

const taxonomicRanks = data.columns.filter(d => d !== "RecordID");

const tableOfRelationships = [];

data.forEach(row => {
  taxonomicRanks.forEach((d, i) => {
    if (!tableOfRelationships.find(e => e.name === row[d])) tableOfRelationships.push({
      name: row[d],
      parent: row[taxonomicRanks[i - 1]] || null
    })
  })
});

Yukarıdaki veriler için bu tableOfRelationships:

+---------+----------------------+---------------+
| (Index) |         name         |    parent     |
+---------+----------------------+---------------+
|       0 | "Animalia"           | null          |
|       1 | "Chordata"           | "Animalia"    |
|       2 | "Mammalia"           | "Chordata"    |
|       3 | "Primates"           | "Mammalia"    |
|       4 | "Hominidae"          | "Primates"    |
|       5 | "Homo"               | "Hominidae"   |
|       6 | "Homo sapiens"       | "Homo"        |
|       7 | "Carnivora"          | "Mammalia"    |
|       8 | "Canidae"            | "Carnivora"   |
|       9 | "Canis"              | "Canidae"     |
|      10 | "Canis latrans"      | "Canis"       |
|      11 | "Cetacea"            | "Mammalia"    |
|      12 | "Delphinidae"        | "Cetacea"     |
|      13 | "Tursiops"           | "Delphinidae" |
|      14 | "Tursiops truncatus" | "Tursiops"    |
|      15 | "Pan"                | "Hominidae"   |
|      16 | "Pan paniscus"       | "Pan"         |
+---------+----------------------+---------------+

Şunun nullebeveyni olarak bakın Animalia: bu yüzden veri setinizi Krallıklar ile ayırmanız gerektiğini söyledim null, tüm tabloda sadece bir değer olabilir .

Son olarak, bu tabloya dayanarak, hiyerarşiyi aşağıdakileri kullanarak oluştururuz d3.stratify():

const stratify = d3.stratify()
    .id(function(d) { return d.name; })
    .parentId(function(d) { return d.parent; });

const hierarchicalData = stratify(tableOfRelationships);

Ve işte demo. Tarayıcınızın konsolunu açın (snippet'inki bu görev için çok iyi değil) ve childrennesnenin birkaç seviyesini ( ) inceleyin :


Not : Ne tür bir veri ortamı oluşturacağınızı bilmiyorum, ama taksonomik aşamalardan gerçekten kaçınmalısınız. Bütün Linnaean taksonomisi modası geçmiş, artık rütbe kullanmıyoruz: filogenetik sistematik 60'lı yılların ortalarında geliştirildiğinden, taksonomik bir sıra olmaksızın sadece taksonları kullanıyoruz (burada evrim biyolojisi öğretmeni). Ayrıca, 7 milyondan fazla türü tanımladığımız için bu 7 milyon satırı merak ediyorum!


3
. @ gerardo Cevabınız için teşekkürler, 7M satırlarının bir örneğinde çalışıp çalışmadığını göreceğim. Veritabanı birçok tür için tekrarlanan satırlar içerir. bu nedenle fikir, belirli bir taksonomik sıralama için kaç kayıt olduğunu göstermektir. Fikir, Mike Bostock'un Zumlanabilir Saçağı Ağacı'na benzer bir şey yaratmaktır .
Andres Camilo Zuñiga Gonzalez

9

Python ve python-benedictkitaplığı kullanarak tam olarak ihtiyacınız olanı yapmak kolaydır ( Github'da açık kaynak :

Kurulum pip install python-benedict

from benedict import benedict as bdict

# data source can be a filepath or an url
data_source = """
RecordID,kingdom,phylum,class,order,family,genus,species
1,Animalia,Chordata,Mammalia,Primates,Hominidae,Homo,Homo sapiens
2,Animalia,Chordata,Mammalia,Carnivora,Canidae,Canis,Canis
3,Plantae,nan,Magnoliopsida,Brassicales,Brassicaceae,Arabidopsis,Arabidopsis thaliana
4,Plantae,nan,Magnoliopsida,Fabales,Fabaceae,Phaseoulus,Phaseolus vulgaris
"""
data_input = bdict.from_csv(data_source)
data_output = bdict()

ancestors_hierarchy = ['kingdom', 'phylum', 'class', 'order', 'family', 'genus', 'species']
for value in data_input['values']:
    data_output['.'.join([value[ancestor] for ancestor in ancestors_hierarchy])] = bdict()

print(data_output.dump())
# if this output is ok for your needs, you don't need the following code

keypaths = sorted(data_output.keypaths(), key=lambda item: len(item.split('.')), reverse=True)

data_output['children'] = []
def transform_data(d, key, value):
    if isinstance(value, dict):
        value.update({ 'name':key, 'children':[] })
data_output.traverse(transform_data)

for keypath in keypaths:
    target_keypath = '.'.join(keypath.split('.')[:-1] + ['children'])
    data_output[target_keypath].append(data_output.pop(keypath))

print(data_output.dump())

İlk baskı çıktısı:

{
    "Animalia": {
        "Chordata": {
            "Mammalia": {
                "Carnivora": {
                    "Canidae": {
                        "Canis": {
                            "Canis": {}
                        }
                    }
                },
                "Primates": {
                    "Hominidae": {
                        "Homo": {
                            "Homo sapiens": {}
                        }
                    }
                }
            }
        }
    },
    "Plantae": {
        "nan": {
            "Magnoliopsida": {
                "Brassicales": {
                    "Brassicaceae": {
                        "Arabidopsis": {
                            "Arabidopsis thaliana": {}
                        }
                    }
                },
                "Fabales": {
                    "Fabaceae": {
                        "Phaseoulus": {
                            "Phaseolus vulgaris": {}
                        }
                    }
                }
            }
        }
    }
}

İkinci yazdırılan çıktı:

{
    "children": [
        {
            "name": "Animalia",
            "children": [
                {
                    "name": "Chordata",
                    "children": [
                        {
                            "name": "Mammalia",
                            "children": [
                                {
                                    "name": "Carnivora",
                                    "children": [
                                        {
                                            "name": "Canidae",
                                            "children": [
                                                {
                                                    "name": "Canis",
                                                    "children": [
                                                        {
                                                            "name": "Canis",
                                                            "children": []
                                                        }
                                                    ]
                                                }
                                            ]
                                        }
                                    ]
                                },
                                {
                                    "name": "Primates",
                                    "children": [
                                        {
                                            "name": "Hominidae",
                                            "children": [
                                                {
                                                    "name": "Homo",
                                                    "children": [
                                                        {
                                                            "name": "Homo sapiens",
                                                            "children": []
                                                        }
                                                    ]
                                                }
                                            ]
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        },
        {
            "name": "Plantae",
            "children": [
                {
                    "name": "nan",
                    "children": [
                        {
                            "name": "Magnoliopsida",
                            "children": [
                                {
                                    "name": "Brassicales",
                                    "children": [
                                        {
                                            "name": "Brassicaceae",
                                            "children": [
                                                {
                                                    "name": "Arabidopsis",
                                                    "children": [
                                                        {
                                                            "name": "Arabidopsis thaliana",
                                                            "children": []
                                                        }
                                                    ]
                                                }
                                            ]
                                        }
                                    ]
                                },
                                {
                                    "name": "Fabales",
                                    "children": [
                                        {
                                            "name": "Fabaceae",
                                            "children": [
                                                {
                                                    "name": "Phaseoulus",
                                                    "children": [
                                                        {
                                                            "name": "Phaseolus vulgaris",
                                                            "children": []
                                                        }
                                                    ]
                                                }
                                            ]
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    ]
}

5

var log = console.log;
var data = `
1,Animalia,Chordata,Mammalia,Primates,Hominidae,Homo,Homo sapiens
2,Animalia,Chordata,Mammalia,Carnivora,Canidae,Canis,Canis
3,Plantae,nan,Magnoliopsida,Brassicales,Brassicaceae,Arabidopsis,Arabidopsis thaliana
4,Plantae,nan,Magnoliopsida,Fabales,Fabaceae,Phaseoulus,Phaseolus vulgaris`;
//make array of rows with array of values
data = data.split("\n").map(v=>v.split(","));
//init tree
var tree = {};
data.forEach(row=>{
    //set current = root of tree for every row
    var cur = tree; 
    var id = false;
    row.forEach((value,i)=>{
        if (i == 0) {
            //set id and skip value
            id = value;
            return;
        }
        //If branch not exists create. 
        //If last value - write id
        if (!cur[value]) cur[value] = (i == row.length - 1) ? id : {};
        //Move link down on hierarhy
        cur = cur[value];
    });
}); 
log("Tree:");
log(JSON.stringify(tree, null, "  "));

//Now you have hierarhy in tree and can do anything with it.
var toStruct = function(obj) {
    let ret = [];
    for (let key in obj) {
        let child = obj[key];
        let rec = {};
        rec.name = key;
        if (typeof child == "object") rec.children = toStruct(child);
        ret.push(rec);
    }
    return ret;
}
var struct = toStruct(tree);
console.log("Struct:");
console.log(struct);


5

Bu basit görünüyor, bu yüzden belki probleminizi anlamıyorum.

İstediğiniz veri yapısı, iç içe geçmiş sözlükler, anahtar / değer çiftleridir. Üst düzey krallık sözlüğünüzde, değerleri phylum sözlükleri olan krallıklarınızın her biri için bir anahtar vardır. Bir phylum sözlüğünde (bir krallık için) her phylum adı için bir anahtar vardır ve her anahtarın bir sınıf sözlüğü olan bir değeri vardır.

Kodlamayı kolaylaştırmak için, cins sözlüklerinizin her tür için bir anahtarı olacaktır, ancak türün değerleri boş sözlükler olacaktır.

İstediğin bu olmalı; garip kütüphanelere gerek yok.

import csv

def read_data(filename):
    tree = {}
    with open(filename) as f:
        f.readline()  # skip the column headers line of the file
        for animal_cols in csv.reader(f):
            spot = tree
            for name in animal_cols[1:]:  # each name, skipping the record number
                if name in spot:  # The parent is already in the tree
                    spot = spot[name]  
                else:
                    spot[name] = {}  # creates a new entry in the tree
                    spot = spot[name]
    return tree

Test etmek için verilerinizi ve pprintstandart kütüphaneden kullandım.

from pprint import pprint
pprint(read_data('data.txt'))

alma

{'Animalia': {'Chordata': {'Mammalia': {'Carnivora': {'Canidae': {'Canis': {'Canis': {}}}},
                                        'Primates': {'Hominidae': {'Homo': {'Homo sapiens': {}}}}}}},
 'Plantae': {'nan': {'Magnoliopsida': {'Brassicales': {'Brassicaceae': {'Arabidopsis': {'Arabidopsis thaliana': {}}}},
                                       'Fabales': {'Fabaceae': {'Phaseoulus': {'Phaseolus vulgaris': {}}}}}}}}

Sorunuzu tekrar okurken, büyük bir çift tablo isteyebilirsiniz ('daha genel gruptan bağlantı', 'daha spesifik gruba bağlantı'). Yani, 'Animalia', 'Animalia: Chordata' ve 'Animalia: Chordata' 'bağlantıları' Animalia: Chordata: Mammalia 'vb. İle bağlantılıdır. ebeveyn, çocuk) çiftleri istediğiniz şeydir, ağacı bu şekilde yürütün:

def walk_children(tree, parent=''):
    for child in tree.keys():
        full_name = parent + ':' + child
        yield (parent, full_name)
        yield from walk_children(tree[child], full_name)

tree = read_data('data.txt')
for (parent, child) in walk_children(tree):
    print(f'parent="{parent}" child="{child}"')

vererek:

parent="" child=":Animalia"
parent=":Animalia" child=":Animalia:Chordata"
parent=":Animalia:Chordata" child=":Animalia:Chordata:Mammalia"
parent=":Animalia:Chordata:Mammalia" child=":Animalia:Chordata:Mammalia:Primates"
parent=":Animalia:Chordata:Mammalia:Primates" child=":Animalia:Chordata:Mammalia:Primates:Hominidae"
parent=":Animalia:Chordata:Mammalia:Primates:Hominidae" child=":Animalia:Chordata:Mammalia:Primates:Hominidae:Homo"
parent=":Animalia:Chordata:Mammalia:Primates:Hominidae:Homo" child=":Animalia:Chordata:Mammalia:Primates:Hominidae:Homo:Homo sapiens"
parent=":Animalia:Chordata:Mammalia" child=":Animalia:Chordata:Mammalia:Carnivora"
parent=":Animalia:Chordata:Mammalia:Carnivora" child=":Animalia:Chordata:Mammalia:Carnivora:Canidae"
parent=":Animalia:Chordata:Mammalia:Carnivora:Canidae" child=":Animalia:Chordata:Mammalia:Carnivora:Canidae:Canis"
parent=":Animalia:Chordata:Mammalia:Carnivora:Canidae:Canis" child=":Animalia:Chordata:Mammalia:Carnivora:Canidae:Canis:Canis"
parent="" child=":Plantae"
parent=":Plantae" child=":Plantae:nan"
parent=":Plantae:nan" child=":Plantae:nan:Magnoliopsida"
parent=":Plantae:nan:Magnoliopsida" child=":Plantae:nan:Magnoliopsida:Brassicales"
parent=":Plantae:nan:Magnoliopsida:Brassicales" child=":Plantae:nan:Magnoliopsida:Brassicales:Brassicaceae"
parent=":Plantae:nan:Magnoliopsida:Brassicales:Brassicaceae" child=":Plantae:nan:Magnoliopsida:Brassicales:Brassicaceae:Arabidopsis"
parent=":Plantae:nan:Magnoliopsida:Brassicales:Brassicaceae:Arabidopsis" child=":Plantae:nan:Magnoliopsida:Brassicales:Brassicaceae:Arabidopsis:Arabidopsis thaliana"
parent=":Plantae:nan:Magnoliopsida" child=":Plantae:nan:Magnoliopsida:Fabales"
parent=":Plantae:nan:Magnoliopsida:Fabales" child=":Plantae:nan:Magnoliopsida:Fabales:Fabaceae"
parent=":Plantae:nan:Magnoliopsida:Fabales:Fabaceae" child=":Plantae:nan:Magnoliopsida:Fabales:Fabaceae:Phaseoulus"
parent=":Plantae:nan:Magnoliopsida:Fabales:Fabaceae:Phaseoulus" child=":Plantae:nan:Magnoliopsida:Fabales:Fabaceae:Phaseoulus:Phaseolus vulgaris"

Bu , soruda istendiği gibi nameve childrenistendiği gibi iç içe bir dikte döndürmez .
Fabio Caccamo

Hayır değil. İstenen "böyle bir şey" idi; Bunu fikir veri yapısını bulmaya çalışıyorum. Dört sıralı bir ağaç olan, ağacı yürüterek özel bir yapı inşa edilebilir.
Charles Merriam

3

Python'da, bir ağacı kodlamanın bir yolu a'nın kullanılmasıdır dict; burada anahtarlar düğümleri temsil eder ve ilişkili değer düğümün üst öğesidir:

{'Homo sapiens': 'Homo',
 'Canis': 'Canidae',
 'Arabidopsis thaliana': 'Arabidopsis',
 'Phaseolus vulgaris': 'Phaseoulus',
 'Homo': 'Hominidae',
 'Arabidopsis': 'Brassicaceae',
 'Phaseoulus': 'Fabaceae',
 'Hominidae': 'Primates',
 'Canidae': 'Carnivora',
 'Brassicaceae': 'Brassicales',
 'Fabaceae': 'Fabales',
 'Primates': 'Mammalia',
 'Carnivora': 'Mammalia',
 'Brassicales': 'Magnoliopsida',
 'Fabales': 'Magnoliopsida',
 'Mammalia': 'Chordata',
 'Magnoliopsida': 'nan',
 'Chordata': 'Animalia',
 'nan': 'Plantae',
 'Animalia': None,
 'Plantae': None}

Bunun bir avantajı, dictsyinelenen anahtarlara sahip olamayacağından düğümlerin benzersiz olmasını sağlamanızdır .

Bunun yerine daha genel bir yönlendirilmiş grafik kodlamak istiyorsanız (yani, düğümlerin birden fazla üst öğesi olabilir), değerler için listeler kullanabilir ve temsil eden alt öğelerin (veya ebeveynlerin, varsayalım) olmasını sağlayabilirsiniz:

{'Homo': ['Homo sapiens', 'ManBearPig'],
'Ursus': ['Ursus arctos', 'ManBearPig'],
'Sus': ['ManBearPig']}

Gerekirse, listeler için Diziler yerine JS'deki Nesneler ile benzer bir şey yapabilirsiniz.

Yukarıdaki ilk dikteyi oluşturmak için kullandığım Python kodu:

import csv

ROWS = []
# Load file: tbl.csv
with open('tbl.csv', 'r') as in_file:
    csvreader = csv.reader(in_file)

    # Ignore leading row numbers
    ROWS = [row[1:] for row in csvreader]
    # Drop header row
    del ROWS[0]

# Build dict
mytree = {row[i]: row[i-1] for row in ROWS for i in range(len(row)-1, 0, -1)}
# Add top-level nodes
mytree = {**mytree, **{row[0]: None for row in ROWS}}

2

Muhtemelen verilerinizi bir hiyerarşiye dönüştürmenin en basit yolu D3'ün yerleşik yuvalama operatörünü kullanmaktır d3.nest():

Yerleştirme, bir dizideki öğelerin hiyerarşik bir ağaç yapısında gruplandırılmasına olanak tanır;

Anahtar işlevleri kayıt yoluyla nest.key()hiyerarşinizin yapısını kolayca belirleyebilirsiniz. Gerardo, cevabında ortaya koyduğu gibi .columns, bu temel fonksiyonları oluşturmayı otomatikleştirmek için CSV'nizi ayrıştırdıktan sonra veri dizisinde gösterilen özelliği kullanabilirsiniz . Kodun tamamı aşağıdaki satırlara kadar kaynar:

const nester = d3.nest();                             // Create a nest operator
const [, ...taxonomicRanks] = data.columns;           // Get rid of the RecordID property
taxonomicRanks.forEach(r => nester.key(d => d[r]));   // Register key functions
const nest = nester.entries(data);                    // Calculate hierarchy

Ancak, ortaya çıkan hiyerarşinin nesneler { key, values }yerine sorunuzda istenen yapıya tam olarak benzemediğini unutmayın { name, children }; bu arada, Gerardo'nun cevabı için de aynı şekilde geçerli. Bununla birlikte, her iki yanıt için de acı vermez, çünkü sonuçlar d3.hierarchy()bir çocuk erişimci işlevi belirtilerek tıkanabilir :

d3.hierarchy(nest, d => d.values)   // Second argument is the children accessor

Aşağıdaki demo tüm parçaları bir araya getiriyor:

Ayrıca, yayınlanan yapınıza tam olarak ihtiyaç duymanız durumunda , d3.nest () anahtarına ve ad ve çocuklara değer dönüştürmeye de göz atmak isteyebilirsiniz .


Sürece keyfini çıkarın d3.nest: yakında kullanımdan kaldırılacak.
Gerardo Furtado

@GerardoFurtado Bu benim ilk düşüncemdi. Ancak, bu varsayımı destekleyen herhangi bir referans bulamadım. Çıkarılması hakkında okuduğumu ve hala paketin içinde bulunmasına şaşırdığımı düşündüm. d3 koleksiyonu arşivlendi, ancak üzerinde herhangi bir kullanımdan kaldırma notu yok. Bu konuda güvenilir bir bilginiz var mı?
altocumulus

Bu v6 için, buraya bak . "D3-collection [Kaldırıldı!]" Ya bakın .
Gerardo Furtado

@GerardoFurtado Hayır, aklımdaki referans bu değildi. Yine de soruma cevap maalesef.
altocumulus

1

Eğlenceli bir meydan okuma. Bu javascript kodunu deneyin. Lodash'ın setini basitlik için kullanıyorum.

import { set } from 'lodash'

const csvString = `RecordID,kingdom,phylum,class,order,family,genus,species
    1,Animalia,Chordata,Mammalia,Primates,Hominidae,Homo,Homo sapiens
    2,Animalia,Chordata,Mammalia,Carnivora,Canidae,Canis,Canis
    3,Plantae,nan,Magnoliopsida,Brassicales,Brassicaceae,Arabidopsis,Arabidopsis thaliana
    4,Plantae,nan,Magnoliopsida,Fabales,Fabaceae,Phaseoulus,Phaseolus vulgaris`

// First create a quick lookup map
const result = csvString
  .split('\n') // Split for Rows
  .slice(1) // Remove headers
  .reduce((acc, row) => {
    const path = row
      .split(',') // Split for columns
      .filter(item => item !== 'nan') // OPTIONAL: Filter 'nan'
      .slice(1) // Remove record id
    const species = path.pop() // Pull out species (last entry)
    set(acc, path, species)
    return acc
  }, {})

console.log(JSON.stringify(result, null, 2))

// Then convert to the name-children structure by recursively calling this function
const convert = (obj) => {
  // If we're at the end of our chain, end the chain (children is empty)
  if (typeof obj === 'string') {
    return [{
      name: obj,
      children: [],
    }]
  }
  // Else loop through each entry and add them as children
  return Object.entries(obj)
    .reduce((acc, [key, value]) => acc.concat({
      name: key,
      children: convert(value), // Recursive call
    }), [])
}

const result2 = convert(result)

console.log(JSON.stringify(result2, null, 2))

Bu, istediğiniz sonuca (benzer) nihai sonucu verir.

[
  {
    "name": "Animalia",
    "children": [
      {
        "name": "Chordata",
        "children": [
          {
            "name": "Mammalia",
            "children": [
              {
                "name": "Primates",
                "children": [
                  {
                    "name": "Hominidae",
                    "children": [
                      {
                        "name": "Homo",
                        "children": [
                          {
                            "name": "Homo sapiens",
                            "children": []
                          }
                        ]
                      }
                    ]
                  }
                ]
              },
              {
                "name": "Carnivora",
                "children": [
                  {
                    "name": "Canidae",
                    "children": [
                      {
                        "name": "Canis",
                        "children": [
                          {
                            "name": "Canis",
                            "children": []
                          }
                        ]
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  },
  {
    "name": "Plantae",
    "children": [
      {
        "name": "Magnoliopsida",
        "children": [
          {
            "name": "Brassicales",
            "children": [
              {
                "name": "Brassicaceae",
                "children": [
                  {
                    "name": "Arabidopsis",
                    "children": [
                      {
                        "name": "Arabidopsis thaliana",
                        "children": []
                      }
                    ]
                  }
                ]
              }
            ]
          },
          {
            "name": "Fabales",
            "children": [
              {
                "name": "Fabaceae",
                "children": [
                  {
                    "name": "Phaseoulus",
                    "children": [
                      {
                        "name": "Phaseolus vulgaris",
                        "children": []
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
]

1

Aslında, @Charles Merriam çözümü çok zariftir.

Soruyla aynı sonuca ulaşmak istiyorsanız, aşağıdakileri deneyin.

from io import StringIO
import csv


CSV_CONTENTS = """RecordID,kingdom,phylum,class,order,family,genus,species
1,Animalia,Chordata,Mammalia,Primates,Hominidae,Homo,Homo sapiens
2,Animalia,Chordata,Mammalia,Carnivora,Canidae,Canis,Canis
3,Plantae,nan,Magnoliopsida,Brassicales,Brassicaceae,Arabidopsis,Arabidopsis thaliana
4,Plantae,nan,Magnoliopsida,Fabales,Fabaceae,Phaseoulus,Phaseolus vulgaris
"""


def recursive(dict_data):
    lst = []
    for key, val in dict_data.items():
        children = recursive(val)
        lst.append(dict(name=key, children=children))
    return lst


def main():
    with StringIO() as io_f:
        io_f.write(CSV_CONTENTS)
        io_f.seek(0)
        io_f.readline()  # skip the column headers line of the file
        result_tree = {}
        for row_data in csv.reader(io_f):
            cur_dict = result_tree  # cursor, back to root
            for item in row_data[1:]:  # each item, skip the record number
                if item not in cur_dict:
                    cur_dict[item] = {}  # create new dict
                    cur_dict = cur_dict[item]
                else:
                    cur_dict = cur_dict[item]

    # change answer format
    result_list = []
    for cur_kingdom_name in result_tree:
        result_list.append(dict(name=cur_kingdom_name, children=recursive(result_tree[cur_kingdom_name])))

    # Optional
    import json
    from os import startfile
    output_file = 'result.json'
    with open(output_file, 'w') as f:
        json.dump(result_list, f)
    startfile(output_file)


if __name__ == '__main__':
    main()

resim açıklamasını buraya girin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.